Merge branch 'js/userdiff-cc'
Improves the pattern to match the hunk-header for C/C++. * js/userdiff-cc: userdiff: have 'cpp' hunk header pattern catch more C++ anchor points t4018: test cases showing that the cpp pattern misses many anchor points t4018: test cases for the built-in cpp pattern t4018: reduce test files for pattern compilation tests t4018: convert custom pattern test to the new infrastructure t4018: convert java pattern test to the new infrastructure t4018: convert perl pattern tests to the new infrastructure t4018: an infrastructure to test hunk headers userdiff: support unsigned and long long suffixes of integer constants userdiff: support C++ ->* and .* operators in the word regexp
This commit is contained in:
commit
c228a5c077
@ -7,179 +7,103 @@ test_description='Test custom diff function name patterns'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
LF='
|
||||
test_expect_success 'setup' '
|
||||
# a non-trivial custom pattern
|
||||
git config diff.custom1.funcname "!static
|
||||
!String
|
||||
[^ ].*s.*" &&
|
||||
|
||||
# a custom pattern which matches to end of line
|
||||
git config diff.custom2.funcname "......Beer\$" &&
|
||||
|
||||
# alternation in pattern
|
||||
git config diff.custom3.funcname "Beer$" &&
|
||||
git config diff.custom3.xfuncname "^[ ]*((public|static).*)$" &&
|
||||
|
||||
# for regexp compilation tests
|
||||
echo A >A.java &&
|
||||
echo B >B.java
|
||||
'
|
||||
cat >Beer.java <<\EOF
|
||||
public class Beer
|
||||
{
|
||||
int special;
|
||||
public static void main(String args[])
|
||||
{
|
||||
String s=" ";
|
||||
for(int x = 99; x > 0; x--)
|
||||
{
|
||||
System.out.print(x + " bottles of beer on the wall "
|
||||
+ x + " bottles of beer\n"
|
||||
+ "Take one down, pass it around, " + (x - 1)
|
||||
+ " bottles of beer on the wall.\n");
|
||||
}
|
||||
System.out.print("Go to the store, buy some more,\n"
|
||||
+ "99 bottles of beer on the wall.\n");
|
||||
}
|
||||
}
|
||||
EOF
|
||||
sed 's/beer\\/beer,\\/' <Beer.java >Beer-correct.java
|
||||
cat >Beer.perl <<\EOT
|
||||
package Beer;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use parent qw(Exporter);
|
||||
our @EXPORT_OK = qw(round finalround);
|
||||
diffpatterns="
|
||||
ada
|
||||
bibtex
|
||||
cpp
|
||||
csharp
|
||||
fortran
|
||||
html
|
||||
java
|
||||
matlab
|
||||
objc
|
||||
pascal
|
||||
perl
|
||||
php
|
||||
python
|
||||
ruby
|
||||
tex
|
||||
custom1
|
||||
custom2
|
||||
custom3
|
||||
"
|
||||
|
||||
sub other; # forward declaration
|
||||
|
||||
# hello
|
||||
|
||||
sub round {
|
||||
my ($n) = @_;
|
||||
print "$n bottles of beer on the wall ";
|
||||
print "$n bottles of beer\n";
|
||||
print "Take one down, pass it around, ";
|
||||
$n = $n - 1;
|
||||
print "$n bottles of beer on the wall.\n";
|
||||
}
|
||||
|
||||
sub finalround
|
||||
{
|
||||
print "Go to the store, buy some more\n";
|
||||
print "99 bottles of beer on the wall.\n");
|
||||
}
|
||||
|
||||
sub withheredocument {
|
||||
print <<"EOF"
|
||||
decoy here-doc
|
||||
EOF
|
||||
# some lines of context
|
||||
# to pad it out
|
||||
print "hello\n";
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Beer - subroutine to output fragment of a drinking song
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Beer qw(round finalround);
|
||||
|
||||
sub song {
|
||||
for (my $i = 99; $i > 0; $i--) {
|
||||
round $i;
|
||||
}
|
||||
finalround;
|
||||
}
|
||||
|
||||
song;
|
||||
|
||||
=cut
|
||||
EOT
|
||||
sed -e '
|
||||
s/hello/goodbye/
|
||||
s/beer\\/beer,\\/
|
||||
s/more\\/more,\\/
|
||||
s/song;/song();/
|
||||
' <Beer.perl >Beer-correct.perl
|
||||
|
||||
test_expect_funcname () {
|
||||
lang=${2-java}
|
||||
test_expect_code 1 git diff --no-index -U1 \
|
||||
"Beer.$lang" "Beer-correct.$lang" >diff &&
|
||||
grep "^@@.*@@ $1" diff
|
||||
}
|
||||
|
||||
for p in ada bibtex cpp csharp fortran html java matlab objc pascal perl php python ruby tex
|
||||
for p in $diffpatterns
|
||||
do
|
||||
test_expect_success "builtin $p pattern compiles" '
|
||||
echo "*.java diff=$p" >.gitattributes &&
|
||||
test_expect_code 1 git diff --no-index \
|
||||
Beer.java Beer-correct.java 2>msg &&
|
||||
! grep fatal msg &&
|
||||
! grep error msg
|
||||
A.java B.java 2>msg &&
|
||||
! test_i18ngrep fatal msg &&
|
||||
! test_i18ngrep error msg
|
||||
'
|
||||
test_expect_success "builtin $p wordRegex pattern compiles" '
|
||||
echo "*.java diff=$p" >.gitattributes &&
|
||||
test_expect_code 1 git diff --no-index --word-diff \
|
||||
Beer.java Beer-correct.java 2>msg &&
|
||||
! grep fatal msg &&
|
||||
! grep error msg
|
||||
A.java B.java 2>msg &&
|
||||
! test_i18ngrep fatal msg &&
|
||||
! test_i18ngrep error msg
|
||||
'
|
||||
done
|
||||
|
||||
test_expect_success 'default behaviour' '
|
||||
rm -f .gitattributes &&
|
||||
test_expect_funcname "public class Beer\$"
|
||||
'
|
||||
|
||||
test_expect_success 'set up .gitattributes declaring drivers to test' '
|
||||
cat >.gitattributes <<-\EOF
|
||||
*.java diff=java
|
||||
*.perl diff=perl
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'preset java pattern' '
|
||||
test_expect_funcname "public static void main("
|
||||
'
|
||||
|
||||
test_expect_success 'preset perl pattern' '
|
||||
test_expect_funcname "sub round {\$" perl
|
||||
'
|
||||
|
||||
test_expect_success 'perl pattern accepts K&R style brace placement, too' '
|
||||
test_expect_funcname "sub finalround\$" perl
|
||||
'
|
||||
|
||||
test_expect_success 'but is not distracted by end of <<here document' '
|
||||
test_expect_funcname "sub withheredocument {\$" perl
|
||||
'
|
||||
|
||||
test_expect_success 'perl pattern is not distracted by sub within POD' '
|
||||
test_expect_funcname "=head" perl
|
||||
'
|
||||
|
||||
test_expect_success 'perl pattern gets full line of POD header' '
|
||||
test_expect_funcname "=head1 SYNOPSIS\$" perl
|
||||
'
|
||||
|
||||
test_expect_success 'perl pattern is not distracted by forward declaration' '
|
||||
test_expect_funcname "package Beer;\$" perl
|
||||
'
|
||||
|
||||
test_expect_success 'custom pattern' '
|
||||
test_config diff.java.funcname "!static
|
||||
!String
|
||||
[^ ].*s.*" &&
|
||||
test_expect_funcname "int special;\$"
|
||||
'
|
||||
|
||||
test_expect_success 'last regexp must not be negated' '
|
||||
echo "*.java diff=java" >.gitattributes &&
|
||||
test_config diff.java.funcname "!static" &&
|
||||
test_expect_code 128 git diff --no-index Beer.java Beer-correct.java 2>msg &&
|
||||
grep ": Last expression must not be negated:" msg
|
||||
test_expect_code 128 git diff --no-index A.java B.java 2>msg &&
|
||||
test_i18ngrep ": Last expression must not be negated:" msg
|
||||
'
|
||||
|
||||
test_expect_success 'pattern which matches to end of line' '
|
||||
test_config diff.java.funcname "Beer\$" &&
|
||||
test_expect_funcname "Beer\$"
|
||||
test_expect_success 'setup hunk header tests' '
|
||||
for i in $diffpatterns
|
||||
do
|
||||
echo "$i-* diff=$i"
|
||||
done > .gitattributes &&
|
||||
|
||||
# add all test files to the index
|
||||
(
|
||||
cd "$TEST_DIRECTORY"/t4018 &&
|
||||
git --git-dir="$TRASH_DIRECTORY/.git" add .
|
||||
) &&
|
||||
|
||||
# place modified files in the worktree
|
||||
for i in $(git ls-files)
|
||||
do
|
||||
sed -e "s/ChangeMe/IWasChanged/" <"$TEST_DIRECTORY/t4018/$i" >"$i" || return 1
|
||||
done
|
||||
'
|
||||
|
||||
test_expect_success 'alternation in pattern' '
|
||||
test_config diff.java.funcname "Beer$" &&
|
||||
test_config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
|
||||
test_expect_funcname "public static void main("
|
||||
'
|
||||
# check each individual file
|
||||
for i in $(git ls-files)
|
||||
do
|
||||
if grep broken "$i" >/dev/null 2>&1
|
||||
then
|
||||
result=failure
|
||||
else
|
||||
result=success
|
||||
fi
|
||||
test_expect_$result "hunk header: $i" "
|
||||
test_when_finished 'cat actual' && # for debugging only
|
||||
git diff -U1 $i >actual &&
|
||||
grep '@@ .* @@.*RIGHT' actual
|
||||
"
|
||||
done
|
||||
|
||||
test_done
|
||||
|
18
t/t4018/README
Normal file
18
t/t4018/README
Normal file
@ -0,0 +1,18 @@
|
||||
How to write RIGHT test cases
|
||||
=============================
|
||||
|
||||
Insert the word "ChangeMe" (exactly this form) at a distance of
|
||||
at least two lines from the line that must appear in the hunk header.
|
||||
|
||||
The text that must appear in the hunk header must contain the word
|
||||
"right", but in all upper-case, like in the title above.
|
||||
|
||||
To mark a test case that highlights a malfunction, insert the word
|
||||
BROKEN in all lower-case somewhere in the file.
|
||||
|
||||
This text is a bit twisted and out of order, but it is itself a
|
||||
test case for the default hunk header pattern. Know what you are doing
|
||||
if you change it.
|
||||
|
||||
BTW, this tests that the head line goes to the hunk header, not the line
|
||||
of equal signs.
|
4
t/t4018/cpp-c++-function
Normal file
4
t/t4018/cpp-c++-function
Normal file
@ -0,0 +1,4 @@
|
||||
Item RIGHT::DoSomething( Args with_spaces )
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-class-constructor
Normal file
4
t/t4018/cpp-class-constructor
Normal file
@ -0,0 +1,4 @@
|
||||
Item::Item(int RIGHT)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
5
t/t4018/cpp-class-constructor-mem-init
Normal file
5
t/t4018/cpp-class-constructor-mem-init
Normal file
@ -0,0 +1,5 @@
|
||||
Item::Item(int RIGHT) :
|
||||
member(0)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-class-definition
Normal file
4
t/t4018/cpp-class-definition
Normal file
@ -0,0 +1,4 @@
|
||||
class RIGHT
|
||||
{
|
||||
int ChangeMe;
|
||||
};
|
5
t/t4018/cpp-class-definition-derived
Normal file
5
t/t4018/cpp-class-definition-derived
Normal file
@ -0,0 +1,5 @@
|
||||
class RIGHT :
|
||||
public Baseclass
|
||||
{
|
||||
int ChangeMe;
|
||||
};
|
4
t/t4018/cpp-class-destructor
Normal file
4
t/t4018/cpp-class-destructor
Normal file
@ -0,0 +1,4 @@
|
||||
RIGHT::~RIGHT()
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-function-returning-global-type
Normal file
4
t/t4018/cpp-function-returning-global-type
Normal file
@ -0,0 +1,4 @@
|
||||
::Item get::it::RIGHT()
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
5
t/t4018/cpp-function-returning-nested
Normal file
5
t/t4018/cpp-function-returning-nested
Normal file
@ -0,0 +1,5 @@
|
||||
get::Item get::it::RIGHT()
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
||||
|
4
t/t4018/cpp-function-returning-pointer
Normal file
4
t/t4018/cpp-function-returning-pointer
Normal file
@ -0,0 +1,4 @@
|
||||
const char *get_it_RIGHT(char *ptr)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-function-returning-reference
Normal file
4
t/t4018/cpp-function-returning-reference
Normal file
@ -0,0 +1,4 @@
|
||||
string& get::it::RIGHT(char *ptr)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
5
t/t4018/cpp-gnu-style-function
Normal file
5
t/t4018/cpp-gnu-style-function
Normal file
@ -0,0 +1,5 @@
|
||||
const char *
|
||||
RIGHT(int arg)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-namespace-definition
Normal file
4
t/t4018/cpp-namespace-definition
Normal file
@ -0,0 +1,4 @@
|
||||
namespace RIGHT
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-operator-definition
Normal file
4
t/t4018/cpp-operator-definition
Normal file
@ -0,0 +1,4 @@
|
||||
Value operator+(Value LEFT, Value RIGHT)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
8
t/t4018/cpp-skip-access-specifiers
Normal file
8
t/t4018/cpp-skip-access-specifiers
Normal file
@ -0,0 +1,8 @@
|
||||
class RIGHT : public Baseclass
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
private:
|
||||
void DoSomething();
|
||||
int ChangeMe;
|
||||
};
|
9
t/t4018/cpp-skip-comment-block
Normal file
9
t/t4018/cpp-skip-comment-block
Normal file
@ -0,0 +1,9 @@
|
||||
struct item RIGHT(int i)
|
||||
// Do not
|
||||
// pick up
|
||||
/* these
|
||||
** comments.
|
||||
*/
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
8
t/t4018/cpp-skip-labels
Normal file
8
t/t4018/cpp-skip-labels
Normal file
@ -0,0 +1,8 @@
|
||||
void RIGHT (void)
|
||||
{
|
||||
repeat: // C++ comment
|
||||
next: /* C comment */
|
||||
do_something();
|
||||
|
||||
ChangeMe;
|
||||
}
|
9
t/t4018/cpp-struct-definition
Normal file
9
t/t4018/cpp-struct-definition
Normal file
@ -0,0 +1,9 @@
|
||||
struct RIGHT {
|
||||
unsigned
|
||||
/* this bit field looks like a label and should not be picked up */
|
||||
decoy_bitfield: 2,
|
||||
more : 1;
|
||||
int filler;
|
||||
|
||||
int ChangeMe;
|
||||
};
|
7
t/t4018/cpp-struct-single-line
Normal file
7
t/t4018/cpp-struct-single-line
Normal file
@ -0,0 +1,7 @@
|
||||
void wrong()
|
||||
{
|
||||
}
|
||||
|
||||
struct RIGHT_iterator_tag {};
|
||||
|
||||
int ChangeMe;
|
4
t/t4018/cpp-template-function-definition
Normal file
4
t/t4018/cpp-template-function-definition
Normal file
@ -0,0 +1,4 @@
|
||||
template<class T> int RIGHT(T arg)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
4
t/t4018/cpp-union-definition
Normal file
4
t/t4018/cpp-union-definition
Normal file
@ -0,0 +1,4 @@
|
||||
union RIGHT {
|
||||
double v;
|
||||
int ChangeMe;
|
||||
};
|
4
t/t4018/cpp-void-c-function
Normal file
4
t/t4018/cpp-void-c-function
Normal file
@ -0,0 +1,4 @@
|
||||
void RIGHT (void)
|
||||
{
|
||||
ChangeMe;
|
||||
}
|
17
t/t4018/custom1-pattern
Normal file
17
t/t4018/custom1-pattern
Normal file
@ -0,0 +1,17 @@
|
||||
public class Beer
|
||||
{
|
||||
int special, RIGHT;
|
||||
public static void main(String args[])
|
||||
{
|
||||
String s=" ";
|
||||
for(int x = 99; x > 0; x--)
|
||||
{
|
||||
System.out.print(x + " bottles of beer on the wall "
|
||||
+ x + " bottles of beer\n" // ChangeMe
|
||||
+ "Take one down, pass it around, " + (x - 1)
|
||||
+ " bottles of beer on the wall.\n");
|
||||
}
|
||||
System.out.print("Go to the store, buy some more,\n"
|
||||
+ "99 bottles of beer on the wall.\n");
|
||||
}
|
||||
}
|
8
t/t4018/custom2-match-to-end-of-line
Normal file
8
t/t4018/custom2-match-to-end-of-line
Normal file
@ -0,0 +1,8 @@
|
||||
public class RIGHT_Beer
|
||||
{
|
||||
int special;
|
||||
public static void main(String args[])
|
||||
{
|
||||
System.out.print("ChangeMe");
|
||||
}
|
||||
}
|
17
t/t4018/custom3-alternation-in-pattern
Normal file
17
t/t4018/custom3-alternation-in-pattern
Normal file
@ -0,0 +1,17 @@
|
||||
public class Beer
|
||||
{
|
||||
int special;
|
||||
public static void main(String RIGHT[])
|
||||
{
|
||||
String s=" ";
|
||||
for(int x = 99; x > 0; x--)
|
||||
{
|
||||
System.out.print(x + " bottles of beer on the wall "
|
||||
+ x + " bottles of beer\n" // ChangeMe
|
||||
+ "Take one down, pass it around, " + (x - 1)
|
||||
+ " bottles of beer on the wall.\n");
|
||||
}
|
||||
System.out.print("Go to the store, buy some more,\n"
|
||||
+ "99 bottles of beer on the wall.\n");
|
||||
}
|
||||
}
|
8
t/t4018/java-class-member-function
Normal file
8
t/t4018/java-class-member-function
Normal file
@ -0,0 +1,8 @@
|
||||
public class Beer
|
||||
{
|
||||
int special;
|
||||
public static void main(String RIGHT[])
|
||||
{
|
||||
System.out.print("ChangeMe");
|
||||
}
|
||||
}
|
8
t/t4018/perl-skip-end-of-heredoc
Normal file
8
t/t4018/perl-skip-end-of-heredoc
Normal file
@ -0,0 +1,8 @@
|
||||
sub RIGHTwithheredocument {
|
||||
print <<"EOF"
|
||||
decoy here-doc
|
||||
EOF
|
||||
# some lines of context
|
||||
# to pad it out
|
||||
print "ChangeMe\n";
|
||||
}
|
10
t/t4018/perl-skip-forward-decl
Normal file
10
t/t4018/perl-skip-forward-decl
Normal file
@ -0,0 +1,10 @@
|
||||
package RIGHT;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use parent qw(Exporter);
|
||||
our @EXPORT_OK = qw(round finalround);
|
||||
|
||||
sub other; # forward declaration
|
||||
|
||||
# ChangeMe
|
18
t/t4018/perl-skip-sub-in-pod
Normal file
18
t/t4018/perl-skip-sub-in-pod
Normal file
@ -0,0 +1,18 @@
|
||||
=head1 NAME
|
||||
|
||||
Beer - subroutine to output fragment of a drinking song
|
||||
|
||||
=head1 SYNOPSIS_RIGHT
|
||||
|
||||
use Beer qw(round finalround);
|
||||
|
||||
sub song {
|
||||
for (my $i = 99; $i > 0; $i--) {
|
||||
round $i;
|
||||
}
|
||||
finalround;
|
||||
}
|
||||
|
||||
ChangeMe;
|
||||
|
||||
=cut
|
4
t/t4018/perl-sub-definition
Normal file
4
t/t4018/perl-sub-definition
Normal file
@ -0,0 +1,4 @@
|
||||
sub RIGHT {
|
||||
my ($n) = @_;
|
||||
print "ChangeMe";
|
||||
}
|
4
t/t4018/perl-sub-definition-kr-brace
Normal file
4
t/t4018/perl-sub-definition-kr-brace
Normal file
@ -0,0 +1,4 @@
|
||||
sub RIGHT
|
||||
{
|
||||
print "ChangeMe\n";
|
||||
}
|
12
userdiff.c
12
userdiff.c
@ -125,15 +125,13 @@ PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
|
||||
"\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
|
||||
PATTERNS("cpp",
|
||||
/* Jump targets or access declarations */
|
||||
"!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
|
||||
/* C/++ functions/methods at top level */
|
||||
"^([A-Za-z_][A-Za-z_0-9]*([ \t*]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
|
||||
/* compound type at top level */
|
||||
"^((struct|class|enum)[^;]*)$",
|
||||
"!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n"
|
||||
/* functions/methods, variables, and compounds at top level */
|
||||
"^((::[[:space:]]*)?[A-Za-z_].*)$",
|
||||
/* -- */
|
||||
"[a-zA-Z_][a-zA-Z0-9_]*"
|
||||
"|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
|
||||
"|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
|
||||
"|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lLuU]*"
|
||||
"|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*"),
|
||||
PATTERNS("csharp",
|
||||
/* Keywords */
|
||||
"!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n"
|
||||
|
Loading…
Reference in New Issue
Block a user