From da5f301d95744b8f1e95f8c0a4d6bd839c8daac5 Mon Sep 17 00:00:00 2001 From: Jesse Wattenbarger Date: Tue, 13 May 2025 05:57:39 -0400 Subject: [PATCH 1/4] Add more tests --- tests/test_ar.bats | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_ar.bats b/tests/test_ar.bats index 89649d7..f771d8e 100644 --- a/tests/test_ar.bats +++ b/tests/test_ar.bats @@ -38,6 +38,11 @@ setup() { done } +@test "ar::pop removes and returns an element from the end of the array" { + ar::pop _starting_array + [[ "${#_starting_array[@]}" == 2 ]] +} + @test "ar::index returns the index for the first occurence of value" { local i i="$(ar::index _starting_array sausage)" @@ -54,6 +59,12 @@ setup() { [[ $status -eq 2 ]] } +@test "ar::extend appends items from the second array to the first array" { + local _second_array=(onions celery garlic) + ar::extend _starting_array _second_array + [[ "${_starting_array[*]}" == "rice beans sausage onions celery garlic" ]] +} + @test "ar::remove removes the first occurence of value from the array" { ar::remove _starting_array rice [[ "${_starting_array[*]}" == "beans sausage" ]] From 8955be671f33f9f7bdf2d0236a4d3440acaeab6d Mon Sep 17 00:00:00 2001 From: Jesse Wattenbarger Date: Sat, 17 May 2025 15:26:18 -0400 Subject: [PATCH 2/4] Add more tests and use assertions from bats assert lib --- ar.bash | 2 +- tests/test_ar.bats | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/ar.bash b/ar.bash index c887aa6..15c7142 100644 --- a/ar.bash +++ b/ar.bash @@ -167,7 +167,7 @@ ar::insert() { ## @fn ar::index() -## @brief Return the index of the first item in array whose needle is equal to the given value. +## @brief Return the index of the first item in array equal to the given value. ## @detail Like Python's list.index(x[, start[, end]]) ## Usage: ar::index arrayname needle [start [end]] ar::index() { diff --git a/tests/test_ar.bats b/tests/test_ar.bats index f771d8e..b7f5ced 100644 --- a/tests/test_ar.bats +++ b/tests/test_ar.bats @@ -72,7 +72,25 @@ setup() { @test "ar::remove fails with non-zero rc if value does not exist" { run ar::remove _starting_array beef - [[ $status -eq 1 ]] + assert_failure +} + +@test "ar::count returns the number of times value appears in array" { + run ar::count _starting_array "rice" + assert_success + assert_output "1" + + local _another_array=(rice beans rice sausage) + run ar::count _another_array "rice" + assert_success + assert_output "2" +} + +@test "ar::reverse reverses an array in-place" { + local _starting_array=(rice beans sausage) + local _expected_reversed_array=(sausage beans rice) + ar::reverse _starting_array + assert_equal "${_starting_array[*]}" "${_expected_reversed_array[*]}" } @test "ar::set turns an array into a set array" { @@ -88,3 +106,23 @@ setup() { ar::in_set expected_arr "${set_arr[i]}" done } + +@test "ar::union returns the union of two sets" { + local -a first_arr=(rice beans sausage) + local -a second_arr=(beef onions) + local -i first_len="${#first_arr[@]}" + local -i second_len="${#second_arr[@]}" + local -i combined_len=$(( first_len + second_len )) + local -i i + local -a union_arr + ar::union first_arr second_arr union_arr + assert_equal "$combined_len" 5 + for ((i=0; i < first_len; i++)); do + ar::in_set union_arr "${first_arr[i]}" + [[ $status -eq 0 ]] + done + for ((i=0; i < second_len; i++)); do + ar::in_set union_arr "${second_arr[i]}" + [[ $status -eq 0 ]] + done +} From 5bdaeaf52dddaca02298827c3bef06f73cdf9391 Mon Sep 17 00:00:00 2001 From: Jesse Wattenbarger Date: Sat, 17 May 2025 16:56:53 -0400 Subject: [PATCH 3/4] Add set difference and test --- ar.bash | 28 +++++++++++++++++++++++++--- tests/test_ar.bats | 19 ++++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/ar.bash b/ar.bash index 15c7142..6ad561d 100644 --- a/ar.bash +++ b/ar.bash @@ -304,8 +304,8 @@ ar::reverse() { ## @param arr_set The array to write the result into ar::set() { local -n arr="$1" - local -A assoc local -n arr_set="$2" + local -A assoc for val in "${arr[@]}"; do assoc[$val]=1 done @@ -351,12 +351,12 @@ ar::union() { } -## @fn ar::punion() +## @fn ar::print_union() ## @brief Print the union of two arrays ## @detail Can be captured as an array with res=($(punion arr1 arr2)) ## @param arr1 The first array ## @param arr2 The second array -ar::punion() { +ar::print_union() { local -n arr1="$1" local -n arr2="$2" local -A union_assoc @@ -399,6 +399,28 @@ ar::intersection() { intersect_arr=("${!intersect_assoc[@]}") } +## @fn ar::difference +## @brief Write the difference between two sets to a third var +## @detail Write elements that are in the first set but not the second. +## @param arr1 The first array name +## @param arr2 The second array name +## @params difference_arr The array name to write the result to +ar::difference() { + local -n arr1="$1" + local -n arr2="$2" + local -n difference_arr="$3" + local -A assoc2 + local -A diff_assoc + for val in "${arr2[@]}"; do + assoc2["$val"]=1 + done + for val in "${arr1[@]}"; do + if [[ ! -v assoc2["$val"] ]]; then + diff_assoc["$val"]=1 + fi + done + difference_arr=("${!diff_assoc[@]}") +} ## @fn array_to_string ## @brief Turn an array into a string with seperator diff --git a/tests/test_ar.bats b/tests/test_ar.bats index b7f5ced..dc4a7ba 100644 --- a/tests/test_ar.bats +++ b/tests/test_ar.bats @@ -107,7 +107,7 @@ setup() { done } -@test "ar::union returns the union of two sets" { +@test "ar::union writes the union of two sets to a third var" { local -a first_arr=(rice beans sausage) local -a second_arr=(beef onions) local -i first_len="${#first_arr[@]}" @@ -126,3 +126,20 @@ setup() { [[ $status -eq 0 ]] done } + +@test "ar::intersection writes the intersection of two sets to a third var" { + local -a first_arr=(rice beans sausage) + local -a second_arr=(rice beef onions) + local -a intersection_arr + ar::intersection first_arr second_arr intersection_arr + assert_equal "${intersection_arr[0]}" "rice" +} + +@test "ar::difference write the set difference of two sets to a third var" { + local -a first_arr=(rice beans sausage) + local -a second_arr=(rice beef onions) + local -a expected_diff=(beans sausage) + local -a diff_arr + ar::difference first_arr second_arr diff_arr + assert_equal "${diff_arr[*]}" "${expected_diff[*]}" +} From ec30555e288c8b3a68f037bf90f1adcff6eb938c Mon Sep 17 00:00:00 2001 From: Jesse Wattenbarger Date: Sat, 17 May 2025 18:13:10 -0400 Subject: [PATCH 4/4] Add symmetric_difference and test --- ar.bash | 34 ++++++++++++++++++++++++++++++++++ tests/test_ar.bats | 17 ++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/ar.bash b/ar.bash index 6ad561d..e49ff5c 100644 --- a/ar.bash +++ b/ar.bash @@ -422,6 +422,40 @@ ar::difference() { difference_arr=("${!diff_assoc[@]}") } +## @fn ar::symmetric_difference +## @brief Write the symmetric difference between two sets to a third var +## @detail Write elements are in either set but not their intersection +## @param arr1 The first array name +## @param arr2 The second array name +## @params difference_arr The array name to write the result to +ar::symmetric_difference() { + local -n arr1="$1" + local -n arr2="$2" + local -n symmetric_diff_arr="$3" + local -A assoc1 assoc2 symmetric_diff_assoc + + for val in "${arr1[@]}"; do + assoc1["$val"]=1 + done + for val in "${arr2[@]}"; do + assoc2["$val"]=1 + done + + # Find elements in arr1 but not arr2 + for val in "${arr1[@]}"; do + if [[ ! -v assoc2["$val"] ]]; then + symmetric_diff_assoc["$val"]=1 + fi + done + # Find elements in arr2 but not arr1 + for val in "${arr2[@]}"; do + if [[ ! -v assoc1["$val"] ]]; then + symmetric_diff_assoc["$val"]=1 + fi + done + symmetric_diff_arr=("${!symmetric_diff_assoc[@]}") +} + ## @fn array_to_string ## @brief Turn an array into a string with seperator ## @param vname_of_array The variable name of the array diff --git a/tests/test_ar.bats b/tests/test_ar.bats index dc4a7ba..69f5073 100644 --- a/tests/test_ar.bats +++ b/tests/test_ar.bats @@ -135,7 +135,7 @@ setup() { assert_equal "${intersection_arr[0]}" "rice" } -@test "ar::difference write the set difference of two sets to a third var" { +@test "ar::difference writes the set difference of two sets to a third var" { local -a first_arr=(rice beans sausage) local -a second_arr=(rice beef onions) local -a expected_diff=(beans sausage) @@ -143,3 +143,18 @@ setup() { ar::difference first_arr second_arr diff_arr assert_equal "${diff_arr[*]}" "${expected_diff[*]}" } + +@test "ar::symmetric_difference writes the symmetric set difference of two sets to a third var" { + local -a first_arr=(rice beans sausage) + local -a second_arr=(rice beef onions) + local -a expected_diff=(beans sausage beef onions) + local -a diff_arr + ar::symmetric_difference first_arr second_arr diff_arr + # Order shouldn't matter + local -i expected_len="${#expected_diff[@]}" + local -i actual_len="${#diff_arr[@]}" + assert_equal "$expected_len" "$actual_len" + for ((i=0; i < expected_len; i++)); do + ar::in_set diff_arr "${expected_diff[i]}" + done +}