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