summaryrefslogblamecommitdiff
path: root/tools/partest-ack
blob: f7d5063292f1a4c2f4afbd144c10a13febe70b95 (plain) (tree)
1
2
3
4
5
6
7
8



                                                                
                                                                                    


                   







                                                                              









                                                                               



                                         
 


                                                            
 


                                          




        



















































































                                                                                                                   


                                        









                                                             
  
#!/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