Adds optional code coverage reporting to run_tests.sh.
[python_utils.git] / tests / run_tests.sh
1 #!/bin/bash
2
3 source /home/scott/bin/color_vars.sh
4
5 ROOT=/home/scott/lib/python_modules
6 DOCTEST=0
7 UNITTEST=0
8 INTEGRATION=0
9 FAILURES=0
10
11 dup() {
12     if [ $# -ne 2 ]; then
13         echo "Usage: dup <string> <count>"
14         return
15     fi
16     local times=$(seq 1 $2)
17     for x in ${times}; do
18         echo -n "$1"
19     done
20 }
21
22 make_header() {
23     if [ $# -ne 2 ]; then
24         echo "Usage: make_header <required title> <color>"
25         return
26     fi
27     local title="$1"
28     local title_len=${#title}
29     title_len=$((title_len + 4))
30     local width=70
31     local left=4
32     local right=$(($width-($title_len+$left)))
33     local color="$2"
34     dup '-' $left
35     echo -ne "[ ${color}${title}${NC} ]"
36     dup '-' $right
37     echo
38 }
39
40 function usage() {
41     echo "Usage: $0 [-a]|[-i][-u][-d] [--coverage]"
42     echo
43     echo "Runs tests under ${ROOT}.  Options control which test types:"
44     echo
45     echo "    -a | --all . . . . . . . . . . . . Run all types of tests"
46     echo "    -d | --doctests  . . . . . . . . . Run doctests"
47     echo "    -u | --unittests . . . . . . . . . Run unittests"
48     echo "    -i | --integration . . . . . . . . Run integration tests"
49     echo
50     exit 1
51 }
52
53 while [[ $# -gt 0 ]]; do
54     key="$1"
55     case $key in
56         -a|--all)
57             DOCTEST=1
58             UNITTEST=1
59             INTEGRATION=1
60             ;;
61         -d|--doctests)
62             DOCTEST=1
63             ;;
64         -u|--unittests)
65             UNITTEST=1
66             ;;
67         -i|--integration)
68             INTEGRATION=1
69             ;;
70         --coverage)
71             COVERAGE=1
72             ;;
73         *)    # unknown option
74             echo "Argument $key was not recognized."
75             echo
76             usage
77             exit 1
78             ;;
79     esac
80     shift
81 done
82
83 if [ $(expr ${DOCTEST} + ${UNITTEST} + ${INTEGRATION}) -eq 0 ]; then
84     usage
85     exit 2
86 fi
87
88 if [ ${COVERAGE} -eq 1 ]; then
89     coverage erase
90 fi
91
92 FAILED_TESTS=""
93 if [ ${DOCTEST} -eq 1 ]; then
94     for doctest in $(grep -lR doctest ${ROOT}/*); do
95         if [[ ${doctest} == *.py ]]; then
96             BASE=$(basename ${doctest})
97             BASE="${BASE} (doctest)"
98             make_header "${BASE}" "${CYAN}"
99             if [ ${COVERAGE} -eq 1 ]; then
100                 OUT=$( coverage run --source ${HOME}/lib --append ${doctest} 2>&1 )
101             else
102                 OUT=$( python3 ${doctest} 2>&1 )
103             fi
104             FAILED=$( echo "${OUT}" | grep '\*\*\*Test Failed\*\*\*' | wc -l )
105             if [ $FAILED == 0 ]; then
106                 echo "OK"
107             else
108                 echo -e "${FAILED}"
109                 FAILURES=$((FAILURES+1))
110                 FAILED_TESTS="${FAILED_TESTS},${BASE} (python3 ${doctest})"
111             fi
112         fi
113     done
114 fi
115
116 if [ ${UNITTEST} -eq 1 ]; then
117     for test in $(find ${ROOT} -name "*_test.py" -print); do
118         BASE=$(basename ${test})
119         BASE="${BASE} (unittest)"
120         make_header "${BASE}" "${GREEN}"
121         if [ ${COVERAGE} -eq 1 ]; then
122             coverage run --source ${HOME}/lib --append ${test} --unittests_ignore_perf
123         else
124             ${test}
125         fi
126         if [ $? -ne 0 ]; then
127             FAILURES=$((FAILURES+1))
128             FAILED_TESTS="${FAILED_TESTS},${BASE} (python3 ${test})"
129         fi
130     done
131 fi
132
133 if [ ${INTEGRATION} -eq 1 ]; then
134     for test in $(find ${ROOT} -name "*_itest.py" -print); do
135         BASE=$(basename ${test})
136         BASE="${BASE} (integration test)"
137         make_header "${BASE}" "${ORANGE}"
138         if [ ${COVERAGE} -eq 1 ]; then
139             coverage run --source ${HOME}/lib --append ${test}
140         else
141             ${test}
142         fi
143         if [ $? -ne 0 ]; then
144             FAILURES=$((FAILURES+1))
145             FAILED_TESTS="${FAILED_TESTS},${BASE} (python3 ${test})"
146         fi
147     done
148 fi
149
150 if [ ${COVERAGE} -eq 1 ]; then
151     make_header "Code Coverage Report" "${GREEN}"
152     coverage report --omit=config-3.8.py --sort=-cover
153 fi
154
155 if [ ${FAILURES} -ne 0 ]; then
156     FAILED_TESTS=$(echo ${FAILED_TESTS} | sed 's/^,/__/g')
157     FAILED_TESTS=$(echo ${FAILED_TESTS} | sed 's/,/\n__/g')
158     if [ ${FAILURES} -eq 1 ]; then
159         echo -e "${RED}There was ${FAILURES} failure:"
160     else
161         echo -e "${RED}There were ${FAILURES} failures:"
162     fi
163     echo "${FAILED_TESTS}"
164     echo -e "${NC}"
165     exit ${FAILURES}
166 else
167     echo -e "${BLACK}${ON_GREEN}Everything looks good.${NC}"
168     exit 0
169 fi