Windows: a test_cmp that is agnostic to random LF <> CRLF conversions

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>

Johannes Sixt committed Oct 26, 2013 at 21:17 UTC 4d715ac05cf5b800a98ce75bbc0cb3ea2dfe70ab
2 files changed +67
t/test-lib-functions.sh
+66
@@ -710,3 +710,69 @@ test_ln_s_add () {
710 git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
711 fi
712 }
713 +
714 +# The following mingw_* functions obey POSIX shell syntax, but are actually
715 +# bash scripts, and are meant to be used only with bash on Windows.
716 +
717 +# A test_cmp function that treats LF and CRLF equal and avoids to fork
718 +# diff when possible.
719 +mingw_test_cmp () {
720 + # Read text into shell variables and compare them. If the results
721 + # are different, use regular diff to report the difference.
722 + local test_cmp_a= test_cmp_b=
723 +
724 + # When text came from stdin (one argument is '-') we must feed it
725 + # to diff.
726 + local stdin_for_diff=
727 +
728 + # Since it is difficult to detect the difference between an
729 + # empty input file and a failure to read the files, we go straight
730 + # to diff if one of the inputs is empty.
731 + if test -s "$1" && test -s "$2"
732 + then
733 + # regular case: both files non-empty
734 + mingw_read_file_strip_cr_ test_cmp_a <"$1"
735 + mingw_read_file_strip_cr_ test_cmp_b <"$2"
736 + elif test -s "$1" && test "$2" = -
737 + then
738 + # read 2nd file from stdin
739 + mingw_read_file_strip_cr_ test_cmp_a <"$1"
740 + mingw_read_file_strip_cr_ test_cmp_b
741 + stdin_for_diff='<<<"$test_cmp_b"'
742 + elif test "$1" = - && test -s "$2"
743 + then
744 + # read 1st file from stdin
745 + mingw_read_file_strip_cr_ test_cmp_a
746 + mingw_read_file_strip_cr_ test_cmp_b <"$2"
747 + stdin_for_diff='<<<"$test_cmp_a"'
748 + fi
749 + test -n "$test_cmp_a" &&
750 + test -n "$test_cmp_b" &&
751 + test "$test_cmp_a" = "$test_cmp_b" ||
752 + eval "diff -u \"\$@\" $stdin_for_diff"
753 +}
754 +
755 +# $1 is the name of the shell variable to fill in
756 +mingw_read_file_strip_cr_ () {
757 + # Read line-wise using LF as the line separator
758 + # and use IFS to strip CR.
759 + local line
760 + while :
761 + do
762 + if IFS=$'\r' read -r -d $'\n' line
763 + then
764 + # good
765 + line=$line$'\n'
766 + else
767 + # we get here at EOF, but also if the last line
768 + # was not terminated by LF; in the latter case,
769 + # some text was read
770 + if test -z "$line"
771 + then
772 + # EOF, really
773 + break
774 + fi
775 + fi
776 + eval "$1=\$$1\$line"
777 + done
778 +}
t/test-lib.sh
+1
@@ -817,6 +817,7 @@ case $(uname -s) in
817 test_set_prereq NOT_CYGWIN
818 test_set_prereq SED_STRIPS_CR
819 test_set_prereq GREP_STRIPS_CR
820 + GIT_TEST_CMP=mingw_test_cmp
821 ;;
822 *CYGWIN*)
823 test_set_prereq POSIXPERM