From db8cd8e36771eed98eb638fd0593c978c3da52a9 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Tue, 9 Jan 2018 15:26:39 -0800 Subject: [PATCH] glcpp/tests: Convert shell scripts to a python script This ports glcpp-test.sh and glcpp-test-cr-lf.sh to a python script that accepts arguments for each line ending type. This should allow for better reporting to users. v2: - Use $PYTHON2 to be consistent with other tests in mesa Signed-off-by: Dylan Baker Reviewed-by: Eric Anholt --- .../glsl/glcpp/tests/glcpp-test-cr-lf.sh | 148 +----------- src/compiler/glsl/glcpp/tests/glcpp-test.sh | 121 +--------- src/compiler/glsl/glcpp/tests/glcpp_test.py | 221 ++++++++++++++++++ 3 files changed, 223 insertions(+), 267 deletions(-) create mode 100755 src/compiler/glsl/glcpp/tests/glcpp_test.py diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf.sh b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf.sh index c1e39290d39..c41ee9f93fb 100755 --- a/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf.sh +++ b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf.sh @@ -1,149 +1,3 @@ #!/bin/sh -if [ -z "$srcdir" -o -z "$abs_builddir" ]; then - echo "" - echo "Warning: you're invoking the script manually and things may fail." - echo "Attempting to determine/set srcdir and abs_builddir variables." - echo "" - - # Should point to `dirname Makefile.glsl.am` - srcdir=./../../../ - cd `dirname "$0"` - # Should point to `dirname Makefile` equivalent to the above. - abs_builddir=`pwd`/../../../ -fi - -testdir="$srcdir/glsl/glcpp/tests" -glcpp_test="$srcdir/glsl/glcpp/tests/glcpp-test.sh" - -total=0 -pass=0 - -# This supports a pipe that doesn't destroy the exit status of first command -# -# http://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another -stdintoexitstatus() { - read exitstatus - return $exitstatus -} - -run_test () -{ - cmd="$1" - - total=$((total+1)) - - if [ "$VERBOSE" = "yes" ]; then - if $cmd; then - echo "PASS" - pass=$((pass+1)) - else - echo "FAIL" - fi - else - # This is "$cmd | tail -2" but with the exit status of "$cmd" not "tail -2" - if (((($cmd; echo $? >&3) | tail -2 | head -1 >&4) 3>&1) | stdintoexitstatus) 4>&1; then - echo "PASS" - pass=$((pass+1)) - else - echo "FAIL" - fi - fi -} - -usage () -{ - cat <&2 - echo >&2 - usage - exit 1 - ;; - esac -done - -# All tests depend on the .out files being present. So first do a -# normal run of the test suite, (silently) just to create the .out -# files as a side effect. -rm -rf ./subtest-lf -mkdir subtest-lf -for file in "$testdir"/*.c; do - base=$(basename "$file") - cp "$file" subtest-lf -done - -${glcpp_test} --testdir=subtest-lf >/dev/null 2>&1 - -echo "===== Testing with \\\\r line terminators (old Mac format) =====" - -# Prepare test files with '\r' instead of '\n' -rm -rf ./subtest-cr -mkdir subtest-cr -for file in "$testdir"/*.c; do - base=$(basename "$file") - tr "\n" "\r" < "$file" > subtest-cr/"$base" - cp $abs_builddir/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr/"$base".expected -done - -run_test "${glcpp_test} --testdir=subtest-cr" - -echo "===== Testing with \\\\r\\\\n line terminators (DOS format) =====" - -# Prepare test files with '\r\n' instead of '\n' -rm -rf ./subtest-cr-lf -mkdir subtest-cr-lf -for file in "$testdir"/*.c; do - base=$(basename "$file") - sed -e 's/$/ /' < "$file" > subtest-cr-lf/"$base" - cp $abs_builddir/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr-lf/"$base".expected -done - -run_test "${glcpp_test} --testdir=subtest-cr-lf" - -echo "===== Testing with \\\\n\\\\r (bizarre, but allowed by GLSL spec.) =====" - -# Prepare test files with '\n\r' instead of '\n' -rm -rf ./subtest-lf-cr -mkdir subtest-lf-cr -for file in "$testdir"/*.c; do - base=$(basename "$file") - sed -e 's/$/ /' < "$file" | tr "\n\r" "\r\n" > subtest-lf-cr/"$base" - cp $abs_builddir/glsl/glcpp/tests/subtest-lf/"$base".out subtest-lf-cr/"$base".expected -done - -run_test "${glcpp_test} --testdir=subtest-lf-cr" - -if [ $total -eq 0 ]; then - echo "Could not find any tests." - exit 1 -fi - -echo "" -echo "$pass/$total tests returned correct results" -echo "" - -if [ "$pass" = "$total" ]; then - exit 0 -else - exit 1 -fi +$PYTHON2 $srcdir/glsl/glcpp/tests/glcpp_test.py $abs_builddir/glsl/glcpp/glcpp $srcdir/glsl/glcpp/tests --windows --oldmac --bizarro diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test.sh b/src/compiler/glsl/glcpp/tests/glcpp-test.sh index 44c9451cf60..3925c4ab8cf 100755 --- a/src/compiler/glsl/glcpp/tests/glcpp-test.sh +++ b/src/compiler/glsl/glcpp/tests/glcpp-test.sh @@ -1,122 +1,3 @@ #!/bin/sh -if [ -z "$srcdir" -o -z "$abs_builddir" ]; then - echo "" - echo "Warning: you're invoking the script manually and things may fail." - echo "Attempting to determine/set srcdir and abs_builddir variables." - echo "" - - # Should point to `dirname Makefile.glsl.am` - srcdir=./../../../ - cd `dirname "$0"` - # Should point to `dirname Makefile` equivalent to the above. - abs_builddir=`pwd`/../../../ -fi - -testdir=$srcdir/glsl/glcpp/tests -outdir=$abs_builddir/glsl/glcpp/tests -glcpp=$abs_builddir/glsl/glcpp/glcpp - -trap 'rm $test.valgrind-errors; exit 1' INT QUIT - -usage () -{ - cat < Use tests in the given (default is ".") - --valgrind Run the test suite a second time under valgrind -EOF -} - -test_specific_args () -{ - test="$1" - - tr "\r" "\n" < "$test" | grep 'glcpp-args:' | sed -e 's,^.*glcpp-args: *,,' -} - -# Parse command-line options -for option; do - case "${option}" in - "--help") - usage - exit 0 - ;; - "--valgrind") - do_valgrind=yes - ;; - "--testdir="*) - testdir="${option#--testdir=}" - outdir="${outdir}/${option#--testdir=}" - ;; - *) - echo "Unrecognized option: $option" >&2 - echo >&2 - usage - exit 1 - ;; - esac -done - -total=0 -pass=0 -clean=0 - -mkdir -p $outdir - -echo "====== Testing for correctness ======" -for test in $testdir/*.c; do - out=$outdir/${test##*/}.out - - printf "Testing `basename $test`... " - $glcpp $(test_specific_args $test) < $test > $out 2>&1 - total=$((total+1)) - if cmp $test.expected $out >/dev/null 2>&1; then - echo "PASS" - pass=$((pass+1)) - else - echo "FAIL" - diff -u $test.expected $out - fi -done - -if [ $total -eq 0 ]; then - echo "Could not find any tests." - exit 1 -fi - -echo "" -echo "$pass/$total tests returned correct results" -echo "" - -if [ "$do_valgrind" = "yes" ]; then - echo "====== Testing for valgrind cleanliness ======" - for test in $testdir/*.c; do - printf "Testing `basename $test` with valgrind..." - valgrind --error-exitcode=31 --log-file=$test.valgrind-errors $glcpp $(test_specific_args $test) < $test >/dev/null 2>&1 - if [ "$?" = "31" ]; then - echo "ERRORS" - cat $test.valgrind-errors - else - echo "CLEAN" - clean=$((clean+1)) - rm $test.valgrind-errors - fi - done - - echo "" - echo "$pass/$total tests returned correct results" - echo "$clean/$total tests are valgrind-clean" -fi - -if [ "$pass" = "$total" ] && [ "$do_valgrind" != "yes" ] || [ "$pass" = "$total" ]; then - exit 0 -else - exit 1 -fi - +$PYTHON2 $srcdir/glsl/glcpp/tests/glcpp_test.py $abs_builddir/glsl/glcpp/glcpp $srcdir/glsl/glcpp/tests --unix diff --git a/src/compiler/glsl/glcpp/tests/glcpp_test.py b/src/compiler/glsl/glcpp/tests/glcpp_test.py new file mode 100755 index 00000000000..f07c2414ea2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/glcpp_test.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python2 +# encoding=utf-8 +# Copyright © 2018 Intel Corporation + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +"""Run glcpp tests with various line endings.""" + +from __future__ import print_function +import argparse +import difflib +import io +import os +import subprocess +import sys +import tempfile + + +def arg_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('glcpp', help='Path to the he glcpp binary.') + parser.add_argument('testdir', help='Path to tests and expected output.') + parser.add_argument('--unix', action='store_true', help='Run tests for Unix style newlines') + parser.add_argument('--windows', action='store_true', help='Run tests for Windows/Dos style newlines') + parser.add_argument('--oldmac', action='store_true', help='Run tests for Old Mac (pre-OSX) style newlines') + parser.add_argument('--bizarro', action='store_true', help='Run tests for Bizarro world style newlines') + parser.add_argument('--valgrind', action='store_true', help='Run with valgrind for errors') + return parser.parse_args() + + +def parse_test_file(filename, nl_format): + """Check for any special arguments and return them as a list.""" + with open(filename) as f: + for l in f.read().split(nl_format): + if 'glcpp-args:' in l: + return l.split('glcpp-args:')[1].strip().split() + return [] + + +def test_output(glcpp, filename, expfile, nl_format='\n'): + """Test that the output of glcpp is what we expect.""" + extra_args = parse_test_file(filename, nl_format) + + with open(filename, 'rb') as f: + proc = subprocess.Popen( + [glcpp] + extra_args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE) + actual, _ = proc.communicate(f.read()) + + with open(expfile, 'rb') as f: + expected = f.read() + + if actual == expected: + return (True, []) + return (False, difflib.unified_diff(actual.splitlines(), expected.splitlines())) + + +def _valgrind(glcpp, filename): + """Run valgrind and report any warnings.""" + extra_args = parse_test_file(filename, nl_format='\n') + + try: + _, tmpfile = tempfile.mkstemp() + with open(filename, 'rb') as f: + proc = subprocess.Popen( + ['valgrind', '--error-exitcode=31', '--log-file', tmpfile, glcpp] + extra_args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE) + proc.communicate(f.read()) + if proc.returncode != 31: + return (True, []) + with open(tmpfile, 'rb') as f: + contents = f.read() + return (False, contents) + finally: + os.unlink(tmpfile) + + +def test_unix(args): + """Test files with unix style (\n) new lines.""" + total = 0 + passed = 0 + + print('============= Testing for Correctness (Unix) =============') + for filename in os.listdir(args.testdir): + if not filename.endswith('.c'): + continue + + print( '{}:'.format(os.path.splitext(filename)[0]), end=' ') + total += 1 + + testfile = os.path.join(args.testdir, filename) + valid, diff = test_output(args.glcpp, testfile, testfile + '.expected') + if valid: + passed += 1 + print('PASS') + else: + print('FAIL') + for l in diff: + print(l, file=sys.stderr) + + print('{}/{}'.format(passed, total), 'tests returned correct results') + return total == passed + + +def _replace_test(args, replace): + """Test files with non-unix style line endings. Print your own header.""" + total = 0 + passed = 0 + + for filename in os.listdir(args.testdir): + if not filename.endswith('.c'): + continue + + print( '{}:'.format(os.path.splitext(filename)[0]), end=' ') + total += 1 + testfile = os.path.join(args.testdir, filename) + try: + _, tmpfile = tempfile.mkstemp() + with io.open(testfile, 'rt') as f: + contents = f.read() + with io.open(tmpfile, 'wt') as f: + f.write(contents.replace('\n', replace)) + valid, diff = test_output( + args.glcpp, tmpfile, testfile + '.expected', nl_format=replace) + finally: + os.unlink(tmpfile) + + if valid: + passed += 1 + print('PASS') + else: + print('FAIL') + for l in diff: + print(l, file=sys.stderr) + + print('{}/{}'.format(passed, total), 'tests returned correct results') + return total == passed + + +def test_windows(args): + """Test files with windows/dos style (\r\n) new lines.""" + print('============= Testing for Correctness (Windows) =============') + return _replace_test(args, '\r\n') + + +def test_oldmac(args): + """Test files with Old Mac style (\r) new lines.""" + print('============= Testing for Correctness (Old Mac) =============') + return _replace_test(args, '\r') + + +def test_bizarro(args): + """Test files with Bizarro world style (\n\r) new lines.""" + # This is allowed by the spec, but why? + print('============= Testing for Correctness (Bizarro) =============') + return _replace_test(args, '\n\r') + + +def test_valgrind(args): + total = 0 + passed = 0 + + print('============= Testing for Valgrind Warnings =============') + for filename in os.listdir(args.testdir): + if not filename.endswith('.c'): + continue + + print( '{}:'.format(os.path.splitext(filename)[0]), end=' ') + total += 1 + valid, log = _valgrind(args.glcpp, os.path.join(args.testdir, filename)) + if valid: + passed += 1 + print('PASS') + else: + print('FAIL') + print(log, file=sys.stderr) + + print('{}/{}'.format(passed, total), 'tests returned correct results') + return total == passed + + +def main(): + args = arg_parser() + + success = True + if args.unix: + success = success and test_unix(args) + if args.windows: + success = success and test_windows(args) + if args.oldmac: + success = success and test_oldmac(args) + if args.bizarro: + success = success and test_bizarro(args) + if args.valgrind: + success = success and test_valgrind(args) + + exit(0 if success else 1) + + +if __name__ == '__main__': + main() -- 2.30.2