All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] t0027: combinations of core.autocrlf, core.eol and text
@ 2014-06-29  6:34 Torsten Bögershausen
  2014-06-30 18:27 ` Junio C Hamano
  0 siblings, 1 reply; 2+ messages in thread
From: Torsten Bögershausen @ 2014-06-29  6:34 UTC (permalink / raw)
  To: git; +Cc: tboegi

Historically there are 3 different parameters controlling how line endings
are handled by Git:
- core.autocrlf
- core.eol
- the "text" attribute in .gitattributes

There are different types of content:
- (1) Files with only LF
- (2) Files with only CRLF
- (3) Files with mixed LF and CRLF
- (4) Files with LF and/or CRLF with CR not followed by LF
- (5) Files which are binary (e.g. have NUL bytes)

Recently the question came up, how files with mixed EOLs are handled by Git
(and libgit2) when they are checked out and core.autocrlf=true.

See
http://git.661346.n2.nabble.com/The-different-EOL-behavior-between-libgit2-based-software-and-official-Git-td7613670.html#a7613801

Add the EXPENSIVE t0027-auto-crlf.sh to test all combination of files
and parameters for both "git add/commit" and "git checkout".

Signed-off-by: Torsten Bögershausen <tboegi@web.de>
---
 t/t0027-auto-crlf.sh | 265 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 265 insertions(+)
 create mode 100755 t/t0027-auto-crlf.sh

diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh
new file mode 100755
index 0000000..72dd3e8
--- /dev/null
+++ b/t/t0027-auto-crlf.sh
@@ -0,0 +1,265 @@
+#!/bin/sh
+
+test_description='CRLF conversion all combinations'
+
+. ./test-lib.sh
+
+if ! test_have_prereq EXPENSIVE
+then
+	skip_all="EXPENSIVE not set"
+	test_done
+fi
+
+
+compare_files()
+{
+	od -c <"$1" >"$1".expect &&
+	od -c <"$2" >"$2".actual &&
+	test_cmp "$1".expect "$2".actual &&
+	rm "$1".expect "$2".actual
+}
+
+compare_ws_file()
+{
+	pfx=$1
+	exp=$2.expect
+	act=$pfx.actual.$3
+	od -c <"$2" >"$exp" &&
+	od -c <"$3" >"$act" &&
+	test_cmp $exp $act &&
+	rm $exp $act
+}
+
+create_gitattributes()
+{
+	txtbin=$1
+	case "$txtbin" in
+		auto)
+		echo "*.txt text=auto" >.gitattributes
+		;;
+		text)
+		echo "*.txt text" >.gitattributes
+		;;
+		-text)
+		echo "*.txt -text" >.gitattributes
+		;;
+		*)
+		echo >.gitattributes
+		;;
+	esac
+}
+
+create_file_in_repo()
+{
+	crlf=$1
+	txtbin=$2
+	create_gitattributes "$txtbin" &&
+	for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
+	do
+		pfx=crlf_${crlf}_attr_${txtbin}_$f.txt &&
+		cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
+	done &&
+	git commit -m "core.autocrlf $crlf"
+}
+
+check_files_in_repo()
+{
+	crlf=$1
+	txtbin=$2
+	lfname=$3
+	crlfname=$4
+	lfmixcrlf=$5
+	lfmixcr=$6
+	crlfnul=$7
+	pfx=crlf_${crlf}_attr_${txtbin}_ &&
+	compare_files $lfname ${pfx}LF.txt &&
+	compare_files $crlfname ${pfx}CRLF.txt &&
+	compare_files $lfmixcrlf ${pfx}CRLF_mix_LF.txt &&
+	compare_files $lfmixcr ${pfx}LF_mix_CR.txt &&
+	compare_files $crlfnul ${pfx}CRLF_nul.txt
+}
+
+
+check_files_in_ws()
+{
+	eol=$1
+	crlf=$2
+	txtbin=$3
+	lfname=$4
+	crlfname=$5
+	lfmixcrlf=$6
+	lfmixcr=$7
+	crlfnul=$8
+	create_gitattributes $txtbin &&
+	git config core.autocrlf $crlf &&
+	pfx=eol_${eol}_crlf_${crlf}_attr_${txtbin}_ &&
+	src=crlf_false_attr__ &&
+	for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
+	do
+		rm $src$f.txt &&
+		if test -z "$eol"; then
+			git checkout $src$f.txt
+		else
+			git -c core.eol=$eol checkout $src$f.txt
+		fi
+	done
+
+
+	test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF" "
+		compare_ws_file $pfx $lfname    ${src}LF.txt
+	"
+	test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF" "
+		compare_ws_file $pfx $crlfname  ${src}CRLF.txt
+	"
+	test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_mix_LF" "
+		compare_ws_file $pfx $lfmixcrlf ${src}CRLF_mix_LF.txt
+	"
+	test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=LF_mix_CR" "
+		compare_ws_file $pfx $lfmixcr   ${src}LF_mix_CR.txt
+	"
+	test_expect_success "checkout core.eol=$eol core.autocrlf=$crlf gitattributes=$txtbin file=CRLF_nul" "
+		compare_ws_file $pfx $crlfnul   ${src}CRLF_nul.txt
+	"
+}
+
+#######
+(
+	type od >/dev/null &&
+	printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul &&
+	cat >expect <<-EOF &&
+	0000000 l i n e 1 \0 \r \n l i n e 2 \r \n l
+	0000020 i n e 3
+	0000024
+EOF
+	od -c CRLF_nul | sed -e "s/[ 	][	 ]*/ /g" -e "s/ *$//" >actual
+	test_cmp expect actual &&
+	rm expect actual
+) || {
+		skip_all="od not found or od -c not usable"
+		exit 0
+		test_done
+}
+
+test_expect_success 'setup master' '
+	echo >.gitattributes &&
+	git checkout -b master &&
+	git add .gitattributes &&
+	git commit -m "add .gitattributes" "" &&
+	printf "line1\nline2\nline3"     >LF &&
+	printf "line1\r\nline2\r\nline3" >CRLF &&
+	printf "line1\r\nline2\nline3"   >CRLF_mix_LF &&
+	printf "line1\nline2\rline3"     >LF_mix_CR &&
+	printf "line1\r\nline2\rline3"   >CRLF_mix_CR &&
+	printf "line1Q\nline2\nline3" | q_to_nul >LF_nul
+'
+#  CRLF_nul had been created above
+
+test_expect_success 'create files' '
+	create_file_in_repo false "" &&
+	create_file_in_repo true  "" &&
+	create_file_in_repo input "" &&
+
+	create_file_in_repo false "auto" &&
+	create_file_in_repo true  "auto" &&
+	create_file_in_repo input "auto" &&
+
+	create_file_in_repo false "text" &&
+	create_file_in_repo true  "text" &&
+	create_file_in_repo input "text" &&
+
+	create_file_in_repo false "-text" &&
+	create_file_in_repo true  "-text" &&
+	create_file_in_repo input "-text" &&
+	rm -f *.txt &&
+	git reset --hard
+'
+
+test_expect_success 'commit empty gitattribues' '
+	check_files_in_repo false ""      LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul &&
+	check_files_in_repo true  ""      LF LF   LF          LF_mix_CR CRLF_nul &&
+	check_files_in_repo input ""      LF LF   LF          LF_mix_CR CRLF_nul
+'
+
+test_expect_success 'commit text=auto' '
+	check_files_in_repo false "auto"  LF LF   LF          LF_mix_CR CRLF_nul &&
+	check_files_in_repo true  "auto"  LF LF   LF          LF_mix_CR CRLF_nul &&
+	check_files_in_repo input "auto"  LF LF   LF          LF_mix_CR CRLF_nul
+'
+
+test_expect_success 'commit text' '
+	check_files_in_repo false "text"  LF LF   LF          LF_mix_CR LF_nul &&
+	check_files_in_repo true  "text"  LF LF   LF          LF_mix_CR LF_nul &&
+	check_files_in_repo input "text"  LF LF   LF          LF_mix_CR LF_nul
+'
+
+test_expect_success 'commit -text' '
+	check_files_in_repo false "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul &&
+	check_files_in_repo true  "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul &&
+	check_files_in_repo input "-text" LF CRLF CRLF_mix_LF LF_mix_CR CRLF_nul
+'
+
+################################################################################
+# Check how files in the repo are changed when they are checked out
+# How to read the table below:
+# - check_files_in_ws will check multiple files, see below
+# - parameter $1 : core.eol               lf | crlf
+# - parameter $2 : core.autocrlf          false | true | input
+# - parameter $3 : text in .gitattributs  "" (empty) | auto | text | -text
+# - parameter $4 : reference for a file with only LF in the repo
+# - parameter $5 : reference for a file with only CRLF in the repo
+# - parameter $6 : reference for a file with mixed LF and CRLF in the repo
+# - parameter $7 : reference for a file with LF and CR in the repo (does somebody uses this ?)
+# - parameter $8 : reference for a file with CRLF and a NUL (should be handled as binary when auto)
+
+check_files_in_ws lf      false  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      true   ""       CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      input  ""       LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+check_files_in_ws lf      false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws lf      input "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+check_files_in_ws lf      false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws lf      input "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+check_files_in_ws lf      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws lf      input "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+###########
+#core.autocrlf=input is forbidden with core.eol=crlf
+check_files_in_ws crlf    false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws crlf    true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+check_files_in_ws crlf    false "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws crlf    true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+
+check_files_in_ws crlf    false "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws crlf    true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+
+check_files_in_ws crlf    false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws crlf    true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+if test_have_prereq MINGW
+then
+check_files_in_ws ""      false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws ""      true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws ""      false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws ""      true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws ""      false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws ""      true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws ""      false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws ""      true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+
+check_files_in_ws native  false ""        LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws native  true  ""        CRLF  CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws native  false "auto"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws native  true  "auto"    CRLF  CRLF  CRLF         LF_mix_CR    CRLF_nul
+check_files_in_ws native  false "text"    LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws native  true  "text"    CRLF  CRLF  CRLF         CRLF_mix_CR  CRLF_nul
+check_files_in_ws native  false "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+check_files_in_ws native  true  "-text"   LF    CRLF  CRLF_mix_LF  LF_mix_CR    CRLF_nul
+fi
+
+test_done
-- 
2.0.0.9631.g7e872d2

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 2/2] t0027: combinations of core.autocrlf, core.eol and text
  2014-06-29  6:34 [PATCH 2/2] t0027: combinations of core.autocrlf, core.eol and text Torsten Bögershausen
@ 2014-06-30 18:27 ` Junio C Hamano
  0 siblings, 0 replies; 2+ messages in thread
From: Junio C Hamano @ 2014-06-30 18:27 UTC (permalink / raw)
  To: Torsten Bögershausen; +Cc: git

Torsten Bögershausen <tboegi@web.de> writes:

> Historically there are 3 different parameters controlling how line endings
> are handled by Git:
> - core.autocrlf
> - core.eol
> - the "text" attribute in .gitattributes
>
> There are different types of content:
> - (1) Files with only LF
> - (2) Files with only CRLF
> - (3) Files with mixed LF and CRLF
> - (4) Files with LF and/or CRLF with CR not followed by LF
> - (5) Files which are binary (e.g. have NUL bytes)
>
> Recently the question came up, how files with mixed EOLs are handled by Git
> (and libgit2) when they are checked out and core.autocrlf=true.

I have a slight suspicion that it may be better to leave behaviour
on some nonsensical combinations (e.g. 3 and 4) as "unspecified",
which would mean we shouldn't be able to pick between
test_expect_success and test_expect_failure for some of them.

> +test_description='CRLF conversion all combinations'
> +
> +check_files_in_ws()
> +{

(minor) Please have SP between "ws" and "()".


> +(
> +	type od >/dev/null &&
> +	printf "line1Q\r\nline2\r\nline3" | q_to_nul >CRLF_nul &&
> +	cat >expect <<-EOF &&
> +	0000000 l i n e 1 \0 \r \n l i n e 2 \r \n l
> +	0000020 i n e 3
> +	0000024
> +EOF
> +	od -c CRLF_nul | sed -e "s/[ 	][	 ]*/ /g" -e "s/ *$//" >actual
> +	test_cmp expect actual &&
> +	rm expect actual
> +) || {
> +		skip_all="od not found or od -c not usable"
> +		exit 0
> +		test_done
> +}

I am not sure how cast-in-stone portable "od -c" output is across
platforms in practice.  You can use tr to convert NUL, CR and LF to
some distinctive and otherwise unused character, just like you use
q_to_nul to map NUL to "Q" already.  And that would allow you to
forget about such portability issues.


> +test_expect_success 'setup master' '
> +	echo >.gitattributes &&
> +	git checkout -b master &&
> +	git add .gitattributes &&
> +	git commit -m "add .gitattributes" "" &&
> +	printf "line1\nline2\nline3"     >LF &&
> +	printf "line1\r\nline2\r\nline3" >CRLF &&
> +	printf "line1\r\nline2\nline3"   >CRLF_mix_LF &&
> +	printf "line1\nline2\rline3"     >LF_mix_CR &&
> +	printf "line1\r\nline2\rline3"   >CRLF_mix_CR &&
> +	printf "line1Q\nline2\nline3" | q_to_nul >LF_nul

I do not see why you would want files that end with incomplete lines
for these.  Please have the line-end for the last line in them.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-06-30 18:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-29  6:34 [PATCH 2/2] t0027: combinations of core.autocrlf, core.eol and text Torsten Bögershausen
2014-06-30 18:27 ` Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.