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:
Junio C Hamano 2014-03-31 16:30:54 -07:00
commit c228a5c077
33 changed files with 304 additions and 161 deletions

View File

@ -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
View 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
View File

@ -0,0 +1,4 @@
Item RIGHT::DoSomething( Args with_spaces )
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
Item::Item(int RIGHT)
{
ChangeMe;
}

View File

@ -0,0 +1,5 @@
Item::Item(int RIGHT) :
member(0)
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
class RIGHT
{
int ChangeMe;
};

View File

@ -0,0 +1,5 @@
class RIGHT :
public Baseclass
{
int ChangeMe;
};

View File

@ -0,0 +1,4 @@
RIGHT::~RIGHT()
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
::Item get::it::RIGHT()
{
ChangeMe;
}

View File

@ -0,0 +1,5 @@
get::Item get::it::RIGHT()
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
const char *get_it_RIGHT(char *ptr)
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
string& get::it::RIGHT(char *ptr)
{
ChangeMe;
}

View File

@ -0,0 +1,5 @@
const char *
RIGHT(int arg)
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
namespace RIGHT
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
Value operator+(Value LEFT, Value RIGHT)
{
ChangeMe;
}

View File

@ -0,0 +1,8 @@
class RIGHT : public Baseclass
{
public:
protected:
private:
void DoSomething();
int ChangeMe;
};

View 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
View File

@ -0,0 +1,8 @@
void RIGHT (void)
{
repeat: // C++ comment
next: /* C comment */
do_something();
ChangeMe;
}

View 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;
};

View File

@ -0,0 +1,7 @@
void wrong()
{
}
struct RIGHT_iterator_tag {};
int ChangeMe;

View File

@ -0,0 +1,4 @@
template<class T> int RIGHT(T arg)
{
ChangeMe;
}

View File

@ -0,0 +1,4 @@
union RIGHT {
double v;
int ChangeMe;
};

View File

@ -0,0 +1,4 @@
void RIGHT (void)
{
ChangeMe;
}

17
t/t4018/custom1-pattern Normal file
View 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");
}
}

View File

@ -0,0 +1,8 @@
public class RIGHT_Beer
{
int special;
public static void main(String args[])
{
System.out.print("ChangeMe");
}
}

View 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");
}
}

View File

@ -0,0 +1,8 @@
public class Beer
{
int special;
public static void main(String RIGHT[])
{
System.out.print("ChangeMe");
}
}

View File

@ -0,0 +1,8 @@
sub RIGHTwithheredocument {
print <<"EOF"
decoy here-doc
EOF
# some lines of context
# to pad it out
print "ChangeMe\n";
}

View 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

View 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

View File

@ -0,0 +1,4 @@
sub RIGHT {
my ($n) = @_;
print "ChangeMe";
}

View File

@ -0,0 +1,4 @@
sub RIGHT
{
print "ChangeMe\n";
}

View File

@ -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"