glcpp/tests: Convert shell scripts to a python script
authorDylan Baker <dylan@pnwbakers.com>
Tue, 9 Jan 2018 23:26:39 +0000 (15:26 -0800)
committerDylan Baker <dylan@pnwbakers.com>
Wed, 18 Apr 2018 16:03:57 +0000 (09:03 -0700)
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 <dylan.c.baker@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf.sh
src/compiler/glsl/glcpp/tests/glcpp-test.sh
src/compiler/glsl/glcpp/tests/glcpp_test.py [new file with mode: 0755]

index c1e39290d395daa45495265cf594a4b04383635f..c41ee9f93fb0a5eb9edd7dd074056e2270f5ddbc 100755 (executable)
@@ -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 <<EOF
-Usage: `basename "$0"` [options...]
-
-Run the entire glcpp-test suite several times, each time with each source
-file transformed to use a non-standard line-termination character. Each
-entire run with a different line-termination character is considered a
-single test.
-
-Valid options include:
-
-       -v|--verbose    Print all output from the various sub-tests
-EOF
-}
-
-# Parse command-line options
-for option; do
-    case "${option}" in
-       -v|--verbose)
-           VERBOSE=yes;
-           ;;
-       *)
-           echo "Unrecognized option: $option" >&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/$/\r/' < "$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/$/\r/' < "$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
index 44c9451cf6074e023e3ba18c7cd5436f998d3e58..3925c4ab8cf43add3bb6a3f04a48292436c25189 100755 (executable)
@@ -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 <<EOF
-Usage: `basename "$0"` [options...]
-
-Run the test suite for mesa's GLSL pre-processor.
-
-Valid options include:
-
-       --testdir=<DIR> Use tests in the given <DIR> (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 (executable)
index 0000000..f07c241
--- /dev/null
@@ -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()