git/t/t7810-grep.sh

1896 lines
47 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2006 Junio C Hamano
#
test_description='git grep various.
'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
tests: mark tests relying on the current default for `init.defaultBranch` In addition to the manual adjustment to let the `linux-gcc` CI job run the test suite with `master` and then with `main`, this patch makes sure that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts that currently rely on the initial branch name being `master by default. To determine which test scripts to mark up, the first step was to force-set the default branch name to `master` in - all test scripts that contain the keyword `master`, - t4211, which expects `t/t4211/history.export` with a hard-coded ref to initialize the default branch, - t5560 because it sources `t/t556x_common` which uses `master`, - t8002 and t8012 because both source `t/annotate-tests.sh` which also uses `master`) This trick was performed by this command: $ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' $(git grep -l master t/t[0-9]*.sh) \ t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh After that, careful, manual inspection revealed that some of the test scripts containing the needle `master` do not actually rely on a specific default branch name: either they mention `master` only in a comment, or they initialize that branch specificially, or they do not actually refer to the current default branch. Therefore, the aforementioned modification was undone in those test scripts thusly: $ git checkout HEAD -- \ t/t0027-auto-crlf.sh t/t0060-path-utils.sh \ t/t1011-read-tree-sparse-checkout.sh \ t/t1305-config-include.sh t/t1309-early-config.sh \ t/t1402-check-ref-format.sh t/t1450-fsck.sh \ t/t2024-checkout-dwim.sh \ t/t2106-update-index-assume-unchanged.sh \ t/t3040-subprojects-basic.sh t/t3301-notes.sh \ t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \ t/t3436-rebase-more-options.sh \ t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \ t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \ t/t5511-refspec.sh t/t5526-fetch-submodules.sh \ t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \ t/t5548-push-porcelain.sh \ t/t5552-skipping-fetch-negotiator.sh \ t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \ t/t5614-clone-submodules-shallow.sh \ t/t7508-status.sh t/t7606-merge-custom.sh \ t/t9302-fast-import-unpack-limit.sh We excluded one set of test scripts in these commands, though: the range of `git p4` tests. The reason? `git p4` stores the (foreign) remote branch in the branch called `p4/master`, which is obviously not the default branch. Manual analysis revealed that only five of these tests actually require a specific default branch name to pass; They were modified thusly: $ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' t/t980[0167]*.sh t/t9811*.sh Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-19 07:44:19 +08:00
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_invalid_grep_expression() {
params="$@" &&
test_expect_success "invalid expression: grep $params" '
test_must_fail git grep $params -- nonexisting
'
}
LC_ALL=en_US.UTF-8 test-tool regex '^.$' '¿' &&
test_set_prereq MB_REGEX
cat >hello.c <<EOF
#include <assert.h>
#include <stdio.h>
int main(int argc, const char **argv)
{
printf("Hello world.\n");
return 0;
/* char ?? */
}
EOF
test_expect_success setup '
cat >file <<-\EOF &&
foo mmap bar
foo_mmap bar
foo_mmap bar mmap
foo mmap bar_mmap
foo_mmap bar mmap baz
EOF
cat >hello_world <<-\EOF &&
Hello world
HeLLo world
Hello_world
HeLLo_world
EOF
cat >ab <<-\EOF &&
a+b*c
a+bc
abc
EOF
cat >d0 <<-\EOF &&
d
0
EOF
echo vvv >v &&
echo ww w >w &&
echo x x xx x >x &&
echo y yy >y &&
echo zzz > z &&
mkdir t &&
echo test >t/t &&
echo vvv >t/v &&
mkdir t/a &&
echo vvv >t/a/v &&
qz_to_tab_space >space <<-\EOF &&
line without leading space1
Zline with leading space1
Zline with leading space2
Zline with leading space3
line without leading space2
EOF
cat >hello.ps1 <<-\EOF &&
# No-op.
function dummy() {}
# Say hello.
function hello() {
echo "Hello world."
echo "Hello again."
} # hello
# Still a no-op.
function dummy() {}
EOF
if test_have_prereq FUNNYNAMES
then
echo unusual >"\"unusual\" pathname" &&
echo unusual >"t/nested \"unusual\" pathname"
fi &&
if test_have_prereq MB_REGEX
then
echo "¿" >reverse-question-mark
fi &&
git add . &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_tick &&
git commit -m initial
'
test_expect_success 'grep should not segfault with a bad input' '
test_must_fail git grep "("
'
test_invalid_grep_expression --and -e A
test_pattern_type () {
H=$1 &&
HC=$2 &&
L=$3 &&
type=$4 &&
shift 4 &&
expected_str= &&
case "$type" in
BRE)
expected_str="${HC}ab:a+bc"
;;
ERE)
expected_str="${HC}ab:abc"
;;
FIX)
expected_str="${HC}ab:a+b*c"
;;
*)
BUG "unknown pattern type '$type'"
;;
esac &&
config_str="$@" &&
test_expect_success "grep $L with '$config_str' interpreted as $type" '
echo $expected_str >expected &&
git $config_str grep "a+b*c" $H ab >actual &&
test_cmp expected actual
'
}
for H in HEAD ''
do
case "$H" in
HEAD) HC='HEAD:' L='HEAD' ;;
'') HC= L='in working tree' ;;
esac
test_expect_success "grep -w $L" '
cat >expected <<-EOF &&
${HC}file:1:foo mmap bar
${HC}file:3:foo_mmap bar mmap
${HC}file:4:foo mmap bar_mmap
${HC}file:5:foo_mmap bar mmap baz
EOF
git -c grep.linenumber=false grep -n -w -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with --column)" '
cat >expected <<-EOF &&
${HC}file:5:foo mmap bar
${HC}file:14:foo_mmap bar mmap
${HC}file:5:foo mmap bar_mmap
${HC}file:14:foo_mmap bar mmap baz
EOF
git grep --column -w -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with --column, extended OR)" '
cat >expected <<-EOF &&
${HC}file:14:foo_mmap bar mmap
${HC}file:19:foo_mmap bar mmap baz
EOF
git grep --column -w -e mmap$ --or -e baz $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with --column, --invert-match)" '
cat >expected <<-EOF &&
${HC}file:1:foo mmap bar
${HC}file:1:foo_mmap bar
${HC}file:1:foo_mmap bar mmap
${HC}file:1:foo mmap bar_mmap
EOF
git grep --column --invert-match -w -e baz $H -- file >actual &&
test_cmp expected actual
'
test_expect_success "grep $L (with --column, --invert-match, extended OR)" '
cat >expected <<-EOF &&
${HC}hello_world:6:HeLLo_world
EOF
git grep --column --invert-match -e ll --or --not -e _ $H -- hello_world \
>actual &&
test_cmp expected actual
'
test_expect_success "grep $L (with --column, --invert-match, extended AND)" '
cat >expected <<-EOF &&
${HC}hello_world:3:Hello world
${HC}hello_world:3:Hello_world
${HC}hello_world:6:HeLLo_world
EOF
git grep --column --invert-match --not -e _ --and --not -e ll $H -- hello_world \
>actual &&
test_cmp expected actual
'
test_expect_success "grep $L (with --column, double-negation)" '
cat >expected <<-EOF &&
${HC}file:1:foo_mmap bar mmap baz
EOF
git grep --column --not \( --not -e foo --or --not -e baz \) $H -- file \
>actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with --column, -C)" '
cat >expected <<-EOF &&
${HC}file:5:foo mmap bar
${HC}file-foo_mmap bar
${HC}file:14:foo_mmap bar mmap
${HC}file:5:foo mmap bar_mmap
${HC}file:14:foo_mmap bar mmap baz
EOF
git grep --column -w -C1 -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with --line-number, --column)" '
cat >expected <<-EOF &&
${HC}file:1:5:foo mmap bar
${HC}file:3:14:foo_mmap bar mmap
${HC}file:4:5:foo mmap bar_mmap
${HC}file:5:14:foo_mmap bar mmap baz
EOF
git grep -n --column -w -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (with non-extended patterns, --column)" '
cat >expected <<-EOF &&
${HC}file:5:foo mmap bar
${HC}file:10:foo_mmap bar
${HC}file:10:foo_mmap bar mmap
${HC}file:5:foo mmap bar_mmap
${HC}file:10:foo_mmap bar mmap baz
EOF
git grep --column -w -e bar -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L" '
cat >expected <<-EOF &&
${HC}file:1:foo mmap bar
${HC}file:3:foo_mmap bar mmap
${HC}file:4:foo mmap bar_mmap
${HC}file:5:foo_mmap bar mmap baz
EOF
git -c grep.linenumber=true grep -w -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L" '
cat >expected <<-EOF &&
${HC}file:foo mmap bar
${HC}file:foo_mmap bar mmap
${HC}file:foo mmap bar_mmap
${HC}file:foo_mmap bar mmap baz
EOF
git -c grep.linenumber=true grep --no-line-number -w -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (w)" '
test_must_fail git grep -n -w -e "^w" $H >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success "grep -w $L (x)" '
cat >expected <<-EOF &&
${HC}x:1:x x xx x
EOF
git grep -n -w -e "x xx* x" $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (y-1)" '
cat >expected <<-EOF &&
${HC}y:1:y yy
EOF
git grep -n -w -e "^y" $H >actual &&
test_cmp expected actual
'
test_expect_success "grep -w $L (y-2)" '
if git grep -n -w -e "^y y" $H >actual
then
echo should not have matched
cat actual
false
else
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
fi
'
test_expect_success "grep -w $L (z)" '
if git grep -n -w -e "^z" $H >actual
then
echo should not have matched
cat actual
false
else
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
fi
'
test_expect_success "grep $L (with --column, --only-matching)" '
cat >expected <<-EOF &&
${HC}file:1:5:mmap
${HC}file:2:5:mmap
${HC}file:3:5:mmap
${HC}file:3:13:mmap
${HC}file:4:5:mmap
${HC}file:4:13:mmap
${HC}file:5:5:mmap
${HC}file:5:13:mmap
EOF
git grep --column -n -o -e mmap $H >actual &&
test_cmp expected actual
'
test_expect_success "grep $L (t-1)" '
echo "${HC}t/t:1:test" >expected &&
git grep -n -e test $H >actual &&
test_cmp expected actual
'
test_expect_success "grep $L (t-2)" '
echo "${HC}t:1:test" >expected &&
(
cd t &&
git grep -n -e test $H
) >actual &&
test_cmp expected actual
'
test_expect_success "grep $L (t-3)" '
echo "${HC}t/t:1:test" >expected &&
(
cd t &&
git grep --full-name -n -e test $H
) >actual &&
test_cmp expected actual
'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 17:50:53 +08:00
test_expect_success "grep -c $L (no /dev/null)" '
! git grep -c test $H | grep /dev/null
'
test_expect_success "grep --max-depth -1 $L" '
cat >expected <<-EOF &&
${HC}t/a/v:1:vvv
${HC}t/v:1:vvv
${HC}v:1:vvv
EOF
git grep --max-depth -1 -n -e vvv $H >actual &&
test_cmp expected actual &&
git grep --recursive -n -e vvv $H >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 0 $L" '
cat >expected <<-EOF &&
${HC}v:1:vvv
EOF
git grep --max-depth 0 -n -e vvv $H >actual &&
test_cmp expected actual &&
git grep --no-recursive -n -e vvv $H >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 0 -- '*' $L" '
cat >expected <<-EOF &&
${HC}t/a/v:1:vvv
${HC}t/v:1:vvv
${HC}v:1:vvv
EOF
git grep --max-depth 0 -n -e vvv $H -- "*" >actual &&
test_cmp expected actual &&
git grep --no-recursive -n -e vvv $H -- "*" >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 1 $L" '
cat >expected <<-EOF &&
${HC}t/v:1:vvv
${HC}v:1:vvv
EOF
git grep --max-depth 1 -n -e vvv $H >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 0 -- t $L" '
cat >expected <<-EOF &&
${HC}t/v:1:vvv
EOF
git grep --max-depth 0 -n -e vvv $H -- t >actual &&
test_cmp expected actual &&
git grep --no-recursive -n -e vvv $H -- t >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 0 -- . t $L" '
cat >expected <<-EOF &&
${HC}t/v:1:vvv
${HC}v:1:vvv
EOF
git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
test_cmp expected actual &&
git grep --no-recursive -n -e vvv $H -- . t >actual &&
test_cmp expected actual
'
test_expect_success "grep --max-depth 0 -- t . $L" '
cat >expected <<-EOF &&
${HC}t/v:1:vvv
${HC}v:1:vvv
EOF
git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
test_cmp expected actual &&
git grep --no-recursive -n -e vvv $H -- t . >actual &&
test_cmp expected actual
'
test_pattern_type "$H" "$HC" "$L" BRE -c grep.extendedRegexp=false
test_pattern_type "$H" "$HC" "$L" ERE -c grep.extendedRegexp=true
test_pattern_type "$H" "$HC" "$L" BRE -c grep.patternType=basic
test_pattern_type "$H" "$HC" "$L" ERE -c grep.patternType=extended
test_pattern_type "$H" "$HC" "$L" FIX -c grep.patternType=fixed
test_expect_success PCRE "grep $L with grep.patterntype=perl" '
echo "${HC}ab:a+b*c" >expected &&
git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" $H ab >actual &&
test_cmp expected actual
'
test_expect_success !FAIL_PREREQS,!PCRE "grep $L with grep.patterntype=perl errors without PCRE" '
test_must_fail git -c grep.patterntype=perl grep "foo.*bar"
'
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.patternType=default \
-c grep.extendedRegexp=true
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.extendedRegexp=true \
-c grep.patternType=default
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.patternType=extended \
-c grep.extendedRegexp=false
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.patternType=basic \
-c grep.extendedRegexp=true
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.extendedRegexp=false \
-c grep.patternType=extended
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.extendedRegexp=true \
-c grep.patternType=basic
# grep.extendedRegexp is last-one-wins
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.extendedRegexp=true \
-c grep.extendedRegexp=false
# grep.patternType=basic pays no attention to grep.extendedRegexp
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.extendedRegexp=true \
-c grep.patternType=basic \
-c grep.extendedRegexp=false
# grep.patternType=extended pays no attention to grep.extendedRegexp
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.extendedRegexp=true \
-c grep.patternType=extended \
-c grep.extendedRegexp=false
# grep.extendedRegexp is used with a last-one-wins grep.patternType=default
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.patternType=fixed \
-c grep.extendedRegexp=true \
-c grep.patternType=default
# grep.extendedRegexp is used with earlier grep.patternType=default
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.extendedRegexp=false \
-c grep.patternType=default \
-c grep.extendedRegexp=true
# grep.extendedRegexp is used with a last-one-loses grep.patternType=default
test_pattern_type "$H" "$HC" "$L" ERE \
-c grep.extendedRegexp=false \
-c grep.extendedRegexp=true \
-c grep.patternType=default
# grep.extendedRegexp and grep.patternType are both last-one-wins independently
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.patternType=default \
-c grep.extendedRegexp=true \
-c grep.patternType=basic
# grep.patternType=extended and grep.patternType=default
test_pattern_type "$H" "$HC" "$L" BRE \
-c grep.patternType=extended \
-c grep.patternType=default
# grep.patternType=[extended -> default -> fixed] (BRE)" '
test_pattern_type "$H" "$HC" "$L" FIX \
-c grep.patternType=extended \
-c grep.patternType=default \
-c grep.patternType=fixed
test_expect_success "grep --count $L" '
echo ${HC}ab:3 >expected &&
git grep --count -e b $H -- ab >actual &&
test_cmp expected actual
'
test_expect_success "grep --count -h $L" '
echo 3 >expected &&
git grep --count -h -e b $H -- ab >actual &&
test_cmp expected actual
'
test_expect_success FUNNYNAMES "grep $L should quote unusual pathnames" '
cat >expected <<-EOF &&
${HC}"\"unusual\" pathname":unusual
${HC}"t/nested \"unusual\" pathname":unusual
EOF
git grep unusual $H >actual &&
test_cmp expected actual
'
test_expect_success FUNNYNAMES "grep $L in subdir should quote unusual relative pathnames" '
cat >expected <<-EOF &&
${HC}"nested \"unusual\" pathname":unusual
EOF
(
cd t &&
git grep unusual $H
) >actual &&
test_cmp expected actual
'
test_expect_success FUNNYNAMES "grep -z $L with unusual pathnames" '
cat >expected <<-EOF &&
${HC}"unusual" pathname:unusual
${HC}t/nested "unusual" pathname:unusual
EOF
git grep -z unusual $H >actual &&
tr "\0" ":" <actual >actual-replace-null &&
test_cmp expected actual-replace-null
'
test_expect_success FUNNYNAMES "grep -z $L in subdir with unusual relative pathnames" '
cat >expected <<-EOF &&
${HC}nested "unusual" pathname:unusual
EOF
(
cd t &&
git grep -z unusual $H
) >actual &&
tr "\0" ":" <actual >actual-replace-null &&
test_cmp expected actual-replace-null
'
done
test_expect_success MB_REGEX 'grep exactly one char in single-char multibyte file' '
LC_ALL=en_US.UTF-8 git grep "^.$" reverse-question-mark
'
test_expect_success MB_REGEX 'grep two chars in single-char multibyte file' '
LC_ALL=en_US.UTF-8 test_expect_code 1 git grep ".." reverse-question-mark
'
cat >expected <<EOF
file
EOF
test_expect_success 'grep -l -C' '
git grep -l -C1 foo >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:5
EOF
test_expect_success 'grep -c -C' '
git grep -c -C1 foo >actual &&
test_cmp expected actual
'
test_expect_success 'grep -L -C' '
git ls-files >expected &&
git grep -L -C1 nonexistent_string >actual &&
test_cmp expected actual
'
test_expect_success 'grep --files-without-match --quiet' '
git grep --files-without-match --quiet nonexistent_string >actual &&
test_must_be_empty actual
'
test_expect_success 'grep --max-count 0 (must exit with non-zero)' '
test_must_fail git grep --max-count 0 foo >actual &&
test_must_be_empty actual
'
test_expect_success 'grep --max-count 3' '
cat >expected <<-EOF &&
file:foo mmap bar
file:foo_mmap bar
file:foo_mmap bar mmap
EOF
git grep --max-count 3 foo >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count -1 (no limit)' '
cat >expected <<-EOF &&
file:foo mmap bar
file:foo_mmap bar
file:foo_mmap bar mmap
file:foo mmap bar_mmap
file:foo_mmap bar mmap baz
EOF
git grep --max-count -1 foo >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 1 --context 2' '
cat >expected <<-EOF &&
file-foo mmap bar
file:foo_mmap bar
file-foo_mmap bar mmap
EOF
git grep --max-count 1 --context 1 foo_mmap >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 1 --show-function' '
cat >expected <<-EOF &&
hello.ps1=function hello() {
hello.ps1: echo "Hello world."
EOF
git grep --max-count 1 --show-function Hello hello.ps1 >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 2 --show-function' '
cat >expected <<-EOF &&
hello.ps1=function hello() {
hello.ps1: echo "Hello world."
hello.ps1: echo "Hello again."
EOF
git grep --max-count 2 --show-function Hello hello.ps1 >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 1 --count' '
cat >expected <<-EOF &&
hello.ps1:1
EOF
git grep --max-count 1 --count Hello hello.ps1 >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 1 (multiple files)' '
cat >expected <<-EOF &&
hello.c:#include <stdio.h>
hello.ps1:# No-op.
EOF
git grep --max-count 1 -e o -- hello.\* >actual &&
test_cmp expected actual
'
test_expect_success 'grep --max-count 1 --context 1 (multiple files)' '
cat >expected <<-EOF &&
hello.c-#include <assert.h>
hello.c:#include <stdio.h>
hello.c-
--
hello.ps1:# No-op.
hello.ps1-function dummy() {}
EOF
git grep --max-count 1 --context 1 -e o -- hello.\* >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:foo mmap bar_mmap
EOF
test_expect_success 'grep -e A --and -e B' '
git grep -e "foo mmap" --and -e bar_mmap >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:foo_mmap bar mmap
file:foo_mmap bar mmap baz
EOF
test_expect_success 'grep ( -e A --or -e B ) --and -e B' '
git grep \( -e foo_ --or -e baz \) \
--and -e " mmap" >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:foo mmap bar
EOF
test_expect_success 'grep -e A --and --not -e B' '
git grep -e "foo mmap" --and --not -e bar_mmap >actual &&
test_cmp expected actual
'
test_expect_success 'grep should ignore GREP_OPTIONS' '
GREP_OPTIONS=-v git grep " mmap bar\$" >actual &&
test_cmp expected actual
'
test_expect_success 'grep -f, non-existent file' '
test_must_fail git grep -f patterns
'
cat >expected <<EOF
file:foo mmap bar
file:foo_mmap bar
file:foo_mmap bar mmap
file:foo mmap bar_mmap
file:foo_mmap bar mmap baz
EOF
cat >pattern <<EOF
mmap
EOF
test_expect_success 'grep -f, one pattern' '
git grep -f pattern >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:foo mmap bar
file:foo_mmap bar
file:foo_mmap bar mmap
file:foo mmap bar_mmap
file:foo_mmap bar mmap baz
t/a/v:vvv
t/v:vvv
v:vvv
EOF
cat >patterns <<EOF
mmap
vvv
EOF
test_expect_success 'grep -f, multiple patterns' '
git grep -f patterns >actual &&
test_cmp expected actual
'
test_expect_success 'grep, multiple patterns' '
git grep "$(cat patterns)" >actual &&
test_cmp expected actual
'
cat >expected <<EOF
file:foo mmap bar
file:foo_mmap bar
file:foo_mmap bar mmap
file:foo mmap bar_mmap
file:foo_mmap bar mmap baz
t/a/v:vvv
t/v:vvv
v:vvv
EOF
cat >patterns <<EOF
mmap
vvv
EOF
test_expect_success 'grep -f, ignore empty lines' '
git grep -f patterns >actual &&
test_cmp expected actual
'
test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
git grep -f - <patterns >actual &&
test_cmp expected actual
'
test_expect_success 'grep -f, use cwd relative file' '
test_when_finished "git rm -f sub/dir/file" &&
mkdir -p sub/dir &&
echo hit >sub/dir/file &&
git add sub/dir/file &&
echo hit >sub/dir/pattern &&
echo miss >pattern &&
(
cd sub/dir && git grep -f pattern file
) &&
git -C sub/dir grep -f pattern file
'
cat >expected <<EOF
y:y yy
--
z:zzz
EOF
test_expect_success 'grep -q, silently report matches' '
git grep -q mmap >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual &&
test_must_fail git grep -q qfwfq >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success 'grep -C1 hunk mark between files' '
git grep -C1 "^[yz]" >actual &&
test_cmp expected actual
'
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_expect_success 'log grep setup' '
test_commit --append --author "With * Asterisk <xyzzy@frotz.com>" second file a &&
test_commit --append third file a &&
test_commit --append --author "Night Fall <nitfol@frobozz.com>" fourth file a
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
'
test_expect_success 'log grep (1)' '
git log --author=author --pretty=tformat:%s >actual &&
{
echo third && echo initial
} >expect &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_cmp expect actual
'
test_expect_success 'log grep (2)' '
git log --author=" * " -F --pretty=tformat:%s >actual &&
{
echo second
} >expect &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_cmp expect actual
'
test_expect_success 'log grep (3)' '
git log --author="^A U" --pretty=tformat:%s >actual &&
{
echo third && echo initial
} >expect &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_cmp expect actual
'
test_expect_success 'log grep (4)' '
git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
{
echo second
} >expect &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_cmp expect actual
'
test_expect_success 'log grep (5)' '
git log --author=Thor -F --pretty=tformat:%s >actual &&
{
echo third && echo initial
} >expect &&
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_cmp expect actual
'
test_expect_success 'log grep (6)' '
git log --author=-0700 --pretty=tformat:%s >actual &&
test_must_be_empty actual
'
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
test_expect_success 'log grep (7)' '
git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual &&
echo third >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (8)' '
git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual &&
{
echo third && echo second
} >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (9)' '
git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual &&
echo third >expect &&
test_cmp expect actual
'
test_expect_success 'log grep (9)' '
git log -g --grep-reflog="commit: third" --author="non-existent" --pretty=tformat:%s >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success 'log --grep-reflog can only be used under -g' '
test_must_fail git log --grep-reflog="commit: third"
'
test_expect_success 'log with multiple --grep uses union' '
git log --grep=i --grep=r --format=%s >actual &&
{
echo fourth && echo third && echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --all-match with multiple --grep uses intersection' '
git log --all-match --grep=i --grep=r --format=%s >actual &&
{
echo third
} >expect &&
test_cmp expect actual
'
test_expect_success 'log with multiple --author uses union' '
git log --author="Thor" --author="Aster" --format=%s >actual &&
{
echo third && echo second && echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --all-match with multiple --author still uses union' '
git log --all-match --author="Thor" --author="Aster" --format=%s >actual &&
{
echo third && echo second && echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --grep --author uses intersection' '
# grep matches only third and fourth
# author matches only initial and third
git log --author="A U Thor" --grep=r --format=%s >actual &&
{
echo third
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' '
# grep matches initial and second but not third
# author matches only initial and third
git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
{
echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' '
# grep matches only initial and third
# author matches all but second
git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&
{
echo third && echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --grep --author --author takes union of authors and intersects with grep' '
# grep matches only initial and third
# author matches all but second
git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
{
echo third && echo initial
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --all-match --grep --grep --author takes intersection' '
# grep matches only third
# author matches only initial and third
git log --all-match --author="A U Thor" --grep=i --grep=r --format=%s >actual &&
{
echo third
} >expect &&
test_cmp expect actual
'
test_expect_success 'log --author does not search in timestamp' '
git log --author="$GIT_AUTHOR_DATE" >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success 'log --committer does not search in timestamp' '
git log --committer="$GIT_COMMITTER_DATE" >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success 'grep with CE_VALID file' '
git update-index --assume-unchanged t/t &&
rm t/t &&
echo "t/t:test" >expect &&
git grep test >actual &&
test_cmp expect actual &&
git update-index --no-assume-unchanged t/t &&
git checkout t/t
log --author/--committer: really match only with name part When we tried to find commits done by AUTHOR, the first implementation tried to pattern match a line with "^author .*AUTHOR", which later was enhanced to strip leading caret and look for "^author AUTHOR" when the search pattern was anchored at the left end (i.e. --author="^AUTHOR"). This had a few problems: * When looking for fixed strings (e.g. "git log -F --author=x --grep=y"), the regexp internally used "^author .*x" would never match anything; * To match at the end (e.g. "git log --author='google.com>$'"), the generated regexp has to also match the trailing timestamp part the commit header lines have. Also, in order to determine if the '$' at the end means "match at the end of the line" or just a literal dollar sign (probably backslash-quoted), we would need to parse the regexp ourselves. An earlier alternative tried to make sure that a line matches "^author " (to limit by field name) and the user supplied pattern at the same time. While it solved the -F problem by introducing a special override for matching the "^author ", it did not solve the trailing timestamp nor tail match problem. It also would have matched every commit if --author=author was asked for, not because the author's email part had this string, but because every commit header line that talks about the author begins with that field name, regardleses of who wrote it. Instead of piling more hacks on top of hacks, this rethinks the grep machinery that is used to look for strings in the commit header, and makes sure that (1) field name matches literally at the beginning of the line, followed by a SP, and (2) the user supplied pattern is matched against the remainder of the line, excluding the trailing timestamp data. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 13:15:02 +08:00
'
cat >expected <<EOF
hello.c=#include <stdio.h>
hello.c: return 0;
EOF
test_expect_success 'grep -p with userdiff' '
git config diff.custom.funcname "^#" &&
echo "hello.c diff=custom" >.gitattributes &&
git grep -p return >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c=int main(int argc, const char **argv)
hello.c: return 0;
EOF
test_expect_success 'grep -p' '
rm -f .gitattributes &&
git grep -p return >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c-#include <stdio.h>
hello.c-
hello.c=int main(int argc, const char **argv)
hello.c-{
hello.c- printf("Hello world.\n");
hello.c: return 0;
EOF
test_expect_success 'grep -p -B5' '
git grep -p -B5 return >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c=int main(int argc, const char **argv)
hello.c-{
hello.c- printf("Hello world.\n");
hello.c: return 0;
hello.c- /* char ?? */
hello.c-}
EOF
test_expect_success 'grep -W' '
git grep -W return >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c-#include <assert.h>
hello.c:#include <stdio.h>
EOF
test_expect_success 'grep -W shows no trailing empty lines' '
git grep -W stdio >actual &&
test_cmp expected actual
'
test_expect_success 'grep -W with userdiff' '
test_when_finished "rm -f .gitattributes" &&
git config diff.custom.xfuncname "^function .*$" &&
echo "hello.ps1 diff=custom" >.gitattributes &&
git grep -W echo >function-context-userdiff-actual
'
test_expect_success ' includes preceding comment' '
grep "# Say hello" function-context-userdiff-actual
'
test_expect_success ' includes function line' '
grep "=function hello" function-context-userdiff-actual
'
test_expect_success ' includes matching line' '
grep ": echo" function-context-userdiff-actual
'
test_expect_success ' includes last line of the function' '
grep "} # hello" function-context-userdiff-actual
'
for threads in $(test_seq 0 10)
do
test_expect_success "grep --threads=$threads & -c grep.threads=$threads" "
git grep --threads=$threads . >actual.$threads &&
if test $threads -ge 1
then
test_cmp actual.\$(($threads - 1)) actual.$threads
fi &&
git -c grep.threads=$threads grep . >actual.$threads &&
if test $threads -ge 1
then
test_cmp actual.\$(($threads - 1)) actual.$threads
fi
"
done
test_expect_success !PTHREADS,!FAIL_PREREQS \
'grep --threads=N or pack.threads=N warns when no pthreads' '
git grep --threads=2 Hello hello_world 2>err &&
grep ^warning: err >warnings &&
test_line_count = 1 warnings &&
grep -F "no threads support, ignoring --threads" err &&
git -c grep.threads=2 grep Hello hello_world 2>err &&
grep ^warning: err >warnings &&
test_line_count = 1 warnings &&
grep -F "no threads support, ignoring grep.threads" err &&
git -c grep.threads=2 grep --threads=4 Hello hello_world 2>err &&
grep ^warning: err >warnings &&
test_line_count = 2 warnings &&
grep -F "no threads support, ignoring --threads" err &&
grep -F "no threads support, ignoring grep.threads" err &&
git -c grep.threads=0 grep --threads=0 Hello hello_world 2>err &&
test_line_count = 0 err
'
test_expect_success 'grep from a subdirectory to search wider area (1)' '
mkdir -p s &&
(
cd s && git grep "x x x" ..
)
'
test_expect_success 'grep from a subdirectory to search wider area (2)' '
mkdir -p s &&
(
cd s &&
test_expect_code 1 git grep xxyyzz .. >out &&
test_must_be_empty out
)
'
cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
EOF
test_expect_success 'grep -Fi' '
git grep -Fi "CHAR *" >actual &&
test_cmp expected actual
'
test_expect_success 'outside of git repository' '
rm -fr non &&
mkdir -p non/git/sub &&
echo hello >non/git/file1 &&
echo world >non/git/sub/file2 &&
{
echo file1:hello &&
echo sub/file2:world
} >non/expect.full &&
echo file2:world >non/expect.sub &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
test_must_fail git grep o &&
git grep --no-index o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
cd sub &&
test_must_fail git grep o &&
git grep --no-index o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub
) &&
echo ".*o*" >non/git/.gitignore &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
test_must_fail git grep o &&
git grep --no-index --exclude-standard o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
{
echo ".gitignore:.*o*" &&
cat ../expect.full
} >../expect.with.ignored &&
git grep --no-index --no-exclude-standard o >../actual.full &&
test_cmp ../expect.with.ignored ../actual.full
)
'
test_expect_success 'outside of git repository with fallbackToNoIndex' '
rm -fr non &&
mkdir -p non/git/sub &&
echo hello >non/git/file1 &&
echo world >non/git/sub/file2 &&
cat <<-\EOF >non/expect.full &&
file1:hello
sub/file2:world
EOF
echo file2:world >non/expect.sub &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
git -c grep.fallbackToNoIndex=true grep o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
cd sub &&
test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
git -c grep.fallbackToNoIndex=true grep o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub
) &&
echo ".*o*" >non/git/.gitignore &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
test_must_fail git -c grep.fallbackToNoIndex=false grep o &&
git -c grep.fallbackToNoIndex=true grep --exclude-standard o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
{
echo ".gitignore:.*o*" &&
cat ../expect.full
} >../expect.with.ignored &&
git -c grep.fallbackToNoIndex grep --no-exclude-standard o >../actual.full &&
test_cmp ../expect.with.ignored ../actual.full
)
'
test_expect_success 'inside git repository but with --no-index' '
rm -fr is &&
mkdir -p is/git/sub &&
echo hello >is/git/file1 &&
echo world >is/git/sub/file2 &&
echo ".*o*" >is/git/.gitignore &&
{
echo file1:hello &&
echo sub/file2:world
} >is/expect.unignored &&
{
echo ".gitignore:.*o*" &&
cat is/expect.unignored
} >is/expect.full &&
echo file2:world >is/expect.sub &&
(
cd is/git &&
git init &&
test_must_fail git grep o >../actual.full &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty ../actual.full &&
git grep --untracked o >../actual.unignored &&
test_cmp ../expect.unignored ../actual.unignored &&
git grep --no-index o >../actual.full &&
test_cmp ../expect.full ../actual.full &&
git grep --no-index --exclude-standard o >../actual.unignored &&
test_cmp ../expect.unignored ../actual.unignored &&
cd sub &&
test_must_fail git grep o >../../actual.sub &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty ../../actual.sub &&
git grep --no-index o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub &&
git grep --untracked o >../../actual.sub &&
test_cmp ../../expect.sub ../../actual.sub
)
'
test_expect_success 'grep --no-index descends into repos, but not .git' '
rm -fr non &&
mkdir -p non/git &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
echo magic >file &&
git init repo &&
(
cd repo &&
echo magic >file &&
git add file &&
git commit -m foo &&
echo magic >.git/file
) &&
cat >expect <<-\EOF &&
file
repo/file
EOF
git grep -l --no-index magic >actual &&
test_cmp expect actual
)
'
test_expect_success 'setup double-dash tests' '
cat >double-dash <<EOF &&
--
->
other
EOF
git add double-dash
'
cat >expected <<EOF
double-dash:->
EOF
test_expect_success 'grep -- pattern' '
git grep -- "->" >actual &&
test_cmp expected actual
'
test_expect_success 'grep -- pattern -- pathspec' '
git grep -- "->" -- double-dash >actual &&
test_cmp expected actual
'
test_expect_success 'grep -e pattern -- path' '
git grep -e "->" -- double-dash >actual &&
test_cmp expected actual
'
cat >expected <<EOF
double-dash:--
EOF
test_expect_success 'grep -e -- -- path' '
git grep -e -- -- double-dash >actual &&
test_cmp expected actual
'
test_expect_success 'dashdash disambiguates rev as rev' '
test_when_finished "rm -f main" &&
echo content >main &&
echo main:hello.c >expect &&
git grep -l o main -- hello.c >actual &&
test_cmp expect actual
'
test_expect_success 'dashdash disambiguates pathspec as pathspec' '
test_when_finished "git rm -f main" &&
echo content >main &&
git add main &&
echo main:content >expect &&
git grep o -- main >actual &&
test_cmp expect actual
'
test_expect_success 'report bogus arg without dashdash' '
test_must_fail git grep o does-not-exist
'
test_expect_success 'report bogus rev with dashdash' '
test_must_fail git grep o hello.c --
'
test_expect_success 'allow non-existent path with dashdash' '
# We need a real match so grep exits with success.
tree=$(git ls-tree HEAD |
sed s/hello.c/not-in-working-tree/ |
git mktree) &&
git grep o "$tree" -- not-in-working-tree
'
test_expect_success 'grep --no-index pattern -- path' '
rm -fr non &&
mkdir -p non/git &&
(
GIT_CEILING_DIRECTORIES="$(pwd)/non" &&
export GIT_CEILING_DIRECTORIES &&
cd non/git &&
echo hello >hello &&
echo goodbye >goodbye &&
echo hello:hello >expect &&
git grep --no-index o -- hello >actual &&
test_cmp expect actual
)
'
test_expect_success 'grep --no-index complains of revs' '
test_must_fail git grep --no-index o main -- 2>err &&
test_i18ngrep "cannot be used with revs" err
'
test_expect_success 'grep --no-index prefers paths to revs' '
test_when_finished "rm -f main" &&
echo content >main &&
echo main:content >expect &&
git grep --no-index o main >actual &&
test_cmp expect actual
'
test_expect_success 'grep --no-index does not "diagnose" revs' '
test_must_fail git grep --no-index o :1:hello.c 2>err &&
test_i18ngrep ! -i "did you mean" err
'
cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c: printf("Hello world.\n");
EOF
test_expect_success PCRE 'grep --perl-regexp pattern' '
git grep --perl-regexp "\p{Ps}.*?\p{Pe}" hello.c >actual &&
test_cmp expected actual
'
test_expect_success !FAIL_PREREQS,!PCRE 'grep --perl-regexp pattern errors without PCRE' '
test_must_fail git grep --perl-regexp "foo.*bar"
'
test_expect_success PCRE 'grep -P pattern' '
git grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
test_cmp expected actual
'
grep: fix segfault under -P + PCRE2 <=10.30 + (*NO_JIT) Fix a bug in the compilation of PCRE2 patterns under JIT (the most common runtime configuration). Any pattern with a (*NO_JIT) verb would segfault in any currently released PCRE2 version: $ git grep -P '(*NO_JIT)hi.*there' Segmentation fault That this segfaulted was a bug in PCRE2 itself, after reporting it[1] on pcre-dev it's been fixed in a yet-to-be-released version of PCRE (presumably released first as 10.31). Now it'll die with: $ git grep -P '(*NO_JIT)hi.*there' fatal: pcre2_jit_match failed with error code -45: bad JIT option But the cause of the bug is in our own code dating back to my 94da9193a6 ("grep: add support for PCRE v2", 2017-06-01). As explained at more length in the comment being added here, it isn't sufficient to just check pcre2_config() to see whether the JIT should be used, pcre2_pattern_info() also has to be asked. This is something I discovered myself when fiddling around with PCRE2 verbs in patterns passed to git. I don't expect that any user of git has encountered this given the obscurity of passing PCRE2 verbs through to the library, along with the relative obscurity of (*NO_JIT) itself. 1. "How am I supposed to use PCRE2 JIT in the face of (*NO_JIT) ?" (<CACBZZX5mMqDuWuFmi7sRBp3wH6CFyd-ghACukd=v0NN=rBMnJg@mail.gmail.com> & https://lists.exim.org/lurker/thread/20171123.101502.7f0d38ca.en.html) on the pcre-dev mailing list Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-11-23 22:16:58 +08:00
test_expect_success LIBPCRE2 "grep -P with (*NO_JIT) doesn't error out" '
git grep -P "(*NO_JIT)\p{Ps}.*?\p{Pe}" hello.c >actual &&
test_cmp expected actual
'
test_expect_success !FAIL_PREREQS,!PCRE 'grep -P pattern errors without PCRE' '
test_must_fail git grep -P "foo.*bar"
'
test_expect_success 'grep pattern with grep.extendedRegexp=true' '
test_must_fail git -c grep.extendedregexp=true \
grep "\p{Ps}.*?\p{Pe}" hello.c >actual &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-20 05:57:25 +08:00
test_must_be_empty actual
'
test_expect_success PCRE 'grep -P pattern with grep.extendedRegexp=true' '
git -c grep.extendedregexp=true \
grep -P "\p{Ps}.*?\p{Pe}" hello.c >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P -v pattern' '
cat >expected <<-\EOF &&
ab:a+b*c
ab:a+bc
EOF
git grep -P -v "abc" ab >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P -i pattern' '
cat >expected <<-EOF &&
hello.c: printf("Hello world.\n");
EOF
git grep -P -i "PRINTF\([^\d]+\)" hello.c >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P -w pattern' '
cat >expected <<-\EOF &&
hello_world:Hello world
hello_world:HeLLo world
EOF
git grep -P -w "He((?i)ll)o" hello_world >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P backreferences work (the PCRE NO_AUTO_CAPTURE flag is not set)' '
git grep -P -h "(?P<one>.)(?P=one)" hello_world >actual &&
test_cmp hello_world actual &&
git grep -P -h "(.)\1" hello_world >actual &&
test_cmp hello_world actual
'
test_expect_success 'grep -G invalidpattern properly dies ' '
test_must_fail git grep -G "a["
'
test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
test_must_fail git -c grep.patterntype=basic grep "a["
'
test_expect_success 'grep -E invalidpattern properly dies ' '
test_must_fail git grep -E "a["
'
test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
test_must_fail git -c grep.patterntype=extended grep "a["
'
test_expect_success PCRE 'grep -P invalidpattern properly dies ' '
test_must_fail git grep -P "a["
'
test_expect_success PCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
test_must_fail git -c grep.patterntype=perl grep "a["
'
test_expect_success 'grep -G -E -F pattern' '
echo "ab:a+b*c" >expected &&
git grep -G -E -F "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
echo "ab:a+b*c" >expected &&
git \
-c grep.patterntype=basic \
-c grep.patterntype=extended \
-c grep.patterntype=fixed \
grep "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -E -F -G pattern' '
echo "ab:a+bc" >expected &&
git grep -E -F -G "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
echo "ab:a+bc" >expected &&
git \
-c grep.patterntype=extended \
-c grep.patterntype=fixed \
-c grep.patterntype=basic \
grep "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -F -G -E pattern' '
echo "ab:abc" >expected &&
git grep -F -G -E "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
echo "ab:abc" >expected &&
git \
-c grep.patterntype=fixed \
-c grep.patterntype=basic \
-c grep.patterntype=extended \
grep "a+b*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -G -F -P -E pattern' '
echo "d0:d" >expected &&
git grep -G -F -P -E "[\d]" d0 >actual &&
test_cmp expected actual
'
test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
echo "d0:d" >expected &&
git \
-c grep.patterntype=fixed \
-c grep.patterntype=basic \
-c grep.patterntype=perl \
-c grep.patterntype=extended \
grep "[\d]" d0 >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -G -F -E -P pattern' '
echo "d0:0" >expected &&
git grep -G -F -E -P "[\d]" d0 >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
echo "d0:0" >expected &&
git \
-c grep.patterntype=fixed \
-c grep.patterntype=basic \
-c grep.patterntype=extended \
-c grep.patterntype=perl \
grep "[\d]" d0 >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P pattern with grep.patternType=fixed' '
echo "ab:a+b*c" >expected &&
git \
-c grep.patterntype=fixed \
grep -P "a\x{2b}b\x{2a}c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -F pattern with grep.patternType=basic' '
echo "ab:a+b*c" >expected &&
git \
-c grep.patterntype=basic \
grep -F "*c" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -G pattern with grep.patternType=fixed' '
cat >expected <<-\EOF &&
ab:a+b*c
ab:a+bc
EOF
git \
-c grep.patterntype=fixed \
grep -G "a+b" ab >actual &&
test_cmp expected actual
'
test_expect_success 'grep -E pattern with grep.patternType=fixed' '
cat >expected <<-\EOF &&
ab:a+b*c
ab:a+bc
ab:abc
EOF
git \
-c grep.patterntype=fixed \
grep -E "a+" ab >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c<RED>:<RESET>int main(int argc, const char **argv)
hello.c<RED>-<RESET>{
<RED>--<RESET>
hello.c<RED>:<RESET> /* char ?? */
hello.c<RED>-<RESET>}
<RED>--<RESET>
hello_world<RED>:<RESET>Hello_world
hello_world<RED>-<RESET>HeLLo_world
EOF
test_expect_success 'grep --color, separator' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.match normal &&
test_config color.grep.selected normal &&
test_config color.grep.separator red &&
git grep --color=always -A1 -e char -e lo_w hello.c hello_world |
test_decode_color >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c: /* char ?? */
hello_world:Hello_world
EOF
test_expect_success 'grep --break' '
git grep --break -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c:int main(int argc, const char **argv)
hello.c-{
--
hello.c: /* char ?? */
hello.c-}
hello_world:Hello_world
hello_world-HeLLo_world
EOF
test_expect_success 'grep --break with context' '
git grep --break -A1 -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c
int main(int argc, const char **argv)
/* char ?? */
hello_world
Hello_world
EOF
test_expect_success 'grep --heading' '
git grep --heading -e char -e lo_w hello.c hello_world >actual &&
test_cmp expected actual
'
cat >expected <<EOF
<BOLD;GREEN>hello.c<RESET>
4:int main(int argc, const <BLACK;BYELLOW>char<RESET> **argv)
8: /* <BLACK;BYELLOW>char<RESET> ?? */
<BOLD;GREEN>hello_world<RESET>
3:Hel<BLACK;BYELLOW>lo_w<RESET>orld
EOF
test_expect_success 'mimic ack-grep --group' '
test_config color.grep.context normal &&
test_config color.grep.filename "bold green" &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.match "black yellow" &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&
git grep --break --heading -n --color \
-e char -e lo_w hello.c hello_world |
test_decode_color >actual &&
test_cmp expected actual
'
cat >expected <<EOF
space: line with leading space1
space: line with leading space2
space: line with leading space3
EOF
test_expect_success PCRE 'grep -E "^ "' '
git grep -E "^ " space >actual &&
test_cmp expected actual
'
test_expect_success PCRE 'grep -P "^ "' '
git grep -P "^ " space >actual &&
test_cmp expected actual
'
cat >expected <<EOF
space-line without leading space1
space: line <RED>with <RESET>leading space1
space: line <RED>with <RESET>leading <RED>space2<RESET>
space: line <RED>with <RESET>leading space3
space:line without leading <RED>space2<RESET>
EOF
test_expect_success 'grep --color -e A -e B with context' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.matchContext normal &&
test_config color.grep.matchSelected red &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&
git grep --color=always -C2 -e "with " -e space2 space |
test_decode_color >actual &&
test_cmp expected actual
'
cat >expected <<EOF
space-line without leading space1
space- line with leading space1
space: line <RED>with <RESET>leading <RED>space2<RESET>
space- line with leading space3
space-line without leading space2
EOF
test_expect_success 'grep --color -e A --and -e B with context' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.matchContext normal &&
test_config color.grep.matchSelected red &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&
git grep --color=always -C2 -e "with " --and -e space2 space |
test_decode_color >actual &&
test_cmp expected actual
'
cat >expected <<EOF
space-line without leading space1
space: line <RED>with <RESET>leading space1
space- line with leading space2
space: line <RED>with <RESET>leading space3
space-line without leading space2
EOF
test_expect_success 'grep --color -e A --and --not -e B with context' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.matchContext normal &&
test_config color.grep.matchSelected red &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&
git grep --color=always -C2 -e "with " --and --not -e space2 space |
test_decode_color >actual &&
test_cmp expected actual
'
cat >expected <<EOF
hello.c-
hello.c=int main(int argc, const char **argv)
hello.c-{
hello.c: pr<RED>int<RESET>f("<RED>Hello<RESET> world.\n");
hello.c- return 0;
hello.c- /* char ?? */
hello.c-}
EOF
test_expect_success 'grep --color -e A --and -e B -p with context' '
test_config color.grep.context normal &&
test_config color.grep.filename normal &&
test_config color.grep.function normal &&
test_config color.grep.linenumber normal &&
test_config color.grep.matchContext normal &&
test_config color.grep.matchSelected red &&
test_config color.grep.selected normal &&
test_config color.grep.separator normal &&
git grep --color=always -p -C3 -e int --and -e Hello --no-index hello.c |
test_decode_color >actual &&
test_cmp expected actual
'
test_expect_success 'grep can find things only in the work tree' '
: >work-tree-only &&
git add work-tree-only &&
test_when_finished "git rm -f work-tree-only" &&
echo "find in work tree" >work-tree-only &&
git grep --quiet "find in work tree" &&
test_must_fail git grep --quiet --cached "find in work tree" &&
test_must_fail git grep --quiet "find in work tree" HEAD
'
test_expect_success 'grep can find things only in the work tree (i-t-a)' '
echo "intend to add this" >intend-to-add &&
git add -N intend-to-add &&
test_when_finished "git rm -f intend-to-add" &&
git grep --quiet "intend to add this" &&
test_must_fail git grep --quiet --cached "intend to add this" &&
test_must_fail git grep --quiet "intend to add this" HEAD
'
test_expect_success 'grep does not search work tree with assume unchanged' '
echo "intend to add this" >intend-to-add &&
git add -N intend-to-add &&
git update-index --assume-unchanged intend-to-add &&
test_when_finished "git rm -f intend-to-add" &&
test_must_fail git grep --quiet "intend to add this" &&
test_must_fail git grep --quiet --cached "intend to add this" &&
test_must_fail git grep --quiet "intend to add this" HEAD
'
test_expect_success 'grep can find things only in the index' '
echo "only in the index" >cache-this &&
git add cache-this &&
rm cache-this &&
test_when_finished "git rm --cached cache-this" &&
test_must_fail git grep --quiet "only in the index" &&
git grep --quiet --cached "only in the index" &&
test_must_fail git grep --quiet "only in the index" HEAD
'
test_expect_success 'grep does not report i-t-a with -L --cached' '
echo "intend to add this" >intend-to-add &&
git add -N intend-to-add &&
test_when_finished "git rm -f intend-to-add" &&
git ls-files | grep -v "^intend-to-add\$" >expected &&
git grep -L --cached "nonexistent_string" >actual &&
test_cmp expected actual
'
test_expect_success 'grep does not report i-t-a and assume unchanged with -L' '
echo "intend to add this" >intend-to-add-assume-unchanged &&
git add -N intend-to-add-assume-unchanged &&
test_when_finished "git rm -f intend-to-add-assume-unchanged" &&
git update-index --assume-unchanged intend-to-add-assume-unchanged &&
git ls-files | grep -v "^intend-to-add-assume-unchanged\$" >expected &&
git grep -L "nonexistent_string" >actual &&
test_cmp expected actual
'
test_done