summaryrefslogtreecommitdiff
path: root/tools/partest-ack
blob: f7d5063292f1a4c2f4afbd144c10a13febe70b95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env bash
#
# wrapper around partest for fine-grained test selection via ack

declare quiet failed update partest_debug file_regex partest_args ack_args cotouched

[[ $# -gt 0 ]] || {
  cat <<EOM
Usage: $0 <regex> [-dfquvp] [ack options]

  -d          pass --debug to partest
  -f          pass --failed to partest
  -q          DON'T pass --show-log and --show-diff to partest
  -u          pass --update-check to partest
  -v          pass --verbose to partest
  -p <path>   select tests appearing in commits where <path> was also modified

Given a regular expression (and optionally, any arguments accepted by ack)
runs all the tests for which any associated file matches the regex.  Associated
files include .check and .flags files.  Tests in directories will match if any
file matches.  A file can match the regex by its contents or by its name.

You must have ack installed: http://betterthangrep.com/ack-standalone

Examples:

  > tools/partest-ack monad
  % tests-with-matching-paths      ...  2
  % tests-with-matching-code       ...  2
  # 4 tests to run.

  > tools/partest-ack -p src/library/scala/Enumeration.scala
  % tests-modified-in-same-commit  ...  84
  # 84 tests to run.

  > tools/partest-ack -f
  % tests-which-failed             ...  42
  # 42 tests to run.
EOM

  exit 0
}

# The leading : in :achs suppresses some errors. Each letter is a valid
# option. If an option takes an argument, a colon follows it, e.g.
# it would be :ach:s if -h took an argument.
while getopts :fuvdp: opt; do
  case $opt in
    d) partest_debug=true && partest_args="$partest_args --debug" ;;
    f) failed=true && partest_args="$partest_args --failed" ;;
    p) cotouched="$cotouched $OPTARG" ;;
    q) quiet=true ;;
    u) partest_args="$partest_args --update-check" ;;
    v) partest_args="$partest_args --verbose" ;;
    :) echo "Option -$OPTARG requires an argument." >&2 ;;      # this case is called for a missing option argument
    *) echo "Unrecognized argument $OPTARG" ;;                  # this is the catch-all implying an unknown option
  esac
done

shift $((OPTIND-1))
file_regex="$1"
ack_args="$*"

tests () {
  find test/files -mindepth 2 -maxdepth 2 -name '*.scala' -o -type d
}

pathsToTests () {
  for path in $(perl -pe 's#^(test/files/[^/]+/[^/.]+).*$#$1#'); do
    if [[ -d "$path" ]]; then
      echo "$path"
    elif [[ -f "$path.scala" ]]; then
      echo "$path.scala"
    fi
  done | sort -u
}

tests-with-matching-paths() {
  local re="$1"
  for p in $(find test/files -type f); do
    [[ $p =~ $re ]] && echo "$p"
  done
}

tests-which-failed () {
  for f in $(find test/files -name '*.log'); do
    echo ${f%-*}
  done
}

tests-modified-in-same-commit() {
  [[ $# -gt 0 ]] && \
    for rev in $(git rev-list HEAD -- "$@"); do
      git --no-pager show --pretty="format:" --name-only "$rev" -- test/files
    done
}

tests-with-matching-code() {
  ack --noenv --text --files-with-matches "$@" -- test/files
}

countStdout () {
  local -i count=0
  while read line; do
    printf "$line\n"
    count+=1
  done

  printf >&2 " $count\n"
}

testRun () {
  printf >&2 "%% %-30s ... " "$1"
  "$@" | pathsToTests | countStdout
}

allMatches() {
  [[ -n $file_regex ]]  && testRun tests-with-matching-paths $file_regex
  [[ -n $cotouched ]]   && testRun tests-modified-in-same-commit $cotouched
  [[ -n $ack_args ]]    && testRun tests-with-matching-code $ack_args
  [[ -n $failed ]]      && testRun tests-which-failed
}

paths=$(allMatches | sort -u)
[[ -n $quiet ]] || partest_args="--show-diff --show-log $partest_args"

if [[ -z $paths ]] && [[ -z $failed ]]; then
  echo >&2 "No matching tests."
else
  count=$(echo $(echo "$paths" | wc -w))

  # Output a command line which will re-run these same tests.
  echo "# $count tests to run."
  printf "%-52s %s\n" "test/partest $partest_args" "\\"
  for path in $paths; do
    printf "  %-50s %s\n" "$path" "\\"
  done
  echo '  ""'

  test/partest $partest_args $paths
fi