test-suite 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. #!/bin/sh
  2. #set -x
  3. cd $(dirname "$0")
  4. default_path=".."
  5. default_cmd="sparse \$file"
  6. default_args="$SPARSE_TEST_ARGS"
  7. tests_list=""
  8. prog_name=`basename $0`
  9. if [ ! -x "$default_path/sparse-llvm" ]; then
  10. disabled_cmds="sparsec sparsei sparse-llvm sparse-llvm-dis"
  11. fi
  12. # flags:
  13. # - some tests gave an unexpected result
  14. failed=0
  15. # counts:
  16. # - tests that have not been converted to test-suite format
  17. # - tests that are disabled
  18. # - tests that passed
  19. # - tests that failed
  20. # - tests that failed but are known to fail
  21. unhandled_tests=0
  22. disabled_tests=0
  23. ok_tests=0
  24. ko_tests=0
  25. known_ko_tests=0
  26. # defaults to not verbose
  27. [ -z "$V" ] && V=0
  28. vquiet=""
  29. quiet=0
  30. abort=0
  31. ##
  32. # verbose(string) - prints string if we are in verbose mode
  33. verbose()
  34. {
  35. [ "$V" -eq "1" ] && echo " $1"
  36. return 0
  37. }
  38. ##
  39. # warning(string) - prints a warning
  40. warning()
  41. {
  42. [ "$quiet" -ne 1 ] && echo "warning: $1"
  43. return 0
  44. }
  45. ##
  46. # error(string[, die]) - prints an error and exits with value die if given
  47. error()
  48. {
  49. [ "$quiet" -ne 1 ] && echo "error: $1"
  50. [ -n "$2" ] && exit $2
  51. return 0
  52. }
  53. ##
  54. # get_tag_value(file) - get the 'check-<...>' tags & values
  55. get_tag_value()
  56. {
  57. check_name=""
  58. check_command="$default_cmd"
  59. check_exit_value=0
  60. check_timeout=0
  61. check_known_to_fail=0
  62. check_error_ignore=0
  63. check_output_ignore=0
  64. check_output_contains=0
  65. check_output_excludes=0
  66. check_output_pattern=0
  67. check_arch_ignore=""
  68. check_arch_only=""
  69. check_assert=""
  70. check_cpp_if=""
  71. lines=$(grep 'check-[a-z-]*' $1 | \
  72. sed -e 's/^.*\(check-[a-z-]*:*\) *\(.*\)$/\1 \2/')
  73. while read tag val; do
  74. #echo "-> tag: '$tag'"
  75. #echo "-> val: '$val'"
  76. case $tag in
  77. check-name:) check_name="$val" ;;
  78. check-command:) check_command="$val" ;;
  79. check-exit-value:) check_exit_value="$val" ;;
  80. check-timeout:) [ -z "$val" ] && val=1
  81. check_timeout="$val" ;;
  82. check-known-to-fail) check_known_to_fail=1 ;;
  83. check-error-ignore) check_error_ignore=1 ;;
  84. check-output-ignore) check_output_ignore=1 ;;
  85. check-output-contains:) check_output_contains=1 ;;
  86. check-output-excludes:) check_output_excludes=1 ;;
  87. check-output-pattern) check_output_pattern=1 ;;
  88. check-arch-ignore:) arch=$(uname -m)
  89. check_arch_ignore="$val" ;;
  90. check-arch-only:) arch=$(uname -m)
  91. check_arch_only="$val" ;;
  92. check-assert:) check_assert="$val" ;;
  93. check-cpp-if:) check_cpp_if="$val" ;;
  94. check-description:) ;; # ignore
  95. check-note:) ;; # ignore
  96. check-warning:) ;; # ignore
  97. check-error-start) ;; # ignore
  98. check-error-end) ;; # ignore
  99. check-output-start) ;; # ignore
  100. check-output-end) ;; # ignore
  101. check-should-pass) ;; # ignore, unused annotation
  102. check-should-fail) ;; # ignore, unused annotation
  103. check-should-warn) ;; # ignore, unused annotation
  104. check-*) error "$1: unknown tag '$tag'" 1 ;;
  105. esac
  106. done << EOT
  107. $lines
  108. EOT
  109. }
  110. ##
  111. # helper for has_(each|none)_patterns()
  112. has_patterns()
  113. {
  114. ifile="$1"
  115. patt="$2"
  116. ofile="$3"
  117. cmp="$4"
  118. msg="$5"
  119. grep "$patt:" "$ifile" | \
  120. sed -e "s/^.*$patt: *\(.*\)$/\1/" | \
  121. while read val; do
  122. grep -s -q "$val" "$ofile"
  123. if [ "$?" $cmp 0 ]; then
  124. error " Pattern '$val' unexpectedly $msg"
  125. return 1
  126. fi
  127. done
  128. return $?
  129. }
  130. ##
  131. # has_each_patterns(ifile tag ofile) - does ofile contains some
  132. # of the patterns given by ifile's tags?
  133. #
  134. # returns 0 if all present, 1 otherwise
  135. has_each_patterns()
  136. {
  137. has_patterns "$1" "$2" "$4" -ne "$3"
  138. }
  139. ##
  140. # has_none_patterns(ifile tag ofile) - does ofile contains some
  141. # of the patterns given by ifile's tags?
  142. #
  143. # returns 1 if any present, 0 otherwise
  144. has_none_patterns()
  145. {
  146. has_patterns "$1" "$2" "$4" -eq "$3"
  147. }
  148. ##
  149. # minmax_patterns(ifile tag ofile) - does ofile contains the
  150. # the patterns given by ifile's tags
  151. # the right number of time?
  152. minmax_patterns()
  153. {
  154. ifile="$1"
  155. patt="$2"
  156. ofile="$3"
  157. grep "$patt([0-9-]*\(, *\)*[0-9-]*):" "$ifile" | \
  158. sed -e "s/^.*$patt(\([0-9]*\)): *\(.*\)/\1 eq \2/" \
  159. -e "s/^.*$patt(\([0-9-]*\), *\([0-9-]*\)): *\(.*\)/\1 \2 \3/" | \
  160. while read min max pat; do
  161. n=$(grep -s "$pat" "$ofile" | wc -l)
  162. if [ "$max" = "eq" ]; then
  163. if [ "$n" -ne "$min" ]; then
  164. error " Pattern '$pat' expected $min times but got $n times"
  165. return 1
  166. fi
  167. continue
  168. fi
  169. if [ "$min" != '-' ]; then
  170. if [ "$n" -lt "$min" ]; then
  171. error " Pattern '$pat' expected min $min times but got $n times"
  172. return 1
  173. fi
  174. fi
  175. if [ "$max" != '-' ]; then
  176. if [ "$n" -gt "$max" ]; then
  177. error " Pattern '$pat' expected max $max times but got $n times"
  178. return 1
  179. fi
  180. fi
  181. done
  182. return $?
  183. }
  184. ##
  185. # arg_file(filename) - checks if filename exists
  186. arg_file()
  187. {
  188. [ -z "$1" ] && {
  189. do_usage
  190. exit 1
  191. }
  192. [ -e "$1" ] || {
  193. error "Can't open file $1"
  194. exit 1
  195. }
  196. return 0
  197. }
  198. ##
  199. do_usage()
  200. {
  201. echo "$prog_name - a tiny automatic testing script"
  202. echo "Usage: $prog_name [option(s)] [command] [arguments]"
  203. echo
  204. echo "options:"
  205. echo " -a|--abort Abort the tests as soon as one fails."
  206. echo " -q|--quiet Be extra quiet while running the tests."
  207. echo " --args='...' Add these options to the test command."
  208. echo
  209. echo "commands:"
  210. echo " [file ...] Runs the test suite on the given file(s)."
  211. echo " If a directory is given, run only those files."
  212. echo " If no file is given, run the whole testsuite."
  213. echo " single file Run the test in 'file'."
  214. echo " format file [name [cmd]] Help writing a new test case using cmd."
  215. echo
  216. echo " [command] help Print usage."
  217. }
  218. disable()
  219. {
  220. disabled_tests=$(($disabled_tests + 1))
  221. if [ -z "$vquiet" ]; then
  222. echo " SKIP $1 ($2)"
  223. fi
  224. }
  225. ##
  226. # do_test(file) - tries to validate a test case
  227. #
  228. # it "parses" file, looking for check-* tags and tries to validate
  229. # the test against an expected result
  230. # returns:
  231. # - 0 if the test passed,
  232. # - 1 if it failed,
  233. # - 2 if it is not a "test-suite" test.
  234. # - 3 if the test is disabled.
  235. do_test()
  236. {
  237. test_failed=0
  238. file="$1"
  239. quiet=0
  240. get_tag_value $file
  241. # can this test be handled by test-suite ?
  242. # (it has to have a check-name key in it)
  243. if [ "$check_name" = "" ]; then
  244. warning "$file: test unhandled"
  245. unhandled_tests=$(($unhandled_tests + 1))
  246. return 2
  247. fi
  248. test_name="$check_name"
  249. # does the test provide a specific command ?
  250. if [ "$check_command" = "" ]; then
  251. check_command="$defaut_command"
  252. fi
  253. # check for disabled commands
  254. set -- $check_command
  255. base_cmd=$1
  256. for i in $disabled_cmds; do
  257. if [ "$i" = "$base_cmd" ] ; then
  258. disable "$test_name" "$file"
  259. return 3
  260. fi
  261. done
  262. if [ "$check_arch_ignore" != "" ]; then
  263. if echo $arch | egrep -q -w "$check_arch_ignore"; then
  264. disable "$test_name" "$file"
  265. return 3
  266. fi
  267. fi
  268. if [ "$check_arch_only" != "" ]; then
  269. if ! (echo $arch | egrep -q -w "$check_arch_only"); then
  270. disable "$test_name" "$file"
  271. return 3
  272. fi
  273. fi
  274. if [ "$check_assert" != "" ]; then
  275. res=$(../sparse - 2>&1 >/dev/null <<- EOF
  276. _Static_assert($check_assert, "$check_assert");
  277. EOF
  278. )
  279. if [ "$res" != "" ]; then
  280. disable "$test_name" "$file"
  281. return 3
  282. fi
  283. fi
  284. if [ "$check_cpp_if" != "" ]; then
  285. res=$(../sparse -E - 2>/dev/null <<- EOF
  286. #if !($check_cpp_if)
  287. fail
  288. #endif
  289. EOF
  290. )
  291. if [ "$res" != "" ]; then
  292. disable "$test_name" "$file"
  293. return 3
  294. fi
  295. fi
  296. if [ -z "$vquiet" ]; then
  297. echo " TEST $test_name ($file)"
  298. fi
  299. verbose "Using command : $(echo "$@")"
  300. # grab the expected exit value
  301. expected_exit_value=$check_exit_value
  302. verbose "Expecting exit value: $expected_exit_value"
  303. # do we want a timeout?
  304. pre_cmd=""
  305. if [ $check_timeout -ne 0 ]; then
  306. pre_cmd="timeout $check_timeout"
  307. fi
  308. shift
  309. # launch the test command and
  310. # grab the actual output & exit value
  311. eval $pre_cmd $default_path/$base_cmd $default_args "$@" \
  312. 1> $file.output.got 2> $file.error.got
  313. actual_exit_value=$?
  314. must_fail=$check_known_to_fail
  315. [ $must_fail -eq 1 ] && [ $V -eq 0 ] && quiet=1
  316. known_ko_tests=$(($known_ko_tests + $must_fail))
  317. for stream in error output; do
  318. eval ignore=\$check_${stream}_ignore
  319. [ $ignore -eq 1 ] && continue
  320. # grab the expected output
  321. sed -n "/check-$stream-start/,/check-$stream-end/p" $file \
  322. | grep -v check-$stream > "$file".$stream.expected
  323. diff -u "$file".$stream.expected "$file".$stream.got > "$file".$stream.diff
  324. if [ "$?" -ne "0" ]; then
  325. error "actual $stream text does not match expected $stream text."
  326. error "see $file.$stream.* for further investigation."
  327. [ $quiet -ne 1 ] && cat "$file".$stream.diff
  328. test_failed=1
  329. fi
  330. done
  331. if [ "$actual_exit_value" -ne "$expected_exit_value" ]; then
  332. error "Actual exit value does not match the expected one."
  333. error "expected $expected_exit_value, got $actual_exit_value."
  334. test_failed=1
  335. fi
  336. # verify the 'check-output-contains/excludes' tags
  337. if [ $check_output_contains -eq 1 ]; then
  338. has_each_patterns "$file" 'check-output-contains' absent $file.output.got
  339. if [ "$?" -ne "0" ]; then
  340. test_failed=1
  341. fi
  342. fi
  343. if [ $check_output_excludes -eq 1 ]; then
  344. has_none_patterns "$file" 'check-output-excludes' present $file.output.got
  345. if [ "$?" -ne "0" ]; then
  346. test_failed=1
  347. fi
  348. fi
  349. if [ $check_output_pattern -eq 1 ]; then
  350. # verify the 'check-output-pattern(...)' tags
  351. minmax_patterns "$file" 'check-output-pattern' $file.output.got
  352. if [ "$?" -ne "0" ]; then
  353. test_failed=1
  354. fi
  355. fi
  356. if [ "$must_fail" -eq "1" ]; then
  357. if [ "$test_failed" -eq "1" ]; then
  358. [ -z "$vquiet" ] && \
  359. echo "info: XFAIL: test '$file' is known to fail"
  360. else
  361. echo "error: XPASS: test '$file' is known to fail but succeed!"
  362. fi
  363. else
  364. if [ "$test_failed" -eq "1" ]; then
  365. echo "error: FAIL: test '$file' failed"
  366. else
  367. [ "$V" -ne "0" ] && \
  368. echo "info: PASS: test '$file' passed"
  369. fi
  370. fi
  371. if [ "$test_failed" -ne "$must_fail" ]; then
  372. [ $abort -eq 1 ] && exit 1
  373. test_failed=1
  374. failed=1
  375. fi
  376. if [ "$test_failed" -eq "1" ]; then
  377. ko_tests=$(($ko_tests + 1))
  378. else
  379. ok_tests=$(($ok_tests + 1))
  380. rm -f $file.{error,output}.{expected,got,diff}
  381. fi
  382. return $test_failed
  383. }
  384. do_test_suite()
  385. {
  386. for i in $tests_list; do
  387. do_test "$i"
  388. done
  389. OK=OK
  390. [ $failed -eq 0 ] || OK=KO
  391. # prints some numbers
  392. tests_nr=$(($ok_tests + $ko_tests))
  393. echo "$OK: out of $tests_nr tests, $ok_tests passed, $ko_tests failed"
  394. if [ "$known_ko_tests" -ne 0 ]; then
  395. echo " $known_ko_tests of them are known to fail"
  396. fi
  397. if [ "$unhandled_tests" -ne "0" ]; then
  398. echo " $unhandled_tests tests could not be handled by $prog_name"
  399. fi
  400. if [ "$disabled_tests" -ne "0" ]; then
  401. echo " $disabled_tests tests were disabled"
  402. fi
  403. }
  404. ##
  405. do_format_help() {
  406. echo "Usage: $prog_name [option(s)] [--]format file [name [cmd]]"
  407. echo
  408. echo "options:"
  409. echo " -a append the created test to the input file"
  410. echo " -f write a test known to fail"
  411. echo " -l write a test for linearized code"
  412. echo " -p write a test for pre-processing"
  413. echo
  414. echo "argument(s):"
  415. echo " file file containing the test case(s)"
  416. echo " name name for the test case (defaults to file)"
  417. echo " cmd command to be used (defaults to 'sparse \$file')"
  418. }
  419. ##
  420. # do_format([options,] file[, name[, cmd]]) - helps a test writer to format test-suite tags
  421. do_format()
  422. {
  423. def_cmd="$default_cmd"
  424. append=0
  425. linear=0
  426. fail=0
  427. while [ $# -gt 0 ] ; do
  428. case "$1" in
  429. -a)
  430. append=1 ;;
  431. -f)
  432. fail=1 ;;
  433. -l)
  434. def_cmd='test-linearize -Wno-decl $file'
  435. linear=1 ;;
  436. -p)
  437. def_cmd='sparse -E $file' ;;
  438. help|-*)
  439. do_format_help
  440. return 0
  441. ;;
  442. *) break ;;
  443. esac
  444. shift
  445. continue
  446. done
  447. if [ $# -lt 1 -o $# -gt 3 ]; then
  448. do_format_help
  449. return 0
  450. fi
  451. arg_file "$1" || return 1
  452. file="$1"
  453. fname="$2"
  454. [ -z "$fname" ] && fname="$(basename "$1" .c)"
  455. fcmd="$3"
  456. [ -z "$fcmd" ] && fcmd="$def_cmd"
  457. cmd=`eval echo $default_path/$fcmd`
  458. $cmd 1> $file.output.got 2> $file.error.got
  459. fexit_value=$?
  460. [ $append != 0 ] && exec >> $file
  461. cat <<_EOF
  462. /*
  463. * check-name: $fname
  464. _EOF
  465. if [ "$fcmd" != "$default_cmd" ]; then
  466. echo " * check-command: $fcmd"
  467. fi
  468. if [ "$fexit_value" -ne "0" ]; then
  469. echo " * check-exit-value: $fexit_value"
  470. fi
  471. if [ $fail != 0 ]; then
  472. echo " * check-known-to-fail"
  473. fi
  474. if [ $linear != 0 ]; then
  475. echo ' *'
  476. echo ' * check-output-ignore'
  477. echo ' * check-output-contains: xyz\\\\.'
  478. echo ' * check-output-excludes: \\\\.'
  479. fi
  480. for stream in output error; do
  481. if [ -s "$file.$stream.got" ]; then
  482. echo " *"
  483. echo " * check-$stream-start"
  484. cat "$file.$stream.got"
  485. echo " * check-$stream-end"
  486. fi
  487. done
  488. echo " */"
  489. return 0
  490. }
  491. ## allow flags from environment
  492. set -- $SPARSE_TEST_FLAGS "$@"
  493. ## process the flags
  494. while [ "$#" -gt "0" ]; do
  495. case "$1" in
  496. -a|--abort)
  497. abort=1
  498. ;;
  499. -q|--quiet)
  500. vquiet=1
  501. ;;
  502. --args=*)
  503. default_args="${1#--args=}";
  504. ;;
  505. single|--single)
  506. arg_file "$2"
  507. do_test "$2"
  508. case "$?" in
  509. 0) echo "$2 passed !";;
  510. 1) echo "$2 failed !";;
  511. 2) echo "$2 can't be handled by $prog_name";;
  512. esac
  513. exit $failed
  514. ;;
  515. format|--format)
  516. shift
  517. do_format "$@"
  518. exit 0
  519. ;;
  520. help)
  521. do_usage
  522. exit 1
  523. ;;
  524. *.c|*.cdoc)
  525. tests_list="$tests_list $1"
  526. ;;
  527. *)
  528. if [ ! -d "$1" ]; then
  529. do_usage
  530. exit 1
  531. fi
  532. tests_list="$tests_list $(find "$1" -name '*.c' | sort)"
  533. ;;
  534. esac
  535. shift
  536. done
  537. if [ -z "$tests_list" ]; then
  538. tests_list=`find . -name '*.c' | sed -e 's#^\./\(.*\)#\1#' | sort`
  539. fi
  540. do_test_suite
  541. exit $failed