blob: 5abf73cefe514341ff5cfa1b4aa86bd651ed0776 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2020 The Tint Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Test runner for executing a test of tests with Tint. The runner will
# find all .wgsl files in the given folder and attempt to convert them
# to each of the backend formats. If the file contains a '.fail.' in the
# name then the runner will expect the file to fail conversion.
import base64
import copy
import difflib
import optparse
import os
import platform
import re
import subprocess
import sys
import tempfile
"""
A single test case to be executed. Stores the path to the test file
and the result of executing the test.
"""
class TestCase:
def __init__(self, input_path, parse_only):
self.input_path = input_path
self.parse_only = parse_only
self.results = {}
def IsExpectedFail(self):
fail_re = re.compile('^.+[\.]fail[\.]wgsl')
return fail_re.match(self.GetInputPath())
def IsParseOnly(self):
return self.parse_only
def GetInputPath(self):
return self.input_path
def GetResult(self, fmt):
return self.results[fmt]
"""
The test runner, will execute a series of test cases and record the
results.
"""
class TestRunner:
def RunTest(self, tc):
"""Runs a single test."""
print("Testing {}".format(tc.GetInputPath()))
cmd = [self.options.test_prog_path]
if tc.IsParseOnly():
cmd += ['--parse-only']
languages = ["wgsl", "spvasm", "msl", "hlsl"]
try:
for lang in languages:
lang_cmd = copy.copy(cmd)
lang_cmd += ['--format', lang]
lang_cmd += [tc.GetInputPath()]
err = subprocess.check_output(lang_cmd,
stderr=subprocess.STDOUT)
except Exception as e:
if not tc.IsExpectedFail():
print("{}".format("".join(map(chr, bytearray(e.output)))))
print(e)
return False
return True
def RunTests(self):
"""Runs a set of test cases"""
for tc in self.test_cases:
result = self.RunTest(tc)
if not tc.IsExpectedFail() and not result:
self.failures.append(tc.GetInputPath())
elif tc.IsExpectedFail() and result:
print("Expected: " + tc.GetInputPath() +
" to fail but passed.")
self.failures.append(tc.GetInputPath())
def SummarizeResults(self):
"""Prints a summarization of the test results to STDOUT"""
if len(self.failures) > 0:
self.failures.sort()
print('\nSummary of Failures:')
for failure in self.failures:
print(failure)
print('')
print('Test cases executed: {}'.format(len(self.test_cases)))
print(' Successes: {}'.format(
(len(self.test_cases) - len(self.failures))))
print(' Failures: {}'.format(len(self.failures)))
print('')
def Run(self):
"""Executes the test runner."""
base_path = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..'))
usage = 'usage: %prog [options] (file)'
parser = optparse.OptionParser(usage=usage)
parser.add_option('--build-dir',
default=os.path.join(base_path, 'out', 'Debug'),
help='path to build directory')
parser.add_option('--test-dir',
default=os.path.join(os.path.dirname(__file__), '..',
'third_party', 'gpuweb-cts',
'src', 'webgpu', 'shader',
'validation', 'wgsl'),
help='path to directory containing test files')
parser.add_option(
'--test-prog-path',
default=None,
help='path to program to test (default build-dir/tint)')
parser.add_option('--parse-only',
action="store_true",
default=False,
help='only parse test cases; do not compile')
self.options, self.args = parser.parse_args()
if self.options.test_prog_path == None:
test_prog = os.path.abspath(
os.path.join(self.options.build_dir, 'tint'))
if not os.path.isfile(test_prog):
print("Cannot find test program {}".format(test_prog))
return 1
self.options.test_prog_path = test_prog
if not os.path.isfile(self.options.test_prog_path):
print("Cannot find test program '{}'".format(
self.options.test_prog_path))
return 1
input_file_re = re.compile('^.+[\.]wgsl')
self.test_cases = []
if self.args:
for filename in self.args:
input_path = os.path.join(self.options.test_dir, filename)
if not os.path.isfile(input_path):
print("Cannot find test file '{}'".format(filename))
return 1
self.test_cases.append(
TestCase(input_path, self.options.parse_only))
else:
for file_dir, _, filename_list in os.walk(self.options.test_dir):
for input_filename in filename_list:
if input_file_re.match(input_filename):
input_path = os.path.join(file_dir, input_filename)
if os.path.isfile(input_path):
self.test_cases.append(
TestCase(input_path, self.options.parse_only))
self.failures = []
self.RunTests()
self.SummarizeResults()
return len(self.failures)
def main():
runner = TestRunner()
return runner.Run()
if __name__ == '__main__':
sys.exit(main())