Git fork

Merge branch 'ab/userdiff-tests'

A bit of code clean-up and a lot of test clean-up around userdiff
area.

* ab/userdiff-tests:
blame tests: simplify userdiff driver test
blame tests: don't rely on t/t4018/ directory
userdiff: remove support for "broken" tests
userdiff tests: list builtin drivers via test-tool
userdiff tests: explicitly test "default" pattern
userdiff: add and use for_each_userdiff_driver()
userdiff style: normalize pascal regex declaration
userdiff style: declare patterns with consistent style
userdiff style: re-order drivers in alphabetical order

+213 -109
+1
Makefile
··· 753 753 TEST_BUILTINS_OBJS += test-subprocess.o 754 754 TEST_BUILTINS_OBJS += test-trace2.o 755 755 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o 756 + TEST_BUILTINS_OBJS += test-userdiff.o 756 757 TEST_BUILTINS_OBJS += test-wildmatch.o 757 758 TEST_BUILTINS_OBJS += test-windows-named-pipe.o 758 759 TEST_BUILTINS_OBJS += test-write-cache.o
+19 -15
t/annotate-tests.sh
··· 479 479 check_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1 480 480 ' 481 481 482 - test_expect_success 'setup -L :funcname with userdiff driver' ' 483 - echo "fortran-* diff=fortran" >.gitattributes && 484 - fortran_file=fortran-external-function && 485 - orig_file="$TEST_DIRECTORY/t4018/$fortran_file" && 486 - cp "$orig_file" . && 487 - git add "$fortran_file" && 488 - GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \ 489 - git commit -m "add fortran file" && 490 - sed -e "s/ChangeMe/IWasChanged/" <"$orig_file" >"$fortran_file" && 491 - git add "$fortran_file" && 492 - GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \ 493 - git commit -m "change fortran file" 494 - ' 495 - 496 482 test_expect_success 'blame -L :funcname with userdiff driver' ' 497 - check_count -f fortran-external-function -L:RIGHT A 7 B 1 483 + cat >file.template <<-\EOF && 484 + DO NOT MATCH THIS LINE 485 + function RIGHT(a, b) result(c) 486 + AS THE DEFAULT DRIVER WOULD 487 + 488 + integer, intent(in) :: ChangeMe 489 + EOF 490 + 491 + fortran_file=file.f03 && 492 + test_when_finished "rm .gitattributes" && 493 + echo "$fortran_file diff=fortran" >.gitattributes && 494 + 495 + test_commit --author "A <A@test.git>" \ 496 + "add" "$fortran_file" \ 497 + "$(cat file.template)" && 498 + test_commit --author "B <B@test.git>" \ 499 + "change" "$fortran_file" \ 500 + "$(cat file.template | sed -e s/ChangeMe/IWasChanged/)" && 501 + check_count -f "$fortran_file" -L:RIGHT A 3 B 1 498 502 ' 499 503 500 504 test_expect_success 'setup incremental' '
+1
t/helper/test-tool.c
··· 73 73 { "submodule-nested-repo-config", cmd__submodule_nested_repo_config }, 74 74 { "subprocess", cmd__subprocess }, 75 75 { "trace2", cmd__trace2 }, 76 + { "userdiff", cmd__userdiff }, 76 77 { "urlmatch-normalization", cmd__urlmatch_normalization }, 77 78 { "xml-encode", cmd__xml_encode }, 78 79 { "wildmatch", cmd__wildmatch },
+1
t/helper/test-tool.h
··· 63 63 int cmd__submodule_nested_repo_config(int argc, const char **argv); 64 64 int cmd__subprocess(int argc, const char **argv); 65 65 int cmd__trace2(int argc, const char **argv); 66 + int cmd__userdiff(int argc, const char **argv); 66 67 int cmd__urlmatch_normalization(int argc, const char **argv); 67 68 int cmd__xml_encode(int argc, const char **argv); 68 69 int cmd__wildmatch(int argc, const char **argv);
+46
t/helper/test-userdiff.c
··· 1 + #include "test-tool.h" 2 + #include "cache.h" 3 + #include "userdiff.h" 4 + #include "config.h" 5 + 6 + static int driver_cb(struct userdiff_driver *driver, 7 + enum userdiff_driver_type type, void *priv) 8 + { 9 + enum userdiff_driver_type *want_type = priv; 10 + if (type & *want_type && driver->funcname.pattern) 11 + puts(driver->name); 12 + return 0; 13 + } 14 + 15 + static int cmd__userdiff_config(const char *var, const char *value, void *cb) 16 + { 17 + if (userdiff_config(var, value) < 0) 18 + return -1; 19 + return 0; 20 + } 21 + 22 + int cmd__userdiff(int argc, const char **argv) 23 + { 24 + enum userdiff_driver_type want = 0; 25 + if (argc != 2) 26 + return 1; 27 + 28 + if (!strcmp(argv[1], "list-drivers")) 29 + want = (USERDIFF_DRIVER_TYPE_BUILTIN | 30 + USERDIFF_DRIVER_TYPE_CUSTOM); 31 + else if (!strcmp(argv[1], "list-builtin-drivers")) 32 + want = USERDIFF_DRIVER_TYPE_BUILTIN; 33 + else if (!strcmp(argv[1], "list-custom-drivers")) 34 + want = USERDIFF_DRIVER_TYPE_CUSTOM; 35 + else 36 + return error("unknown argument %s", argv[1]); 37 + 38 + if (want & USERDIFF_DRIVER_TYPE_CUSTOM) { 39 + setup_git_directory(); 40 + git_config(cmd__userdiff_config, NULL); 41 + } 42 + 43 + for_each_userdiff_driver(driver_cb, &want); 44 + 45 + return 0; 46 + }
+20 -34
t/t4018-diff-funcname.sh
··· 25 25 echo B >B.java 26 26 ' 27 27 28 + test_expect_success 'setup: test-tool userdiff' ' 29 + # Make sure additions to builtin_drivers are sorted 30 + test_when_finished "rm builtin-drivers.sorted" && 31 + test-tool userdiff list-builtin-drivers >builtin-drivers && 32 + test_file_not_empty builtin-drivers && 33 + sort <builtin-drivers >builtin-drivers.sorted && 34 + test_cmp builtin-drivers.sorted builtin-drivers && 35 + 36 + # Ditto, but "custom" requires the .git directory and config 37 + # to be setup and read. 38 + test_when_finished "rm custom-drivers.sorted" && 39 + test-tool userdiff list-custom-drivers >custom-drivers && 40 + test_file_not_empty custom-drivers && 41 + sort <custom-drivers >custom-drivers.sorted && 42 + test_cmp custom-drivers.sorted custom-drivers 43 + ' 44 + 28 45 diffpatterns=" 29 - ada 30 - bash 31 - bibtex 32 - cpp 33 - csharp 34 - css 35 - dts 36 - elixir 37 - fortran 38 - fountain 39 - golang 40 - html 41 - java 42 - markdown 43 - matlab 44 - objc 45 - pascal 46 - perl 47 - php 48 - python 49 - ruby 50 - rust 51 - scheme 52 - tex 53 - custom1 54 - custom2 55 - custom3 46 + $(cat builtin-drivers) 47 + $(cat custom-drivers) 56 48 " 57 49 58 50 for p in $diffpatterns ··· 102 94 # check each individual file 103 95 for i in $(git ls-files) 104 96 do 105 - if grep broken "$i" >/dev/null 2>&1 106 - then 107 - result=failure 108 - else 109 - result=success 110 - fi 111 - test_expect_$result "hunk header: $i" " 97 + test_expect_success "hunk header: $i" " 112 98 git diff -U1 $i >actual && 113 99 grep '@@ .* @@.*RIGHT' actual 114 100 "
-3
t/t4018/README
··· 7 7 The text that must appear in the hunk header must contain the word 8 8 "right", but in all upper-case, like in the title above. 9 9 10 - To mark a test case that highlights a malfunction, insert the word 11 - BROKEN in all lower-case somewhere in the file. 12 - 13 10 This text is a bit twisted and out of order, but it is itself a 14 11 test case for the default hunk header pattern. Know what you are doing 15 12 if you change it.
+112 -57
userdiff.c
··· 44 44 /* -- */ 45 45 /* Characters not in the default $IFS value */ 46 46 "[^ \t]+"), 47 + PATTERNS("bibtex", 48 + "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", 49 + /* -- */ 50 + "[={}\"]|[^={}\" \t]+"), 51 + PATTERNS("cpp", 52 + /* Jump targets or access declarations */ 53 + "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n" 54 + /* functions/methods, variables, and compounds at top level */ 55 + "^((::[[:space:]]*)?[A-Za-z_].*)$", 56 + /* -- */ 57 + "[a-zA-Z_][a-zA-Z0-9_]*" 58 + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lLuU]*" 59 + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*"), 60 + PATTERNS("csharp", 61 + /* Keywords */ 62 + "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n" 63 + /* Methods and constructors */ 64 + "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe|async)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[<>@._[:alnum:]]+[ \t]*\\(.*\\))[ \t]*$\n" 65 + /* Properties */ 66 + "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[@._[:alnum:]]+)[ \t]*$\n" 67 + /* Type definitions */ 68 + "^[ \t]*(((static|public|internal|private|protected|new|unsafe|sealed|abstract|partial)[ \t]+)*(class|enum|interface|struct)[ \t]+.*)$\n" 69 + /* Namespace */ 70 + "^[ \t]*(namespace[ \t]+.*)$", 71 + /* -- */ 72 + "[a-zA-Z_][a-zA-Z0-9_]*" 73 + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" 74 + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), 75 + IPATTERN("css", 76 + "![:;][[:space:]]*$\n" 77 + "^[:[@.#]?[_a-z0-9].*$", 78 + /* -- */ 79 + /* 80 + * This regex comes from W3C CSS specs. Should theoretically also 81 + * allow ISO 10646 characters U+00A0 and higher, 82 + * but they are not handled in this regex. 83 + */ 84 + "-?[_a-zA-Z][-_a-zA-Z0-9]*" /* identifiers */ 85 + "|-?[0-9]+|\\#[0-9a-fA-F]+" /* numbers */ 86 + ), 47 87 PATTERNS("dts", 48 88 "!;\n" 49 89 "!=\n" ··· 83 123 * they would have been matched above as a variable anyway. */ 84 124 "|[-+]?[0-9.]+([AaIiDdEeFfLlTtXx][Ss]?[-+]?[0-9.]*)?(_[a-zA-Z0-9][a-zA-Z0-9_]*)?" 85 125 "|//|\\*\\*|::|[/<>=]="), 86 - IPATTERN("fountain", "^((\\.[^.]|(int|ext|est|int\\.?/ext|i/e)[. ]).*)$", 126 + IPATTERN("fountain", 127 + "^((\\.[^.]|(int|ext|est|int\\.?/ext|i/e)[. ]).*)$", 128 + /* -- */ 87 129 "[^ \t-]+"), 88 130 PATTERNS("golang", 89 131 /* Functions */ ··· 94 136 "[a-zA-Z_][a-zA-Z0-9_]*" 95 137 "|[-+0-9.eE]+i?|0[xX]?[0-9a-fA-F]+i?" 96 138 "|[-+*/<>%&^|=!:]=|--|\\+\\+|<<=?|>>=?|&\\^=?|&&|\\|\\||<-|\\.{3}"), 97 - PATTERNS("html", "^[ \t]*(<[Hh][1-6]([ \t].*)?>.*)$", 139 + PATTERNS("html", 140 + "^[ \t]*(<[Hh][1-6]([ \t].*)?>.*)$", 141 + /* -- */ 98 142 "[^<>= \t]+"), 99 143 PATTERNS("java", 100 144 "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" ··· 106 150 "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"), 107 151 PATTERNS("markdown", 108 152 "^ {0,3}#{1,6}[ \t].*", 153 + /* -- */ 109 154 "[^<>= \t]+"), 110 155 PATTERNS("matlab", 111 156 /* ··· 114 159 * that is understood by both. 115 160 */ 116 161 "^[[:space:]]*((classdef|function)[[:space:]].*)$|^(%%%?|##)[[:space:]].*$", 162 + /* -- */ 117 163 "[a-zA-Z_][a-zA-Z0-9_]*|[-+0-9.e]+|[=~<>]=|\\.[*/\\^']|\\|\\||&&"), 118 164 PATTERNS("objc", 119 165 /* Negate C statements that can look like functions */ ··· 129 175 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" 130 176 "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), 131 177 PATTERNS("pascal", 132 - "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|" 133 - "implementation|initialization|finalization)[ \t]*.*)$" 134 - "\n" 178 + "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface" 179 + "|implementation|initialization|finalization)[ \t]*.*)$\n" 135 180 "^(.*=[ \t]*(class|record).*)$", 136 181 /* -- */ 137 182 "[a-zA-Z_][a-zA-Z0-9_]*" ··· 174 219 "[a-zA-Z_][a-zA-Z0-9_]*" 175 220 "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" 176 221 "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"), 177 - PATTERNS("python", "^[ \t]*((class|(async[ \t]+)?def)[ \t].*)$", 222 + PATTERNS("python", 223 + "^[ \t]*((class|(async[ \t]+)?def)[ \t].*)$", 178 224 /* -- */ 179 225 "[a-zA-Z_][a-zA-Z0-9_]*" 180 226 "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?" 181 227 "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"), 182 228 /* -- */ 183 - PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$", 229 + PATTERNS("ruby", 230 + "^[ \t]*((class|module|def)[ \t].*)$", 184 231 /* -- */ 185 232 "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*" 186 233 "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?." ··· 200 247 "\\|([^\\\\]*)\\|" 201 248 /* All other words should be delimited by spaces or parentheses */ 202 249 "|([^][)(}{[ \t])+"), 203 - PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", 204 - "[={}\"]|[^={}\" \t]+"), 205 250 PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", 206 251 "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"), 207 - PATTERNS("cpp", 208 - /* Jump targets or access declarations */ 209 - "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:[[:space:]]*($|/[/*])\n" 210 - /* functions/methods, variables, and compounds at top level */ 211 - "^((::[[:space:]]*)?[A-Za-z_].*)$", 212 - /* -- */ 213 - "[a-zA-Z_][a-zA-Z0-9_]*" 214 - "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lLuU]*" 215 - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*"), 216 - PATTERNS("csharp", 217 - /* Keywords */ 218 - "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n" 219 - /* Methods and constructors */ 220 - "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe|async)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[<>@._[:alnum:]]+[ \t]*\\(.*\\))[ \t]*$\n" 221 - /* Properties */ 222 - "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[@._[:alnum:]]+)[ \t]*$\n" 223 - /* Type definitions */ 224 - "^[ \t]*(((static|public|internal|private|protected|new|unsafe|sealed|abstract|partial)[ \t]+)*(class|enum|interface|struct)[ \t]+.*)$\n" 225 - /* Namespace */ 226 - "^[ \t]*(namespace[ \t]+.*)$", 227 - /* -- */ 228 - "[a-zA-Z_][a-zA-Z0-9_]*" 229 - "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" 230 - "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"), 231 - IPATTERN("css", 232 - "![:;][[:space:]]*$\n" 233 - "^[:[@.#]?[_a-z0-9].*$", 234 - /* -- */ 235 - /* 236 - * This regex comes from W3C CSS specs. Should theoretically also 237 - * allow ISO 10646 characters U+00A0 and higher, 238 - * but they are not handled in this regex. 239 - */ 240 - "-?[_a-zA-Z][-_a-zA-Z0-9]*" /* identifiers */ 241 - "|-?[0-9]+|\\#[0-9a-fA-F]+" /* numbers */ 242 - ), 243 252 { "default", NULL, -1, { NULL, 0 } }, 244 253 }; 245 254 #undef PATTERNS ··· 259 268 { NULL, 0 } 260 269 }; 261 270 262 - static struct userdiff_driver *userdiff_find_by_namelen(const char *k, size_t len) 271 + struct find_by_namelen_data { 272 + const char *name; 273 + size_t len; 274 + struct userdiff_driver *driver; 275 + }; 276 + 277 + static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver, 278 + enum userdiff_driver_type type, void *priv) 263 279 { 264 - int i; 265 - for (i = 0; i < ndrivers; i++) { 266 - struct userdiff_driver *drv = drivers + i; 267 - if (!strncmp(drv->name, k, len) && !drv->name[len]) 268 - return drv; 280 + struct find_by_namelen_data *cb_data = priv; 281 + 282 + if (!strncmp(driver->name, cb_data->name, cb_data->len) && 283 + !driver->name[cb_data->len]) { 284 + cb_data->driver = driver; 285 + return 1; /* tell the caller to stop iterating */ 269 286 } 270 - for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) { 271 - struct userdiff_driver *drv = builtin_drivers + i; 272 - if (!strncmp(drv->name, k, len) && !drv->name[len]) 273 - return drv; 274 - } 275 - return NULL; 287 + return 0; 288 + } 289 + 290 + static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t len) 291 + { 292 + struct find_by_namelen_data udcbdata = { 293 + .name = name, 294 + .len = len, 295 + }; 296 + for_each_userdiff_driver(userdiff_find_by_namelen_cb, &udcbdata); 297 + return udcbdata.driver; 276 298 } 277 299 278 300 static int parse_funcname(struct userdiff_funcname *f, const char *k, ··· 379 401 380 402 return driver; 381 403 } 404 + 405 + static int for_each_userdiff_driver_list(each_userdiff_driver_fn fn, 406 + enum userdiff_driver_type type, void *cb_data, 407 + struct userdiff_driver *drv, 408 + int drv_size) 409 + { 410 + int i; 411 + int ret; 412 + for (i = 0; i < drv_size; i++) { 413 + struct userdiff_driver *item = drv + i; 414 + if ((ret = fn(item, type, cb_data))) 415 + return ret; 416 + } 417 + return 0; 418 + } 419 + 420 + int for_each_userdiff_driver(each_userdiff_driver_fn fn, void *cb_data) 421 + { 422 + int ret; 423 + 424 + ret = for_each_userdiff_driver_list(fn, USERDIFF_DRIVER_TYPE_CUSTOM, 425 + cb_data, drivers, ndrivers); 426 + if (ret) 427 + return ret; 428 + 429 + ret = for_each_userdiff_driver_list(fn, USERDIFF_DRIVER_TYPE_BUILTIN, 430 + cb_data, builtin_drivers, 431 + ARRAY_SIZE(builtin_drivers)); 432 + if (ret) 433 + return ret; 434 + 435 + return 0; 436 + }
+13
userdiff.h
··· 21 21 struct notes_cache *textconv_cache; 22 22 int textconv_want_cache; 23 23 }; 24 + enum userdiff_driver_type { 25 + USERDIFF_DRIVER_TYPE_BUILTIN = 1<<0, 26 + USERDIFF_DRIVER_TYPE_CUSTOM = 1<<1, 27 + }; 28 + typedef int (*each_userdiff_driver_fn)(struct userdiff_driver *, 29 + enum userdiff_driver_type, void *); 24 30 25 31 int userdiff_config(const char *k, const char *v); 26 32 struct userdiff_driver *userdiff_find_by_name(const char *name); ··· 33 39 */ 34 40 struct userdiff_driver *userdiff_get_textconv(struct repository *r, 35 41 struct userdiff_driver *driver); 42 + 43 + /* 44 + * Iterate over all userdiff drivers. The userdiff_driver_type 45 + * argument to each_userdiff_driver_fn indicates their type. Return 46 + * non-zero to exit early from the loop. 47 + */ 48 + int for_each_userdiff_driver(each_userdiff_driver_fn, void *); 36 49 37 50 #endif /* USERDIFF */