From 5428cf712ca7f166a7d1d354e045f1b531a80f7b Mon Sep 17 00:00:00 2001 From: carlfriedrich Date: Mon, 22 Jun 2026 14:34:37 +0200 Subject: [PATCH] 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. --- bin/git-forgit | 7 ++-- tests/parse-array.test.sh | 75 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 tests/parse-array.test.sh diff --git a/bin/git-forgit b/bin/git-forgit index 072aafba..e0374f6f 100755 --- a/bin/git-forgit +++ b/bin/git-forgit @@ -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" } diff --git a/tests/parse-array.test.sh b/tests/parse-array.test.sh new file mode 100644 index 00000000..d2f23f39 --- /dev/null +++ b/tests/parse-array.test.sh @@ -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 [expected_element...] +# 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[@]}" +}