1#!/bin/sh
2#
3# Copyright (c) 2006 Junio C Hamano
4#
5
6test_description='git grep various.
7'
8
9GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
10export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
11
12. ./test-lib.sh
13
14test_invalid_grep_expression() {
15	params="$@" &&
16	test_expect_success "invalid expression: grep $params" '
17		test_must_fail git grep $params -- nonexisting
18	'
19}
20
21cat >hello.c <<EOF
22#include <assert.h>
23#include <stdio.h>
24
25int main(int argc, const char **argv)
26{
27	printf("Hello world.\n");
28	return 0;
29	/* char ?? */
30}
31EOF
32
33test_expect_success setup '
34	{
35		echo foo mmap bar
36		echo foo_mmap bar
37		echo foo_mmap bar mmap
38		echo foo mmap bar_mmap
39		echo foo_mmap bar mmap baz
40	} >file &&
41	{
42		echo Hello world
43		echo HeLLo world
44		echo Hello_world
45		echo HeLLo_world
46	} >hello_world &&
47	{
48		echo "a+b*c"
49		echo "a+bc"
50		echo "abc"
51	} >ab &&
52	{
53		echo d &&
54		echo 0
55	} >d0 &&
56	echo vvv >v &&
57	echo ww w >w &&
58	echo x x xx x >x &&
59	echo y yy >y &&
60	echo zzz > z &&
61	mkdir t &&
62	echo test >t/t &&
63	echo vvv >t/v &&
64	mkdir t/a &&
65	echo vvv >t/a/v &&
66	{
67		echo "line without leading space1"
68		echo " line with leading space1"
69		echo " line with leading space2"
70		echo " line with leading space3"
71		echo "line without leading space2"
72	} >space &&
73	cat >hello.ps1 <<-\EOF &&
74	# No-op.
75	function dummy() {}
76
77	# Say hello.
78	function hello() {
79	  echo "Hello world."
80	} # hello
81
82	# Still a no-op.
83	function dummy() {}
84	EOF
85	if test_have_prereq FUNNYNAMES
86	then
87		echo unusual >"\"unusual\" pathname" &&
88		echo unusual >"t/nested \"unusual\" pathname"
89	fi &&
90	git add . &&
91	test_tick &&
92	git commit -m initial
93'
94
95test_expect_success 'grep should not segfault with a bad input' '
96	test_must_fail git grep "("
97'
98
99test_invalid_grep_expression --and -e A
100
101for H in HEAD ''
102do
103	case "$H" in
104	HEAD)	HC='HEAD:' L='HEAD' ;;
105	'')	HC= L='in working tree' ;;
106	esac
107
108	test_expect_success "grep -w $L" '
109		{
110			echo ${HC}file:1:foo mmap bar
111			echo ${HC}file:3:foo_mmap bar mmap
112			echo ${HC}file:4:foo mmap bar_mmap
113			echo ${HC}file:5:foo_mmap bar mmap baz
114		} >expected &&
115		git -c grep.linenumber=false grep -n -w -e mmap $H >actual &&
116		test_cmp expected actual
117	'
118
119	test_expect_success "grep -w $L (with --column)" '
120		{
121			echo ${HC}file:5:foo mmap bar
122			echo ${HC}file:14:foo_mmap bar mmap
123			echo ${HC}file:5:foo mmap bar_mmap
124			echo ${HC}file:14:foo_mmap bar mmap baz
125		} >expected &&
126		git grep --column -w -e mmap $H >actual &&
127		test_cmp expected actual
128	'
129
130	test_expect_success "grep -w $L (with --column, extended OR)" '
131		{
132			echo ${HC}file:14:foo_mmap bar mmap
133			echo ${HC}file:19:foo_mmap bar mmap baz
134		} >expected &&
135		git grep --column -w -e mmap$ --or -e baz $H >actual &&
136		test_cmp expected actual
137	'
138
139	test_expect_success "grep -w $L (with --column, --invert-match)" '
140		{
141			echo ${HC}file:1:foo mmap bar
142			echo ${HC}file:1:foo_mmap bar
143			echo ${HC}file:1:foo_mmap bar mmap
144			echo ${HC}file:1:foo mmap bar_mmap
145		} >expected &&
146		git grep --column --invert-match -w -e baz $H -- file >actual &&
147		test_cmp expected actual
148	'
149
150	test_expect_success "grep $L (with --column, --invert-match, extended OR)" '
151		{
152			echo ${HC}hello_world:6:HeLLo_world
153		} >expected &&
154		git grep --column --invert-match -e ll --or --not -e _ $H -- hello_world \
155			>actual &&
156		test_cmp expected actual
157	'
158
159	test_expect_success "grep $L (with --column, --invert-match, extended AND)" '
160		{
161			echo ${HC}hello_world:3:Hello world
162			echo ${HC}hello_world:3:Hello_world
163			echo ${HC}hello_world:6:HeLLo_world
164		} >expected &&
165		git grep --column --invert-match --not -e _ --and --not -e ll $H -- hello_world \
166			>actual &&
167		test_cmp expected actual
168	'
169
170	test_expect_success "grep $L (with --column, double-negation)" '
171		{
172			echo ${HC}file:1:foo_mmap bar mmap baz
173		} >expected &&
174		git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \
175			>actual &&
176		test_cmp expected actual
177	'
178
179	test_expect_success "grep -w $L (with --column, -C)" '
180		{
181			echo ${HC}file:5:foo mmap bar
182			echo ${HC}file-foo_mmap bar
183			echo ${HC}file:14:foo_mmap bar mmap
184			echo ${HC}file:5:foo mmap bar_mmap
185			echo ${HC}file:14:foo_mmap bar mmap baz
186		} >expected &&
187		git grep --column -w -C1 -e mmap $H >actual &&
188		test_cmp expected actual
189	'
190
191	test_expect_success "grep -w $L (with --line-number, --column)" '
192		{
193			echo ${HC}file:1:5:foo mmap bar
194			echo ${HC}file:3:14:foo_mmap bar mmap
195			echo ${HC}file:4:5:foo mmap bar_mmap
196			echo ${HC}file:5:14:foo_mmap bar mmap baz
197		} >expected &&
198		git grep -n --column -w -e mmap $H >actual &&
199		test_cmp expected actual
200	'
201
202	test_expect_success "grep -w $L (with non-extended patterns, --column)" '
203		{
204			echo ${HC}file:5:foo mmap bar
205			echo ${HC}file:10:foo_mmap bar
206			echo ${HC}file:10:foo_mmap bar mmap
207			echo ${HC}file:5:foo mmap bar_mmap
208			echo ${HC}file:10:foo_mmap bar mmap baz
209		} >expected &&
210		git grep --column -w -e bar -e mmap $H >actual &&
211		test_cmp expected actual
212	'
213
214	test_expect_success "grep -w $L" '
215		{
216			echo ${HC}file:1:foo mmap bar
217			echo ${HC}file:3:foo_mmap bar mmap
218			echo ${HC}file:4:foo mmap bar_mmap
219			echo ${HC}file:5:foo_mmap bar mmap baz
220		} >expected &&
221		git -c grep.linenumber=true grep -w -e mmap $H >actual &&
222		test_cmp expected actual
223	'
224
225	test_expect_success "grep -w $L" '
226		{
227			echo ${HC}file:foo mmap bar
228			echo ${HC}file:foo_mmap bar mmap
229			echo ${HC}file:foo mmap bar_mmap
230			echo ${HC}file:foo_mmap bar mmap baz
231		} >expected &&
232		git -c grep.linenumber=true grep --no-line-number -w -e mmap $H >actual &&
233		test_cmp expected actual
234	'
235
236	test_expect_success "grep -w $L (w)" '
237		test_must_fail git grep -n -w -e "^w" $H >actual &&
238		test_must_be_empty actual
239	'
240
241	test_expect_success "grep -w $L (x)" '
242		{
243			echo ${HC}x:1:x x xx x
244		} >expected &&
245		git grep -n -w -e "x xx* x" $H >actual &&
246		test_cmp expected actual
247	'
248
249	test_expect_success "grep -w $L (y-1)" '
250		{
251			echo ${HC}y:1:y yy
252		} >expected &&
253		git grep -n -w -e "^y" $H >actual &&
254		test_cmp expected actual
255	'
256
257	test_expect_success "grep -w $L (y-2)" '
258		if git grep -n -w -e "^y y" $H >actual
259		then
260			echo should not have matched
261			cat actual
262			false
263		else
264			test_must_be_empty actual
265		fi
266	'
267
268	test_expect_success "grep -w $L (z)" '
269		if git grep -n -w -e "^z" $H >actual
270		then
271			echo should not have matched
272			cat actual
273			false
274		else
275			test_must_be_empty actual
276		fi
277	'
278
279	test_expect_success "grep $L (with --column, --only-matching)" '
280		{
281			echo ${HC}file:1:5:mmap
282			echo ${HC}file:2:5:mmap
283			echo ${HC}file:3:5:mmap
284			echo ${HC}file:3:13:mmap
285			echo ${HC}file:4:5:mmap
286			echo ${HC}file:4:13:mmap
287			echo ${HC}file:5:5:mmap
288			echo ${HC}file:5:13:mmap
289		} >expected &&
290		git grep --column -n -o -e mmap $H >actual &&
291		test_cmp expected actual
292	'
293
294	test_expect_success "grep $L (t-1)" '
295		echo "${HC}t/t:1:test" >expected &&
296		git grep -n -e test $H >actual &&
297		test_cmp expected actual
298	'
299
300	test_expect_success "grep $L (t-2)" '
301		echo "${HC}t:1:test" >expected &&
302		(
303			cd t &&
304			git grep -n -e test $H
305		) >actual &&
306		test_cmp expected actual
307	'
308
309	test_expect_success "grep $L (t-3)" '
310		echo "${HC}t/t:1:test" >expected &&
311		(
312			cd t &&
313			git grep --full-name -n -e test $H
314		) >actual &&
315		test_cmp expected actual
316	'
317
318	test_expect_success "grep -c $L (no /dev/null)" '
319		! git grep -c test $H | grep /dev/null
320	'
321
322	test_expect_success "grep --max-depth -1 $L" '
323		{
324			echo ${HC}t/a/v:1:vvv
325			echo ${HC}t/v:1:vvv
326			echo ${HC}v:1:vvv
327		} >expected &&
328		git grep --max-depth -1 -n -e vvv $H >actual &&
329		test_cmp expected actual &&
330		git grep --recursive -n -e vvv $H >actual &&
331		test_cmp expected actual
332	'
333
334	test_expect_success "grep --max-depth 0 $L" '
335		{
336			echo ${HC}v:1:vvv
337		} >expected &&
338		git grep --max-depth 0 -n -e vvv $H >actual &&
339		test_cmp expected actual &&
340		git grep --no-recursive -n -e vvv $H >actual &&
341		test_cmp expected actual
342	'
343
344	test_expect_success "grep --max-depth 0 -- '*' $L" '
345		{
346			echo ${HC}t/a/v:1:vvv
347			echo ${HC}t/v:1:vvv
348			echo ${HC}v:1:vvv
349		} >expected &&
350		git grep --max-depth 0 -n -e vvv $H -- "*" >actual &&
351		test_cmp expected actual &&
352		git grep --no-recursive -n -e vvv $H -- "*" >actual &&
353		test_cmp expected actual
354	'
355
356	test_expect_success "grep --max-depth 1 $L" '
357		{
358			echo ${HC}t/v:1:vvv
359			echo ${HC}v:1:vvv
360		} >expected &&
361		git grep --max-depth 1 -n -e vvv $H >actual &&
362		test_cmp expected actual
363	'
364
365	test_expect_success "grep --max-depth 0 -- t $L" '
366		{
367			echo ${HC}t/v:1:vvv
368		} >expected &&
369		git grep --max-depth 0 -n -e vvv $H -- t >actual &&
370		test_cmp expected actual &&
371		git grep --no-recursive -n -e vvv $H -- t >actual &&
372		test_cmp expected actual
373	'
374
375	test_expect_success "grep --max-depth 0 -- . t $L" '
376		{
377			echo ${HC}t/v:1:vvv
378			echo ${HC}v:1:vvv
379		} >expected &&
380		git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
381		test_cmp expected actual &&
382		git grep --no-recursive -n -e vvv $H -- . t >actual &&
383		test_cmp expected actual
384	'
385
386	test_expect_success "grep --max-depth 0 -- t . $L" '
387		{
388			echo ${HC}t/v:1:vvv
389			echo ${HC}v:1:vvv
390		} >expected &&
391		git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
392		test_cmp expected actual &&
393		git grep --no-recursive -n -e vvv $H -- t . >actual &&
394		test_cmp expected actual
395	'
396	test_expect_success "grep $L with grep.extendedRegexp=false" '
397		echo "${HC}ab:a+bc" >expected &&
398		git -c grep.extendedRegexp=false grep "a+b*c" $H ab >actual &&
399		test_cmp expected actual
400	'
401
402	test_expect_success "grep $L with grep.extendedRegexp=true" '
403		echo "${HC}ab:abc" >expected &&
404		git -c grep.extendedRegexp=true grep "a+b*c" $H ab >actual &&
405		test_cmp expected actual
406	'
407
408	test_expect_success "grep $L with grep.patterntype=basic" '
409		echo "${HC}ab:a+bc" >expected &&
410		git -c grep.patterntype=basic grep "a+b*c" $H ab >actual &&
411		test_cmp expected actual
412	'
413
414	test_expect_success "grep $L with grep.patterntype=extended" '
415		echo "${HC}ab:abc" >expected &&
416		git -c grep.patterntype=extended grep "a+b*c" $H ab >actual &&
417		test_cmp expected actual
418	'
419
420	test_expect_success "grep $L with grep.patterntype=fixed" '
421		echo "${HC}ab:a+b*c" >expected &&
422		git -c grep.patterntype=fixed grep "a+b*c" $H ab >actual &&
423		test_cmp expected actual
424	'
425
426	test_expect_success PCRE "grep $L with grep.patterntype=perl" '
427		echo "${HC}ab:a+b*c" >expected &&
428		git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" $H ab >actual &&
429		test_cmp expected actual
430	'
431
432	test_expect_success !FAIL_PREREQS,!PCRE "grep $L with grep.patterntype=perl errors without PCRE" '
433		test_must_fail git -c grep.patterntype=perl grep "foo.*bar"
434	'
435
436	test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" '
437		echo "${HC}ab:abc" >expected &&
438		git \
439			-c grep.patternType=default \
440			-c grep.extendedRegexp=true \
441			grep "a+b*c" $H ab >actual &&
442		test_cmp expected actual
443	'
444
445	test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" '
446		echo "${HC}ab:abc" >expected &&
447		git \
448			-c grep.extendedRegexp=true \
449			-c grep.patternType=default \
450			grep "a+b*c" $H ab >actual &&
451		test_cmp expected actual
452	'
453
454	test_expect_success "grep $L with grep.patternType=extended and grep.extendedRegexp=false" '
455		echo "${HC}ab:abc" >expected &&
456		git \
457			-c grep.patternType=extended \
458			-c grep.extendedRegexp=false \
459			grep "a+b*c" $H ab >actual &&
460		test_cmp expected actual
461	'
462
463	test_expect_success "grep $L with grep.patternType=basic and grep.extendedRegexp=true" '
464		echo "${HC}ab:a+bc" >expected &&
465		git \
466			-c grep.patternType=basic \
467			-c grep.extendedRegexp=true \
468			grep "a+b*c" $H ab >actual &&
469		test_cmp expected actual
470	'
471
472	test_expect_success "grep $L with grep.extendedRegexp=false and grep.patternType=extended" '
473		echo "${HC}ab:abc" >expected &&
474		git \
475			-c grep.extendedRegexp=false \
476			-c grep.patternType=extended \
477			grep "a+b*c" $H ab >actual &&
478		test_cmp expected actual
479	'
480
481	test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=basic" '
482		echo "${HC}ab:a+bc" >expected &&
483		git \
484			-c grep.extendedRegexp=true \
485			-c grep.patternType=basic \
486			grep "a+b*c" $H ab >actual &&
487		test_cmp expected actual
488	'
489
490	test_expect_success "grep --count $L" '
491		echo ${HC}ab:3 >expected &&
492		git grep --count -e b $H -- ab >actual &&
493		test_cmp expected actual
494	'
495
496	test_expect_success "grep --count -h $L" '
497		echo 3 >expected &&
498		git grep --count -h -e b $H -- ab >actual &&
499		test_cmp expected actual
500	'
501
502	test_expect_success FUNNYNAMES "grep $L should quote unusual pathnames" '
503		cat >expected <<-EOF &&
504		${HC}"\"unusual\" pathname":unusual
505		${HC}"t/nested \"unusual\" pathname":unusual
506		EOF
507		git grep unusual $H >actual &&
508		test_cmp expected actual
509	'
510
511	test_expect_success FUNNYNAMES "grep $L in subdir should quote unusual relative pathnames" '
512		cat >expected <<-EOF &&
513		${HC}"nested \"unusual\" pathname":unusual
514		EOF
515		(
516			cd t &&
517			git grep unusual $H
518		) >actual &&
519		test_cmp expected actual
520	'
521
522	test_expect_success FUNNYNAMES "grep -z $L with unusual pathnames" '
523		cat >expected <<-EOF &&
524		${HC}"unusual" pathname:unusual
525		${HC}t/nested "unusual" pathname:unusual
526		EOF
527		git grep -z unusual $H >actual &&
528		tr "\0" ":" <actual >actual-replace-null &&
529		test_cmp expected actual-replace-null
530	'
531
532	test_expect_success FUNNYNAMES "grep -z $L in subdir with unusual relative pathnames" '
533		cat >expected <<-EOF &&
534		${HC}nested "unusual" pathname:unusual
535		EOF
536		(
537			cd t &&
538			git grep -z unusual $H
539		) >actual &&
540		tr "\0" ":" <actual >actual-replace-null &&
541		test_cmp expected actual-replace-null
542	'
543done
544
545cat >expected <<EOF
546file
547EOF
548test_expect_success 'grep -l -C' '
549	git grep -l -C1 foo >actual &&
550	test_cmp expected actual
551'
552
553cat >expected <<EOF
554file:5
555EOF
556test_expect_success 'grep -c -C' '
557	git grep -c -C1 foo >actual &&
558	test_cmp expected actual
559'
560
561test_expect_success 'grep -L -C' '
562	git ls-files >expected &&
563	git grep -L -C1 nonexistent_string >actual &&
564	test_cmp expected actual
565'
566
567test_expect_success 'grep --files-without-match --quiet' '
568	git grep --files-without-match --quiet nonexistent_string >actual &&
569	test_must_be_empty actual
570'
571
572cat >expected <<EOF
573file:foo mmap bar_mmap
574EOF
575
576test_expect_success 'grep -e A --and -e B' '
577	git grep -e "foo mmap" --and -e bar_mmap >actual &&
578	test_cmp expected actual
579'
580
581cat >expected <<EOF
582file:foo_mmap bar mmap
583file:foo_mmap bar mmap baz
584EOF
585
586
587test_expect_success 'grep ( -e A --or -e B ) --and -e B' '
588	git grep \( -e foo_ --or -e baz \) \
589		--and -e " mmap" >actual &&
590	test_cmp expected actual
591'
592
593cat >expected <<EOF
594file:foo mmap bar
595EOF
596
597test_expect_success 'grep -e A --and --not -e B' '
598	git grep -e "foo mmap" --and --not -e bar_mmap >actual &&
599	test_cmp expected actual
600'
601
602test_expect_success 'grep should ignore GREP_OPTIONS' '
603	GREP_OPTIONS=-v git grep " mmap bar\$" >actual &&
604	test_cmp expected actual
605'
606
607test_expect_success 'grep -f, non-existent file' '
608	test_must_fail git grep -f patterns
609'
610
611cat >expected <<EOF
612file:foo mmap bar
613file:foo_mmap bar
614file:foo_mmap bar mmap
615file:foo mmap bar_mmap
616file:foo_mmap bar mmap baz
617EOF
618
619cat >pattern <<EOF
620mmap
621EOF
622
623test_expect_success 'grep -f, one pattern' '
624	git grep -f pattern >actual &&
625	test_cmp expected actual
626'
627
628cat >expected <<EOF
629file:foo mmap bar
630file:foo_mmap bar
631file:foo_mmap bar mmap
632file:foo mmap bar_mmap
633file:foo_mmap bar mmap baz
634t/a/v:vvv
635t/v:vvv
636v:vvv
637EOF
638
639cat >patterns <<EOF
640mmap
641vvv
642EOF
643
644test_expect_success 'grep -f, multiple patterns' '
645	git grep -f patterns >actual &&
646	test_cmp expected actual
647'
648
649test_expect_success 'grep, multiple patterns' '
650	git grep "$(cat patterns)" >actual &&
651	test_cmp expected actual
652'
653
654cat >expected <<EOF
655file:foo mmap bar
656file:foo_mmap bar
657file:foo_mmap bar mmap
658file:foo mmap bar_mmap
659file:foo_mmap bar mmap baz
660t/a/v:vvv
661t/v:vvv
662v:vvv
663EOF
664
665cat >patterns <<EOF
666
667mmap
668
669vvv
670
671EOF
672
673test_expect_success 'grep -f, ignore empty lines' '
674	git grep -f patterns >actual &&
675	test_cmp expected actual
676'
677
678test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
679	git grep -f - <patterns >actual &&
680	test_cmp expected actual
681'
682
683cat >expected <<EOF
684y:y yy
685--
686z:zzz
687EOF
688
689test_expect_success 'grep -q, silently report matches' '
690	git grep -q mmap >actual &&
691	test_must_be_empty actual &&
692	test_must_fail git grep -q qfwfq >actual &&
693	test_must_be_empty actual
694'
695
696test_expect_success 'grep -C1 hunk mark between files' '
697	git grep -C1 "^[yz]" >actual &&
698	test_cmp expected actual
699'
700
701test_expect_success 'log grep setup' '
702	test_commit --append --author "With * Asterisk <xyzzy@frotz.com>" second file a &&
703	test_commit --append third file a &&
704	test_commit --append --author "Night Fall <nitfol@frobozz.com>" fourth file a
705'
706
707test_expect_success 'log grep (1)' '
708	git log --author=author --pretty=tformat:%s >actual &&
709	{
710		echo third && echo initial
711	} >expect &&
712	test_cmp expect actual
713'
714
715test_expect_success 'log grep (2)' '
716	git log --author=" * " -F --pretty=tformat:%s >actual &&
717	{
718		echo second
719	} >expect &&
720	test_cmp expect actual
721'
722
723test_expect_success 'log grep (3)' '
724	git log --author="^A U" --pretty=tformat:%s >actual &&
725	{
726		echo third && echo initial
727	} >expect &&
728	test_cmp expect actual
729'
730
731test_expect_success 'log grep (4)' '
732	git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
733	{
734		echo second
735	} >expect &&
736	test_cmp expect actual
737'
738
739test_expect_success 'log grep (5)' '
740	git log --author=Thor -F --pretty=tformat:%s >actual &&
741	{
742		echo third && echo initial
743	} >expect &&
744	test_cmp expect actual
745'
746
747test_expect_success 'log grep (6)' '
748	git log --author=-0700  --pretty=tformat:%s >actual &&
749	test_must_be_empty actual
750'
751
752test_expect_success 'log grep (7)' '
753	git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual &&
754	echo third >expect &&
755	test_cmp expect actual
756'
757
758test_expect_success 'log grep (8)' '
759	git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual &&
760	{
761		echo third && echo second
762	} >expect &&
763	test_cmp expect actual
764'
765
766test_expect_success 'log grep (9)' '
767	git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual &&
768	echo third >expect &&
769	test_cmp expect actual
770'
771
772test_expect_success 'log grep (9)' '
773	git log -g --grep-reflog="commit: third" --author="non-existent" --pretty=tformat:%s >actual &&
774	test_must_be_empty actual
775'
776
777test_expect_success 'log --grep-reflog can only be used under -g' '
778	test_must_fail git log --grep-reflog="commit: third"
779'
780
781test_expect_success 'log with multiple --grep uses union' '
782	git log --grep=i --grep=r --format=%s >actual &&
783	{
784		echo fourth && echo third && echo initial
785	} >expect &&
786	test_cmp expect actual
787'
788
789test_expect_success 'log --all-match with multiple --grep uses intersection' '
790	git log --all-match --grep=i --grep=r --format=%s >actual &&
791	{
792		echo third
793	} >expect &&
794	test_cmp expect actual
795'
796
797test_expect_success 'log with multiple --author uses union' '
798	git log --author="Thor" --author="Aster" --format=%s >actual &&
799	{
800	    echo third && echo second && echo initial
801	} >expect &&
802	test_cmp expect actual
803'
804
805test_expect_success 'log --all-match with multiple --author still uses union' '
806	git log --all-match --author="Thor" --author="Aster" --format=%s >actual &&
807	{
808	    echo third && echo second && echo initial
809	} >expect &&
810	test_cmp expect actual
811'
812
813test_expect_success 'log --grep --author uses intersection' '
814	# grep matches only third and fourth
815	# author matches only initial and third
816	git log --author="A U Thor" --grep=r --format=%s >actual &&
817	{
818		echo third
819	} >expect &&
820	test_cmp expect actual
821'
822
823test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' '
824	# grep matches initial and second but not third
825	# author matches only initial and third
826	git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
827	{
828		echo initial
829	} >expect &&
830	test_cmp expect actual
831'
832
833test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' '
834	# grep matches only initial and third
835	# author matches all but second
836	git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&
837	{
838	    echo third && echo initial
839	} >expect &&
840	test_cmp expect actual
841'
842
843test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' '
844	# grep matches only initial and third
845	# author matches all but second
846	git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
847	{
848	    echo third && echo initial
849	} >expect &&
850	test_cmp expect actual
851'
852
853test_expect_success 'log --all-match --grep --grep --author takes intersection' '
854	# grep matches only third
855	# author matches only initial and third
856	git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual &&
857	{
858		echo third
859	} >expect &&
860	test_cmp expect actual
861'
862
863test_expect_success 'log --author does not search in timestamp' '
864	git log --author="$GIT_AUTHOR_DATE" >actual &&
865	test_must_be_empty actual
866'
867
868test_expect_success 'log --committer does not search in timestamp' '
869	git log --committer="$GIT_COMMITTER_DATE" >actual &&
870	test_must_be_empty actual
871'
872
873test_expect_success 'grep with CE_VALID file' '
874	git update-index --assume-unchanged t/t &&
875	rm t/t &&
876	test "$(git grep test)" = "t/t:test" &&
877	git update-index --no-assume-unchanged t/t &&
878	git checkout t/t
879'
880
881cat >expected <<EOF
882hello.c=#include <stdio.h>
883hello.c:	return 0;
884EOF
885
886test_expect_success 'grep -p with userdiff' '
887	git config diff.custom.funcname "^#" &&
888	echo "hello.c diff=custom" >.gitattributes &&
889	git grep -p return >actual &&
890	test_cmp expected actual
891'
892
893cat >expected <<EOF
894hello.c=int main(int argc, const char **argv)
895hello.c:	return 0;
896EOF
897
898test_expect_success 'grep -p' '
899	rm -f .gitattributes &&
900	git grep -p return >actual &&
901	test_cmp expected actual
902'
903
904cat >expected <<EOF
905hello.c-#include <stdio.h>
906hello.c-
907hello.c=int main(int argc, const char **argv)
908hello.c-{
909hello.c-	printf("Hello world.\n");
910hello.c:	return 0;
911EOF
912
913test_expect_success 'grep -p -B5' '
914	git grep -p -B5 return >actual &&
915	test_cmp expected actual
916'
917
918cat >expected <<EOF
919hello.c=int main(int argc, const char **argv)
920hello.c-{
921hello.c-	printf("Hello world.\n");
922hello.c:	return 0;
923hello.c-	/* char ?? */
924hello.c-}
925EOF
926
927test_expect_success 'grep -W' '
928	git grep -W return >actual &&
929	test_cmp expected actual
930'
931
932cat >expected <<EOF
933hello.c-#include <assert.h>
934hello.c:#include <stdio.h>
935EOF
936
937test_expect_success 'grep -W shows no trailing empty lines' '
938	git grep -W stdio >actual &&
939	test_cmp expected actual
940'
941
942test_expect_success 'grep -W with userdiff' '
943	test_when_finished "rm -f .gitattributes" &&
944	git config diff.custom.xfuncname "^function .*$" &&
945	echo "hello.ps1 diff=custom" >.gitattributes &&
946	git grep -W echo >function-context-userdiff-actual
947'
948
949test_expect_success ' includes preceding comment' '
950	grep "# Say hello" function-context-userdiff-actual
951'
952
953test_expect_success ' includes function line' '
954	grep "=function hello" function-context-userdiff-actual
955'
956
957test_expect_success ' includes matching line' '
958	grep ":  echo" function-context-userdiff-actual
959'
960
961test_expect_success ' includes last line of the function' '
962	grep "} # hello" function-context-userdiff-actual
963'
964
965for threads in $(test_seq 0 10)
966do
967	test_expect_success "grep --threads=$threads & -c grep.threads=$threads" "
968		git grep --threads=$threads . >actual.$threads &&
969		if test $threads -ge 1
970		then
971			test_cmp actual.\$(($threads - 1)) actual.$threads
972		fi &&
973		git -c grep.threads=$threads grep . >actual.$threads &&
974		if test $threads -ge 1
975		then
976			test_cmp actual.\$(($threads - 1)) actual.$threads
977		fi
978	"
979done
980
981test_expect_success !PTHREADS,!FAIL_PREREQS \
982	'grep --threads=N or pack.threads=N warns when no pthreads' '
983	git grep --threads=2 Hello hello_world 2>err &&
984	grep ^warning: err >warnings &&
985	test_line_count = 1 warnings &&
986	grep -F "no threads support, ignoring --threads" err &&
987	git -c grep.threads=2 grep Hello hello_world 2>err &&
988	grep ^warning: err >warnings &&
989	test_line_count = 1 warnings &&
990	grep -F "no threads support, ignoring grep.threads" err &&
991	git -c grep.threads=2 grep --threads=4 Hello hello_world 2>err &&
992	grep ^warning: err >warnings &&
993	test_line_count = 2 warnings &&
994	grep -F "no threads support, ignoring --threads" err &&
995	grep -F "no threads support, ignoring grep.threads" err &&
996	git -c grep.threads=0 grep --threads=0 Hello hello_world 2>err &&
997	test_line_count = 0 err
998'
999
1000test_expect_success 'grep from a subdirectory to search wider area (1)' '
1001	mkdir -p s &&
1002	(
1003		cd s && git grep "x x x" ..
1004	)
1005'
1006
1007test_expect_success 'grep from a subdirectory to search wider area (2)' '
1008	mkdir -p s &&
1009	(
1010		cd s &&
1011		test_expect_code 1 git grep xxyyzz .. >out &&
1012		test_must_be_empty out
1013	)
1014'
1015
1016cat >expected <<EOF
1017hello.c:int main(int argc, const char **argv)
1018EOF
1019
1020test_expect_success 'grep -Fi' '
1021	git grep -Fi "CHAR *" >actual &&
1022	test_cmp expected actual
1023'
1024
1025test_expect_success 'outside of git repository' '
1026	rm -fr non &&
1027	mkdir -p non/git/sub &&
1028	echo hello >non/git/file1 &&
1029	echo world >non/git/sub/file2 &&
1030	{
1031		echo file1:hello &&
1032		echo sub/file2:world
1033	} >non/expect.full &&
1034	echo file2:world >non/expect.sub &&
1035	(
1036		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1037		export GIT_CEILING_DIRECTORIES &&
1038		cd non/git &&
1039		test_must_fail git grep o &&
1040		git grep --no-index o >../actual.full &&
1041		test_cmp ../expect.full ../actual.full &&
1042		cd sub &&
1043		test_must_fail git grep o &&
1044		git grep --no-index o >../../actual.sub &&
1045		test_cmp ../../expect.sub ../../actual.sub
1046	) &&
1047
1048	echo ".*o*" >non/git/.gitignore &&
1049	(
1050		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1051		export GIT_CEILING_DIRECTORIES &&
1052		cd non/git &&
1053		test_must_fail git grep o &&
1054		git grep --no-index --exclude-standard o >../actual.full &&
1055		test_cmp ../expect.full ../actual.full &&
1056
1057		{
1058			echo ".gitignore:.*o*" &&
1059			cat ../expect.full
1060		} >../expect.with.ignored &&
1061		git grep --no-index --no-exclude-standard o >../actual.full &&
1062		test_cmp ../expect.with.ignored ../actual.full
1063	)
1064'
1065
1066test_expect_success 'outside of git repository with fallbackToNoIndex' '
1067	rm -fr non &&
1068	mkdir -p non/git/sub &&
1069	echo hello >non/git/file1 &&
1070	echo world >non/git/sub/file2 &&
1071	cat <<-\EOF >non/expect.full &&
1072	file1:hello
1073	sub/file2:world
1074	EOF
1075	echo file2:world >non/expect.sub &&
1076	(
1077		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1078		export GIT_CEILING_DIRECTORIES &&
1079		cd non/git &&
1080		test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1081		git -c grep.fallbackToNoIndex=true grep o >../actual.full &&
1082		test_cmp ../expect.full ../actual.full &&
1083		cd sub &&
1084		test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1085		git -c grep.fallbackToNoIndex=true grep o >../../actual.sub &&
1086		test_cmp ../../expect.sub ../../actual.sub
1087	) &&
1088
1089	echo ".*o*" >non/git/.gitignore &&
1090	(
1091		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1092		export GIT_CEILING_DIRECTORIES &&
1093		cd non/git &&
1094		test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
1095		git -c grep.fallbackToNoIndex=true grep --exclude-standard o >../actual.full &&
1096		test_cmp ../expect.full ../actual.full &&
1097
1098		{
1099			echo ".gitignore:.*o*" &&
1100			cat ../expect.full
1101		} >../expect.with.ignored &&
1102		git -c grep.fallbackToNoIndex grep --no-exclude-standard o >../actual.full &&
1103		test_cmp ../expect.with.ignored ../actual.full
1104	)
1105'
1106
1107test_expect_success 'inside git repository but with --no-index' '
1108	rm -fr is &&
1109	mkdir -p is/git/sub &&
1110	echo hello >is/git/file1 &&
1111	echo world >is/git/sub/file2 &&
1112	echo ".*o*" >is/git/.gitignore &&
1113	{
1114		echo file1:hello &&
1115		echo sub/file2:world
1116	} >is/expect.unignored &&
1117	{
1118		echo ".gitignore:.*o*" &&
1119		cat is/expect.unignored
1120	} >is/expect.full &&
1121	echo file2:world >is/expect.sub &&
1122	(
1123		cd is/git &&
1124		git init &&
1125		test_must_fail git grep o >../actual.full &&
1126		test_must_be_empty ../actual.full &&
1127
1128		git grep --untracked o >../actual.unignored &&
1129		test_cmp ../expect.unignored ../actual.unignored &&
1130
1131		git grep --no-index o >../actual.full &&
1132		test_cmp ../expect.full ../actual.full &&
1133
1134		git grep --no-index --exclude-standard o >../actual.unignored &&
1135		test_cmp ../expect.unignored ../actual.unignored &&
1136
1137		cd sub &&
1138		test_must_fail git grep o >../../actual.sub &&
1139		test_must_be_empty ../../actual.sub &&
1140
1141		git grep --no-index o >../../actual.sub &&
1142		test_cmp ../../expect.sub ../../actual.sub &&
1143
1144		git grep --untracked o >../../actual.sub &&
1145		test_cmp ../../expect.sub ../../actual.sub
1146	)
1147'
1148
1149test_expect_success 'grep --no-index descends into repos, but not .git' '
1150	rm -fr non &&
1151	mkdir -p non/git &&
1152	(
1153		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1154		export GIT_CEILING_DIRECTORIES &&
1155		cd non/git &&
1156
1157		echo magic >file &&
1158		git init repo &&
1159		(
1160			cd repo &&
1161			echo magic >file &&
1162			git add file &&
1163			git commit -m foo &&
1164			echo magic >.git/file
1165		) &&
1166
1167		cat >expect <<-\EOF &&
1168		file
1169		repo/file
1170		EOF
1171		git grep -l --no-index magic >actual &&
1172		test_cmp expect actual
1173	)
1174'
1175
1176test_expect_success 'setup double-dash tests' '
1177cat >double-dash <<EOF &&
1178--
1179->
1180other
1181EOF
1182git add double-dash
1183'
1184
1185cat >expected <<EOF
1186double-dash:->
1187EOF
1188test_expect_success 'grep -- pattern' '
1189	git grep -- "->" >actual &&
1190	test_cmp expected actual
1191'
1192test_expect_success 'grep -- pattern -- pathspec' '
1193	git grep -- "->" -- double-dash >actual &&
1194	test_cmp expected actual
1195'
1196test_expect_success 'grep -e pattern -- path' '
1197	git grep -e "->" -- double-dash >actual &&
1198	test_cmp expected actual
1199'
1200
1201cat >expected <<EOF
1202double-dash:--
1203EOF
1204test_expect_success 'grep -e -- -- path' '
1205	git grep -e -- -- double-dash >actual &&
1206	test_cmp expected actual
1207'
1208
1209test_expect_success 'dashdash disambiguates rev as rev' '
1210	test_when_finished "rm -f main" &&
1211	echo content >main &&
1212	echo main:hello.c >expect &&
1213	git grep -l o main -- hello.c >actual &&
1214	test_cmp expect actual
1215'
1216
1217test_expect_success 'dashdash disambiguates pathspec as pathspec' '
1218	test_when_finished "git rm -f main" &&
1219	echo content >main &&
1220	git add main &&
1221	echo main:content >expect &&
1222	git grep o -- main >actual &&
1223	test_cmp expect actual
1224'
1225
1226test_expect_success 'report bogus arg without dashdash' '
1227	test_must_fail git grep o does-not-exist
1228'
1229
1230test_expect_success 'report bogus rev with dashdash' '
1231	test_must_fail git grep o hello.c --
1232'
1233
1234test_expect_success 'allow non-existent path with dashdash' '
1235	# We need a real match so grep exits with success.
1236	tree=$(git ls-tree HEAD |
1237	       sed s/hello.c/not-in-working-tree/ |
1238	       git mktree) &&
1239	git grep o "$tree" -- not-in-working-tree
1240'
1241
1242test_expect_success 'grep --no-index pattern -- path' '
1243	rm -fr non &&
1244	mkdir -p non/git &&
1245	(
1246		GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
1247		export GIT_CEILING_DIRECTORIES &&
1248		cd non/git &&
1249		echo hello >hello &&
1250		echo goodbye >goodbye &&
1251		echo hello:hello >expect &&
1252		git grep --no-index o -- hello >actual &&
1253		test_cmp expect actual
1254	)
1255'
1256
1257test_expect_success 'grep --no-index complains of revs' '
1258	test_must_fail git grep --no-index o main -- 2>err &&
1259	test_i18ngrep "cannot be used with revs" err
1260'
1261
1262test_expect_success 'grep --no-index prefers paths to revs' '
1263	test_when_finished "rm -f main" &&
1264	echo content >main &&
1265	echo main:content >expect &&
1266	git grep --no-index o main >actual &&
1267	test_cmp expect actual
1268'
1269
1270test_expect_success 'grep --no-index does not "diagnose" revs' '
1271	test_must_fail git grep --no-index o :1:hello.c 2>err &&
1272	test_i18ngrep ! -i "did you mean" err
1273'
1274
1275cat >expected <<EOF
1276hello.c:int main(int argc, const char **argv)
1277hello.c:	printf("Hello world.\n");
1278EOF
1279
1280test_expect_success PCRE 'grep --perl-regexp pattern' '
1281	git grep --perl-regexp "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1282	test_cmp expected actual
1283'
1284
1285test_expect_success !FAIL_PREREQS,!PCRE 'grep --perl-regexp pattern errors without PCRE' '
1286	test_must_fail git grep --perl-regexp "foo.*bar"
1287'
1288
1289test_expect_success PCRE 'grep -P pattern' '
1290	git grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1291	test_cmp expected actual
1292'
1293
1294test_expect_success LIBPCRE2 "grep -P with (*NO_JIT) doesn't error out" '
1295	git grep -P "(*NO_JIT)\p{Ps}.*?\p{Pe}" hello.c >actual &&
1296	test_cmp expected actual
1297
1298'
1299
1300test_expect_success !FAIL_PREREQS,!PCRE 'grep -P pattern errors without PCRE' '
1301	test_must_fail git grep -P "foo.*bar"
1302'
1303
1304test_expect_success 'grep pattern with grep.extendedRegexp=true' '
1305	test_must_fail git -c grep.extendedregexp=true \
1306		grep "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1307	test_must_be_empty actual
1308'
1309
1310test_expect_success PCRE 'grep -P pattern with grep.extendedRegexp=true' '
1311	git -c grep.extendedregexp=true \
1312		grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
1313	test_cmp expected actual
1314'
1315
1316test_expect_success PCRE 'grep -P -v pattern' '
1317	{
1318		echo "ab:a+b*c"
1319		echo "ab:a+bc"
1320	} >expected &&
1321	git grep -P -v "abc" ab >actual &&
1322	test_cmp expected actual
1323'
1324
1325test_expect_success PCRE 'grep -P -i pattern' '
1326	cat >expected <<-EOF &&
1327	hello.c:	printf("Hello world.\n");
1328	EOF
1329	git grep -P -i "PRINTF\([^\d]+\)" hello.c >actual &&
1330	test_cmp expected actual
1331'
1332
1333test_expect_success PCRE 'grep -P -w pattern' '
1334	{
1335		echo "hello_world:Hello world"
1336		echo "hello_world:HeLLo world"
1337	} >expected &&
1338	git grep -P -w "He((?i)ll)o" hello_world >actual &&
1339	test_cmp expected actual
1340'
1341
1342test_expect_success PCRE 'grep -P backreferences work (the PCRE NO_AUTO_CAPTURE flag is not set)' '
1343	git grep -P -h "(?P<one>.)(?P=one)" hello_world >actual &&
1344	test_cmp hello_world actual &&
1345	git grep -P -h "(.)\1" hello_world >actual &&
1346	test_cmp hello_world actual
1347'
1348
1349test_expect_success 'grep -G invalidpattern properly dies ' '
1350	test_must_fail git grep -G "a["
1351'
1352
1353test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
1354	test_must_fail git -c grep.patterntype=basic grep "a["
1355'
1356
1357test_expect_success 'grep -E invalidpattern properly dies ' '
1358	test_must_fail git grep -E "a["
1359'
1360
1361test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
1362	test_must_fail git -c grep.patterntype=extended grep "a["
1363'
1364
1365test_expect_success PCRE 'grep -P invalidpattern properly dies ' '
1366	test_must_fail git grep -P "a["
1367'
1368
1369test_expect_success PCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
1370	test_must_fail git -c grep.patterntype=perl grep "a["
1371'
1372
1373test_expect_success 'grep -G -E -F pattern' '
1374	echo "ab:a+b*c" >expected &&
1375	git grep -G -E -F "a+b*c" ab >actual &&
1376	test_cmp expected actual
1377'
1378
1379test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
1380	echo "ab:a+b*c" >expected &&
1381	git \
1382		-c grep.patterntype=basic \
1383		-c grep.patterntype=extended \
1384		-c grep.patterntype=fixed \
1385		grep "a+b*c" ab >actual &&
1386	test_cmp expected actual
1387'
1388
1389test_expect_success 'grep -E -F -G pattern' '
1390	echo "ab:a+bc" >expected &&
1391	git grep -E -F -G "a+b*c" ab >actual &&
1392	test_cmp expected actual
1393'
1394
1395test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
1396	echo "ab:a+bc" >expected &&
1397	git \
1398		-c grep.patterntype=extended \
1399		-c grep.patterntype=fixed \
1400		-c grep.patterntype=basic \
1401		grep "a+b*c" ab >actual &&
1402	test_cmp expected actual
1403'
1404
1405test_expect_success 'grep -F -G -E pattern' '
1406	echo "ab:abc" >expected &&
1407	git grep -F -G -E "a+b*c" ab >actual &&
1408	test_cmp expected actual
1409'
1410
1411test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
1412	echo "ab:abc" >expected &&
1413	git \
1414		-c grep.patterntype=fixed \
1415		-c grep.patterntype=basic \
1416		-c grep.patterntype=extended \
1417		grep "a+b*c" ab >actual &&
1418	test_cmp expected actual
1419'
1420
1421test_expect_success 'grep -G -F -P -E pattern' '
1422	echo "d0:d" >expected &&
1423	git grep -G -F -P -E "[\d]" d0 >actual &&
1424	test_cmp expected actual
1425'
1426
1427test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
1428	echo "d0:d" >expected &&
1429	git \
1430		-c grep.patterntype=fixed \
1431		-c grep.patterntype=basic \
1432		-c grep.patterntype=perl \
1433		-c grep.patterntype=extended \
1434		grep "[\d]" d0 >actual &&
1435	test_cmp expected actual
1436'
1437
1438test_expect_success PCRE 'grep -G -F -E -P pattern' '
1439	echo "d0:0" >expected &&
1440	git grep -G -F -E -P "[\d]" d0 >actual &&
1441	test_cmp expected actual
1442'
1443
1444test_expect_success PCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
1445	echo "d0:0" >expected &&
1446	git \
1447		-c grep.patterntype=fixed \
1448		-c grep.patterntype=basic \
1449		-c grep.patterntype=extended \
1450		-c grep.patterntype=perl \
1451		grep "[\d]" d0 >actual &&
1452	test_cmp expected actual
1453'
1454
1455test_expect_success PCRE 'grep -P pattern with grep.patternType=fixed' '
1456	echo "ab:a+b*c" >expected &&
1457	git \
1458		-c grep.patterntype=fixed \
1459		grep -P "a\x{2b}b\x{2a}c" ab >actual &&
1460	test_cmp expected actual
1461'
1462
1463test_expect_success 'grep -F pattern with grep.patternType=basic' '
1464	echo "ab:a+b*c" >expected &&
1465	git \
1466		-c grep.patterntype=basic \
1467		grep -F "*c" ab >actual &&
1468	test_cmp expected actual
1469'
1470
1471test_expect_success 'grep -G pattern with grep.patternType=fixed' '
1472	{
1473		echo "ab:a+b*c"
1474		echo "ab:a+bc"
1475	} >expected &&
1476	git \
1477		-c grep.patterntype=fixed \
1478		grep -G "a+b" ab >actual &&
1479	test_cmp expected actual
1480'
1481
1482test_expect_success 'grep -E pattern with grep.patternType=fixed' '
1483	{
1484		echo "ab:a+b*c"
1485		echo "ab:a+bc"
1486		echo "ab:abc"
1487	} >expected &&
1488	git \
1489		-c grep.patterntype=fixed \
1490		grep -E "a+" ab >actual &&
1491	test_cmp expected actual
1492'
1493
1494cat >expected <<EOF
1495hello.c<RED>:<RESET>int main(int argc, const char **argv)
1496hello.c<RED>-<RESET>{
1497<RED>--<RESET>
1498hello.c<RED>:<RESET>	/* char ?? */
1499hello.c<RED>-<RESET>}
1500<RED>--<RESET>
1501hello_world<RED>:<RESET>Hello_world
1502hello_world<RED>-<RESET>HeLLo_world
1503EOF
1504
1505test_expect_success 'grep --color, separator' '
1506	test_config color.grep.context		normal &&
1507	test_config color.grep.filename		normal &&
1508	test_config color.grep.function		normal &&
1509	test_config color.grep.linenumber	normal &&
1510	test_config color.grep.match		normal &&
1511	test_config color.grep.selected		normal &&
1512	test_config color.grep.separator	red &&
1513
1514	git grep --color=always -A1 -e char -e lo_w hello.c hello_world |
1515	test_decode_color >actual &&
1516	test_cmp expected actual
1517'
1518
1519cat >expected <<EOF
1520hello.c:int main(int argc, const char **argv)
1521hello.c:	/* char ?? */
1522
1523hello_world:Hello_world
1524EOF
1525
1526test_expect_success 'grep --break' '
1527	git grep --break -e char -e lo_w hello.c hello_world >actual &&
1528	test_cmp expected actual
1529'
1530
1531cat >expected <<EOF
1532hello.c:int main(int argc, const char **argv)
1533hello.c-{
1534--
1535hello.c:	/* char ?? */
1536hello.c-}
1537
1538hello_world:Hello_world
1539hello_world-HeLLo_world
1540EOF
1541
1542test_expect_success 'grep --break with context' '
1543	git grep --break -A1 -e char -e lo_w hello.c hello_world >actual &&
1544	test_cmp expected actual
1545'
1546
1547cat >expected <<EOF
1548hello.c
1549int main(int argc, const char **argv)
1550	/* char ?? */
1551hello_world
1552Hello_world
1553EOF
1554
1555test_expect_success 'grep --heading' '
1556	git grep --heading -e char -e lo_w hello.c hello_world >actual &&
1557	test_cmp expected actual
1558'
1559
1560cat >expected <<EOF
1561<BOLD;GREEN>hello.c<RESET>
15624:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv)
15638:	/* <BLACK;BYELLOW>char<RESET> ?? */
1564
1565<BOLD;GREEN>hello_world<RESET>
15663:Hel<BLACK;BYELLOW>lo_w<RESET>orld
1567EOF
1568
1569test_expect_success 'mimic ack-grep --group' '
1570	test_config color.grep.context		normal &&
1571	test_config color.grep.filename		"bold green" &&
1572	test_config color.grep.function		normal &&
1573	test_config color.grep.linenumber	normal &&
1574	test_config color.grep.match		"black yellow" &&
1575	test_config color.grep.selected		normal &&
1576	test_config color.grep.separator	normal &&
1577
1578	git grep --break --heading -n --color \
1579		-e char -e lo_w hello.c hello_world |
1580	test_decode_color >actual &&
1581	test_cmp expected actual
1582'
1583
1584cat >expected <<EOF
1585space: line with leading space1
1586space: line with leading space2
1587space: line with leading space3
1588EOF
1589
1590test_expect_success PCRE 'grep -E "^ "' '
1591	git grep -E "^ " space >actual &&
1592	test_cmp expected actual
1593'
1594
1595test_expect_success PCRE 'grep -P "^ "' '
1596	git grep -P "^ " space >actual &&
1597	test_cmp expected actual
1598'
1599
1600cat >expected <<EOF
1601space-line without leading space1
1602space: line <RED>with <RESET>leading space1
1603space: line <RED>with <RESET>leading <RED>space2<RESET>
1604space: line <RED>with <RESET>leading space3
1605space:line without leading <RED>space2<RESET>
1606EOF
1607
1608test_expect_success 'grep --color -e A -e B with context' '
1609	test_config color.grep.context		normal &&
1610	test_config color.grep.filename		normal &&
1611	test_config color.grep.function		normal &&
1612	test_config color.grep.linenumber	normal &&
1613	test_config color.grep.matchContext	normal &&
1614	test_config color.grep.matchSelected	red &&
1615	test_config color.grep.selected		normal &&
1616	test_config color.grep.separator	normal &&
1617
1618	git grep --color=always -C2 -e "with " -e space2  space |
1619	test_decode_color >actual &&
1620	test_cmp expected actual
1621'
1622
1623cat >expected <<EOF
1624space-line without leading space1
1625space- line with leading space1
1626space: line <RED>with <RESET>leading <RED>space2<RESET>
1627space- line with leading space3
1628space-line without leading space2
1629EOF
1630
1631test_expect_success 'grep --color -e A --and -e B with context' '
1632	test_config color.grep.context		normal &&
1633	test_config color.grep.filename		normal &&
1634	test_config color.grep.function		normal &&
1635	test_config color.grep.linenumber	normal &&
1636	test_config color.grep.matchContext	normal &&
1637	test_config color.grep.matchSelected	red &&
1638	test_config color.grep.selected		normal &&
1639	test_config color.grep.separator	normal &&
1640
1641	git grep --color=always -C2 -e "with " --and -e space2  space |
1642	test_decode_color >actual &&
1643	test_cmp expected actual
1644'
1645
1646cat >expected <<EOF
1647space-line without leading space1
1648space: line <RED>with <RESET>leading space1
1649space- line with leading space2
1650space: line <RED>with <RESET>leading space3
1651space-line without leading space2
1652EOF
1653
1654test_expect_success 'grep --color -e A --and --not -e B with context' '
1655	test_config color.grep.context		normal &&
1656	test_config color.grep.filename		normal &&
1657	test_config color.grep.function		normal &&
1658	test_config color.grep.linenumber	normal &&
1659	test_config color.grep.matchContext	normal &&
1660	test_config color.grep.matchSelected	red &&
1661	test_config color.grep.selected		normal &&
1662	test_config color.grep.separator	normal &&
1663
1664	git grep --color=always -C2 -e "with " --and --not -e space2  space |
1665	test_decode_color >actual &&
1666	test_cmp expected actual
1667'
1668
1669cat >expected <<EOF
1670hello.c-
1671hello.c=int main(int argc, const char **argv)
1672hello.c-{
1673hello.c:	pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n");
1674hello.c-	return 0;
1675hello.c-	/* char ?? */
1676hello.c-}
1677EOF
1678
1679test_expect_success 'grep --color -e A --and -e B -p with context' '
1680	test_config color.grep.context		normal &&
1681	test_config color.grep.filename		normal &&
1682	test_config color.grep.function		normal &&
1683	test_config color.grep.linenumber	normal &&
1684	test_config color.grep.matchContext	normal &&
1685	test_config color.grep.matchSelected	red &&
1686	test_config color.grep.selected		normal &&
1687	test_config color.grep.separator	normal &&
1688
1689	git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c |
1690	test_decode_color >actual &&
1691	test_cmp expected actual
1692'
1693
1694test_expect_success 'grep can find things only in the work tree' '
1695	: >work-tree-only &&
1696	git add work-tree-only &&
1697	test_when_finished "git rm -f work-tree-only" &&
1698	echo "find in work tree" >work-tree-only &&
1699	git grep --quiet "find in work tree" &&
1700	test_must_fail git grep --quiet --cached "find in work tree" &&
1701	test_must_fail git grep --quiet "find in work tree" HEAD
1702'
1703
1704test_expect_success 'grep can find things only in the work tree (i-t-a)' '
1705	echo "intend to add this" >intend-to-add &&
1706	git add -N intend-to-add &&
1707	test_when_finished "git rm -f intend-to-add" &&
1708	git grep --quiet "intend to add this" &&
1709	test_must_fail git grep --quiet --cached "intend to add this" &&
1710	test_must_fail git grep --quiet "intend to add this" HEAD
1711'
1712
1713test_expect_success 'grep does not search work tree with assume unchanged' '
1714	echo "intend to add this" >intend-to-add &&
1715	git add -N intend-to-add &&
1716	git update-index --assume-unchanged intend-to-add &&
1717	test_when_finished "git rm -f intend-to-add" &&
1718	test_must_fail git grep --quiet "intend to add this" &&
1719	test_must_fail git grep --quiet --cached "intend to add this" &&
1720	test_must_fail git grep --quiet "intend to add this" HEAD
1721'
1722
1723test_expect_success 'grep can find things only in the index' '
1724	echo "only in the index" >cache-this &&
1725	git add cache-this &&
1726	rm cache-this &&
1727	test_when_finished "git rm --cached cache-this" &&
1728	test_must_fail git grep --quiet "only in the index" &&
1729	git grep --quiet --cached "only in the index" &&
1730	test_must_fail git grep --quiet "only in the index" HEAD
1731'
1732
1733test_expect_success 'grep does not report i-t-a with -L --cached' '
1734	echo "intend to add this" >intend-to-add &&
1735	git add -N intend-to-add &&
1736	test_when_finished "git rm -f intend-to-add" &&
1737	git ls-files | grep -v "^intend-to-add\$" >expected &&
1738	git grep -L --cached "nonexistent_string" >actual &&
1739	test_cmp expected actual
1740'
1741
1742test_expect_success 'grep does not report i-t-a and assume unchanged with -L' '
1743	echo "intend to add this" >intend-to-add-assume-unchanged &&
1744	git add -N intend-to-add-assume-unchanged &&
1745	test_when_finished "git rm -f intend-to-add-assume-unchanged" &&
1746	git update-index --assume-unchanged intend-to-add-assume-unchanged &&
1747	git ls-files | grep -v "^intend-to-add-assume-unchanged\$" >expected &&
1748	git grep -L "nonexistent_string" >actual &&
1749	test_cmp expected actual
1750'
1751
1752test_done
1753