fix: support arbitrary whitespace in _forgit_parse_array

Values spanning multiple lines (e.g. a multi-line FORGIT_*_GIT_OPTS
export) were silently dropped: read stopped at the first newline and
IFS only split on spaces, so the resulting array came out empty.

Split on spaces, tabs and newlines and consume the whole value with an
empty delimiter, ignoring leading/trailing whitespace.

Add unit tests covering space-, tab- and newline-separated inputs.
This commit is contained in:
carlfriedrich 2026-06-22 14:34:37 +02:00
parent f2ea9d14ec
commit efa8c39b0d
2 changed files with 80 additions and 2 deletions

View file

@ -100,8 +100,11 @@ _forgit_yank_stash_name() {
_forgit_parse_array() {
${IFS+"false"} && unset old_IFS || old_IFS="$IFS"
# read the value of the second argument
# into an array that has the name of the first argument
IFS=" " read -r -a "$1" <<<"$2"
# into an array that has the name of the first argument.
# Split on any whitespace (spaces, tabs, newlines) and use an empty
# delimiter so the whole value is consumed instead of stopping at the
# first line; leading/trailing whitespace is ignored.
IFS=$' \t\n' read -r -d '' -a "$1" <<<"$2"
${old_IFS+"false"} && unset IFS || IFS="$old_IFS"
}

75
tests/parse-array.test.sh Normal file
View file

@ -0,0 +1,75 @@
#!/usr/bin/env bash
function set_up_before_script() {
source bin/git-forgit
}
# Asserts that _forgit_parse_array splits the given input string into exactly
# the expected elements.
#
# Usage: assert_parsed_array <input> [expected_element...]
# <input> the raw string passed to _forgit_parse_array
# [expected_element] zero or more elements the input should split into,
# typically passed by expanding an array: "${expected[@]}"
function assert_parsed_array() {
local -r input="$1"
shift
local -r expected=("$@")
local -a actual=()
_forgit_parse_array actual "$input"
assert_same "${#expected[@]}" "${#actual[@]}"
local i
for i in "${!expected[@]}"; do
assert_same "${expected[i]}" "${actual[i]}"
done
}
function test_forgit_parse_array_splits_space_separated_values() {
local -r input="--foo --bar"
local -r expected=("--foo" "--bar")
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_keeps_single_value() {
local -r input="--force"
local -r expected=("--force")
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_empty_string_yields_no_elements() {
local -r input=""
local -r expected=()
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_ignores_surrounding_newlines() {
local -r input="
--force
"
local -r expected=("--force")
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_splits_values_across_indented_lines() {
local -r input="
--foo
--bar
"
local -r expected=("--foo" "--bar")
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_splits_on_tabs() {
local -r input=$'\t--foo\t\t--bar\t'
local -r expected=("--foo" "--bar")
assert_parsed_array "$input" "${expected[@]}"
}
function test_forgit_parse_array_whitespace_only_yields_no_elements() {
local -r input="
"
local -r expected=()
assert_parsed_array "$input" "${expected[@]}"
}