#!/bin/bash me=${BASH_SOURCE[0]} # Note: for 2.6 sometimes we need to set PYTHON=pytest PYTHON=${PYTHON:-python} typeset -i BATCH=${BATCH:-0} if (( ! BATCH )) ; then isatty=$(/usr/bin/tty 2>/dev/null) if [[ -n $isatty ]] && [[ "$isatty" != 'not a tty' ]] ; then BATCH=0 fi fi function displaytime { local T=$1 local D=$((T/60/60/24)) local H=$((T/60/60%24)) local M=$((T/60%60)) local S=$((T%60)) (( $D > 0 )) && printf '%d days ' $D (( $H > 0 )) && printf '%d hours ' $H (( $M > 0 )) && printf '%d minutes ' $M (( $D > 0 || $H > 0 || $M > 0 )) && printf 'and ' printf '%d seconds\n' $S } # Python version setup FULLVERSION=$(pyenv local) PYVERSION=${FULLVERSION%.*} if [[ $PYVERSION =~ 'pypy' ]] ; then IS_PYPY=1 else IS_PYPY=0 fi if [[ $FULLVERSION =~ pypy([2-3])\.([7-9]) ]]; then MAJOR="${BASH_REMATCH[1]}" MINOR="${BASH_REMATCH[2]}" else MINOR=${FULLVERSION##?.?.} fi STOP_ONERROR=${STOP_ONERROR:-1} typeset -i timeout=15 function timeout_cmd { ( $@ & child=$! trap -- "" SIGTERM ( sleep "$timeout" if ps -p $child >/dev/null ; then echo "" echo >&1 "**Killing ${2}; takes more than $timeout seconds to run" kill -TERM ${child} fi ) & wait "$child" ) } typeset -A SKIP_TESTS case $PYVERSION in 2.4) . ./2.4-exclude.sh ;; 2.5) . ./2.5-exclude.sh ;; 2.6) . ./2.6-exclude.sh ;; 2.7) . ./2.7-exclude.sh ;; 3.0) SKIP_TESTS=( [test_array.py]=1 # Handling of bytestring [test_binascii.py]=1 # handling of bytearray? [test_concurrent_futures.py]=1 # too long to run over 46 seconds by itself [test_datetimetester.py]=1 [test_decimal.py]=1 [test_dis.py]=1 # We change line numbers - duh! [test_fileio.py]=1 ) if (( BATCH )) ; then # Fails in crontab environment? # Figure out what's up here SKIP_TESTS[test_exception_variations.py]=1 fi ;; 3.1) SKIP_TESTS=( [test_concurrent_futures.py]=1 # too long to run over 46 seconds by itself [test_dis.py]=1 # We change line numbers - duh! [test_fileio.py]=1 ) if (( BATCH )) ; then # Fails in crontab environment? # Figure out what's up here SKIP_TESTS[test_exception_variations.py]=1 fi ;; 3.2) . ./3.2-exclude.sh ;; 3.3) . ./3.3-exclude.sh ;; 3.4) . ./3.4-exclude.sh ;; 3.5) . ./3.5-exclude.sh ;; 3.6) . ./3.6-exclude.sh ;; 3.7) . ./3.7-exclude.sh ;; 3.8) . ./3.8-exclude.sh ;; *) SKIP_TESTS=( [test_aepack.py]=1 [audiotests.py]=1 [test_dis.py]=1 # We change line numbers - duh! [test_generators.py]=1 # I think string formatting of docstrings gets in the way. Not sure ) ;; esac # Test directory setup srcdir=$(dirname $me) cd $srcdir fulldir=$(pwd) # DECOMPILER=uncompyle2 DECOMPILER=${DECOMPILER:-"$fulldir/../../bin/uncompyle6"} OPTS=${OPTS:-""} TESTDIR=/tmp/test${PYVERSION} if [[ -e $TESTDIR ]] ; then rm -fr $TESTDIR fi PYENV_ROOT=${PYENV_ROOT:-$HOME/.pyenv} pyenv_local=$(pyenv local) echo Python version is $pyenv_local # pyenv version update for dir in ../ ../../ ; do cp -v .python-version $dir done mkdir $TESTDIR || exit $? if ((IS_PYPY)); then cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib-python/${MAJOR}/test $TESTDIR else cp -r ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test $TESTDIR fi if [[ $PYVERSION == 3.2 ]] ; then cp ${PYENV_ROOT}/versions/${PYVERSION}.${MINOR}/lib/python${PYVERSION}/test/* $TESTDIR cd $TESTDIR else cd $TESTDIR/test fi pyenv local $FULLVERSION export PYTHONPATH=$TESTDIR export PATH=${PYENV_ROOT}/shims:${PATH} DONT_SKIP_TESTS=${DONT_SKIP_TESTS:-0} # Run tests typeset -i i=0 typeset -i allerrs=0 if [[ -n $1 ]] ; then files=$@ typeset -a files_ary=( $(echo $@) ) if (( ${#files_ary[@]} == 1 || DONT_SKIP_TESTS == 1 )) ; then SKIP_TESTS=() fi else files=$(echo test_*.py) fi typeset -i ALL_FILES_STARTTIME=$(date +%s) typeset -i skipped=0 NOT_INVERTED_TESTS=${NOT_INVERTED_TESTS:-1} for file in $files; do # AIX bash doesn't grok [[ -v SKIP... ]] [[ -z ${SKIP_TESTS[$file]} ]] && SKIP_TESTS[$file]=0 if [[ ${SKIP_TESTS[$file]} == ${NOT_INVERTED_TESTS} ]] ; then ((skipped++)) continue fi # If the fails *before* decompiling, skip it! typeset -i STARTTIME=$(date +%s) if [ ! -r $file ]; then echo "Skipping test $file -- not readable. Does it exist?" continue elif ! $PYTHON $file >/dev/null 2>&1 ; then echo "Skipping test $file -- it fails on its own" continue fi typeset -i ENDTIME=$(date +%s) typeset -i time_diff (( time_diff = ENDTIME - STARTTIME)) if (( time_diff > $timeout )) ; then echo "Skipping test $file -- test takes too long to run: $time_diff seconds" continue fi ((i++)) # (( i > 40 )) && break short_name=$(basename $file .py) if ((IS_PYPY)); then decompiled_file=$short_name-${MAJOR}.${MINOR}.pyc else decompiled_file=$short_name-${PYVERSION}.pyc fi $fulldir/compile-file.py $file && \ mv $file{,.orig} && \ echo ========== $(date +%X) Decompiling $file =========== $DECOMPILER $OPTS $decompiled_file > $file rc=$? if (( rc == 0 )) ; then echo ========== $(date +%X) Running $file =========== timeout_cmd $PYTHON $file rc=$? else echo ======= Skipping $file due to compile/decompile errors ======== fi (( rc != 0 && allerrs++ )) if (( STOP_ONERROR && rc )) ; then echo "** Ran $i tests before failure. Skipped $skipped test for known failures. **" exit $allerrs fi done typeset -i ALL_FILES_ENDTIME=$(date +%s) (( time_diff = ALL_FILES_ENDTIME - ALL_FILES_STARTTIME)) printf "Ran $i unit-test files, $allerrs errors; Elapsed time: " displaytime $time_diff echo "Skipped $skipped test for known failures." cd $fulldir/../.. && pyenv local $FULLVERSION exit $allerrs