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