Windows: a test_cmp that is agnostic to random LF <> CRLF conversions
authorJohannes Sixt <j6t@kdbg.org>
Sat, 26 Oct 2013 19:17:15 +0000 (21:17 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 28 Oct 2013 16:00:36 +0000 (09:00 -0700)
In a number of tests, output that was produced by a shell script is
compared to expected output using test_cmp. Unfortunately, the MSYS bash--
when invoked via git, such as in hooks--converts LF to CRLF on output
(as produced by echo and printf), which leads to many false positives.

Implements a diff tool that undoes the converted CRLF. To avoid that
sub-processes are spawned (which is very slow on Windows), the tool is
implemented as a shell function. Diff is invoked as usual only when a
difference is detected by the shell code.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/test-lib-functions.sh
t/test-lib.sh
index a7e9aacbb2d9b05b0d5083a0fd70cb9287fcf454..f98769427b51017db7b9d757fd12e582609dbb03 100644 (file)
@@ -710,3 +710,69 @@ test_ln_s_add () {
                git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
        fi
 }
+
+# The following mingw_* functions obey POSIX shell syntax, but are actually
+# bash scripts, and are meant to be used only with bash on Windows.
+
+# A test_cmp function that treats LF and CRLF equal and avoids to fork
+# diff when possible.
+mingw_test_cmp () {
+       # Read text into shell variables and compare them. If the results
+       # are different, use regular diff to report the difference.
+       local test_cmp_a= test_cmp_b=
+
+       # When text came from stdin (one argument is '-') we must feed it
+       # to diff.
+       local stdin_for_diff=
+
+       # Since it is difficult to detect the difference between an
+       # empty input file and a failure to read the files, we go straight
+       # to diff if one of the inputs is empty.
+       if test -s "$1" && test -s "$2"
+       then
+               # regular case: both files non-empty
+               mingw_read_file_strip_cr_ test_cmp_a <"$1"
+               mingw_read_file_strip_cr_ test_cmp_b <"$2"
+       elif test -s "$1" && test "$2" = -
+       then
+               # read 2nd file from stdin
+               mingw_read_file_strip_cr_ test_cmp_a <"$1"
+               mingw_read_file_strip_cr_ test_cmp_b
+               stdin_for_diff='<<<"$test_cmp_b"'
+       elif test "$1" = - && test -s "$2"
+       then
+               # read 1st file from stdin
+               mingw_read_file_strip_cr_ test_cmp_a
+               mingw_read_file_strip_cr_ test_cmp_b <"$2"
+               stdin_for_diff='<<<"$test_cmp_a"'
+       fi
+       test -n "$test_cmp_a" &&
+       test -n "$test_cmp_b" &&
+       test "$test_cmp_a" = "$test_cmp_b" ||
+       eval "diff -u \"\$@\" $stdin_for_diff"
+}
+
+# $1 is the name of the shell variable to fill in
+mingw_read_file_strip_cr_ () {
+       # Read line-wise using LF as the line separator
+       # and use IFS to strip CR.
+       local line
+       while :
+       do
+               if IFS=$'\r' read -r -d $'\n' line
+               then
+                       # good
+                       line=$line$'\n'
+               else
+                       # we get here at EOF, but also if the last line
+                       # was not terminated by LF; in the latter case,
+                       # some text was read
+                       if test -z "$line"
+                       then
+                               # EOF, really
+                               break
+                       fi
+               fi
+               eval "$1=\$$1\$line"
+       done
+}
index 0fa7dfde7bbf201d4756202f3797854b54030ea8..77e487bd576f63564658cef3a7d8aeabe6e08b13 100644 (file)
@@ -817,6 +817,7 @@ case $(uname -s) in
        test_set_prereq NOT_CYGWIN
        test_set_prereq SED_STRIPS_CR
        test_set_prereq GREP_STRIPS_CR
+       GIT_TEST_CMP=mingw_test_cmp
        ;;
 *CYGWIN*)
        test_set_prereq POSIXPERM