First Commit

This commit is contained in:
2025-11-18 14:18:26 -07:00
parent 33eb6e3707
commit 27277ec342
6106 changed files with 3571167 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
# Copyright 2020 The Shaderc Authors. All rights reserved.
#
# 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.
add_test(NAME shaderc_expect_unittests
COMMAND ${Python_EXECUTABLE} -m unittest expect_unittest.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_test(NAME shaderc_glslc_test_framework_unittests
COMMAND ${Python_EXECUTABLE} -m unittest glslc_test_framework_unittest.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(${SHADERC_ENABLE_TESTS})
add_test(NAME glslc_tests
COMMAND ${Python_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/glslc_test_framework.py
$<TARGET_FILE:glslc_exe> $<TARGET_FILE:spirv-dis>
--test-dir ${CMAKE_CURRENT_SOURCE_DIR})
endif()

140
3rdparty/shaderc/glslc/test/assembly.py vendored Normal file
View File

@@ -0,0 +1,140 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def assembly_comments():
return """
; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0"""
def empty_main_assembly():
return assembly_comments() + """
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
OpSource ESSL 310
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd"""
def empty_main():
return '#version 310 es\nvoid main() {}'
@inside_glslc_testsuite('SpirvAssembly')
class TestAssemblyFileAsOnlyParameter(expect.ValidNamedObjectFile):
"""Tests that glslc accepts a SPIR-V assembly file as the only parameter."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = [shader]
expected_object_filenames = ('a.spv',)
@inside_glslc_testsuite('SpirvAssembly')
class TestDashCAssemblyFile(expect.ValidObjectFile):
"""Tests that -c works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestAssemblyFileWithOnlyComments(expect.ValidObjectFile):
"""Tests that glslc accepts an assembly file with only comments inside."""
shader = FileShader(assembly_comments(), '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestEmptyAssemblyFile(expect.ValidObjectFile):
"""Tests that glslc accepts an empty assembly file."""
shader = FileShader('', '.spvasm')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestDashEAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
"""Tests that -E works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-E', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestDashSAssemblyFile(expect.SuccessfulReturn, expect.NoGeneratedFiles):
"""Tests that -S works with SPIR-V assembly file."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-S', shader]
@inside_glslc_testsuite('SpirvAssembly')
class TestMultipleAssemblyFiles(expect.ValidObjectFile):
"""Tests that glslc accepts multiple SPIR-V assembly files."""
shader1 = FileShader(empty_main_assembly(), '.spvasm')
shader2 = FileShader(empty_main_assembly(), '.spvasm')
shader3 = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', shader1, shader2, shader3]
@inside_glslc_testsuite('SpirvAssembly')
class TestHybridInputFiles(expect.ValidObjectFile):
"""Tests that glslc accepts a mix of SPIR-V assembly files and
GLSL source files."""
shader1 = FileShader(empty_main_assembly(), '.spvasm')
shader2 = FileShader(empty_main(), '.vert')
shader3 = FileShader(empty_main(), '.frag')
glslc_args = ['-c', shader1, shader2, shader3]
@inside_glslc_testsuite('SpirvAssembly')
class TestShaderStageWithAssemblyFile(expect.ErrorMessage):
"""Tests that assembly files don't work with -fshader-stage"""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
expected_error = [
shader, ": error: #version: Desktop shaders for Vulkan SPIR-V require "
"version 140 or higher\n",
shader, ":2: error: 'extraneous semicolon' :",
" not supported for this version or the enabled extensions\n",
shader, ":2: error: '' : syntax error, unexpected IDENTIFIER\n",
'3 errors generated.\n']
@inside_glslc_testsuite('SpirvAssembly')
class TestStdWithAssemblyFile(expect.ValidObjectFile):
"""Tests that --std= doesn't affect the processing of assembly files."""
shader = FileShader(empty_main_assembly(), '.spvasm')
glslc_args = ['-c', '-std=310es', shader]

View File

@@ -0,0 +1,72 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
"""Classes for conveniently specifying a test environment.
These classes have write() methods that create objects in a test's environment.
For instance, File creates a file, and Directory creates a directory with some
files or subdirectories in it.
Example:
test.environment = Directory('.', [
File('a.vert', 'void main(){}'),
Directory('subdir', [
File('b', 'b content'),
File('c', 'c content')
])
])
In general, these classes don't clean up the disk content they create. They
were written in a test framework that handles clean-up at a higher level.
"""
import os
class Directory:
"""Specifies a directory or a subdirectory."""
def __init__(self, name, content):
"""content is a list of File or Directory objects."""
self.name = name
self.content = content
@staticmethod
def create(path):
"""Creates a directory path if it doesn't already exist."""
try:
os.makedirs(path)
except OSError: # Handles both pre-existence and a racing creation.
if not os.path.isdir(path):
raise
def write(self, parent):
"""Creates a self.name directory within parent (which is a string path) and
recursively writes the content in it.
"""
full_path = os.path.join(parent, self.name)
Directory.create(full_path)
for c in self.content:
c.write(full_path)
class File:
"""Specifies a file by name and content."""
def __init__(self, name, content):
self.name = name
self.content = content
def write(self, directory):
"""Writes content to directory/name."""
with open(os.path.join(directory, self.name), 'w') as f:
f.write(self.content)

View File

@@ -0,0 +1,59 @@
# Copyright 2017 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
@inside_glslc_testsuite('ErrorNoObject')
class ErrorGeneratesNoObjectFile(expect.NoObjectFile,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that on error, no object file is generated."""
shader = FileShader('#version 150\nBad', '.frag')
glslc_args = ['-c', shader]
expected_error_substr = ['syntax error']
@inside_glslc_testsuite('ErrorNoObject')
class FailureToMakeOutputFileIsErrorWithNoOutputFile(
expect.NoNamedOutputFiles,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that if we fail to make an output file, no file is generated,
and we have certain error messages."""
shader = FileShader('#version 150\nvoid main() {}', '.frag')
bad_file = '/file/should/not/exist/today'
glslc_args = ['-c', shader, '-o', bad_file]
expected_output_filenames = [bad_file]
expected_error_substr = ['cannot open output file']
@inside_glslc_testsuite('ErrorNoObject')
class FailureToMakeOutputFileAsCurrentDirIsErrorWithNoOutputFile(
expect.NoNamedOutputFiles,
expect.NoOutputOnStdout,
expect.ErrorMessageSubstr):
"""Tests that if we fail to make an output file because it is the current
directory, then no file is generated, and we have certain error messages."""
shader = FileShader('#version 150\nvoid main() {}', '.frag')
bad_file = '.' # Current directory
glslc_args = ['-c', shader, '-o', bad_file]
expected_output_filenames = [bad_file]
expected_error_substr = ['cannot open output file']

707
3rdparty/shaderc/glslc/test/expect.py vendored Normal file
View File

@@ -0,0 +1,707 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
"""A number of common glslc result checks coded in mixin classes.
A test case can use these checks by declaring their enclosing mixin classes
as superclass and providing the expected_* variables required by the check_*()
methods in the mixin classes.
"""
import difflib
import functools
import os
import re
import subprocess
import sys
from glslc_test_framework import GlslCTest
from builtins import bytes
GLSLANG_GENERATOR_VERSION=11
SHADERC_GENERATOR_NUMBER=13
SHADERC_GENERATOR_WORD=(SHADERC_GENERATOR_NUMBER << 16) + GLSLANG_GENERATOR_VERSION
ASSEMBLER_GENERATOR_WORD=(7<<16)
def convert_to_string(input):
if type(input) is not str:
if sys.version_info[0] == 2:
return input.decode('utf-8')
elif sys.version_info[0] == 3:
return str(input,
encoding='utf-8',
errors='ignore') if input is not None else input
else:
raise Exception(
'Unable to determine if running Python 2 or 3 from {}'.format(
sys.version_info))
else:
return input
def convert_to_unix_line_endings(source):
"""Converts all line endings in source to be unix line endings."""
return source.replace('\r\n', '\n').replace('\r', '\n')
def substitute_file_extension(filename, extension):
"""Substitutes file extension, respecting known shader extensions.
foo.vert -> foo.vert.[extension] [similarly for .frag, .comp, etc.]
foo.glsl -> foo.[extension]
foo.unknown -> foo.[extension]
foo -> foo.[extension]
"""
if filename[-5:] not in ['.vert', '.frag', '.tesc', '.tese',
'.geom', '.comp', '.spvasm']:
return filename.rsplit('.', 1)[0] + '.' + extension
else:
return filename + '.' + extension
def get_object_filename(source_filename):
"""Gets the object filename for the given source file."""
return substitute_file_extension(source_filename, 'spv')
def get_assembly_filename(source_filename):
"""Gets the assembly filename for the given source file."""
return substitute_file_extension(source_filename, 'spvasm')
def verify_file_non_empty(filename):
"""Checks that a given file exists and is not empty."""
if not os.path.isfile(filename):
return False, 'Cannot find file: ' + filename
if not os.path.getsize(filename):
return False, 'Empty file: ' + filename
return True, ''
class ReturnCodeIsZero(GlslCTest):
"""Mixin class for checking that the return code is zero."""
def check_return_code_is_zero(self, status):
if status.returncode:
return False, 'Non-zero return code: {ret}\n'.format(
ret=status.returncode)
return True, ''
class NoOutputOnStdout(GlslCTest):
"""Mixin class for checking that there is no output on stdout."""
def check_no_output_on_stdout(self, status):
if status.stdout:
return False, 'Non empty stdout: {out}\n'.format(out=status.stdout)
return True, ''
class NoOutputOnStderr(GlslCTest):
"""Mixin class for checking that there is no output on stderr."""
def check_no_output_on_stderr(self, status):
if status.stderr:
return False, 'Non empty stderr: {err}\n'.format(err=status.stderr)
return True, ''
class SuccessfulReturn(ReturnCodeIsZero, NoOutputOnStdout, NoOutputOnStderr):
"""Mixin class for checking that return code is zero and no output on
stdout and stderr."""
pass
class NoGeneratedFiles(GlslCTest):
"""Mixin class for checking that there is no file generated."""
def check_no_generated_files(self, status):
all_files = os.listdir(status.directory)
input_files = status.input_filenames
if all([f.startswith(status.directory) for f in input_files]):
all_files = [os.path.join(status.directory, f) for f in all_files]
generated_files = set(all_files) - set(input_files)
if len(generated_files) == 0:
return True, ''
else:
return False, 'Extra files generated: {}'.format(generated_files)
class CorrectBinaryLengthAndPreamble(GlslCTest):
"""Provides methods for verifying preamble for a SPIR-V binary."""
def verify_binary_length_and_header(self, binary, spv_version = 0x10000):
"""Checks that the given SPIR-V binary has valid length and header.
Returns:
False, error string if anything is invalid
True, '' otherwise
Args:
binary: a bytes object containing the SPIR-V binary
spv_version: target SPIR-V version number, with same encoding
as the version word in a SPIR-V header.
"""
def read_word(binary, index, little_endian):
"""Reads the index-th word from the given binary file."""
word = binary[index * 4:(index + 1) * 4]
if little_endian:
word = reversed(word)
return functools.reduce(lambda w, b: (w << 8) | b, word, 0)
def check_endianness(binary):
"""Checks the endianness of the given SPIR-V binary.
Returns:
True if it's little endian, False if it's big endian.
None if magic number is wrong.
"""
first_word = read_word(binary, 0, True)
if first_word == 0x07230203:
return True
first_word = read_word(binary, 0, False)
if first_word == 0x07230203:
return False
return None
num_bytes = len(binary)
if num_bytes % 4 != 0:
return False, ('Incorrect SPV binary: size should be a multiple'
' of words')
if num_bytes < 20:
return False, 'Incorrect SPV binary: size less than 5 words'
preamble = binary[0:19]
little_endian = check_endianness(preamble)
# SPIR-V module magic number
if little_endian is None:
return False, 'Incorrect SPV binary: wrong magic number'
# SPIR-V version number
version = read_word(preamble, 1, little_endian)
# TODO(dneto): Recent Glslang uses version word 0 for opengl_compat
# profile
if version != spv_version and version != 0:
return False, 'Incorrect SPV binary: wrong version number'
# Shaderc-over-Glslang (0x000d....) or
# SPIRV-Tools (0x0007....) generator number
if read_word(preamble, 2, little_endian) != SHADERC_GENERATOR_WORD and \
read_word(preamble, 2, little_endian) != ASSEMBLER_GENERATOR_WORD:
return False, ('Incorrect SPV binary: wrong generator magic '
'number')
# reserved for instruction schema
if read_word(preamble, 4, little_endian) != 0:
return False, 'Incorrect SPV binary: the 5th byte should be 0'
return True, ''
class CorrectObjectFilePreamble(CorrectBinaryLengthAndPreamble):
"""Provides methods for verifying preamble for a SPV object file."""
def verify_object_file_preamble(self, filename, spv_version = 0x10000):
"""Checks that the given SPIR-V binary file has correct preamble."""
success, message = verify_file_non_empty(filename)
if not success:
return False, message
with open(filename, 'rb') as object_file:
object_file.seek(0, os.SEEK_END)
num_bytes = object_file.tell()
object_file.seek(0)
binary = bytes(object_file.read())
return self.verify_binary_length_and_header(binary, spv_version)
return True, ''
class CorrectAssemblyFilePreamble(GlslCTest):
"""Provides methods for verifying preamble for a SPV assembly file."""
def verify_assembly_file_preamble(self, filename):
success, message = verify_file_non_empty(filename)
if not success:
return False, message
with open(filename) as assembly_file:
line1 = assembly_file.readline()
line2 = assembly_file.readline()
line3 = assembly_file.readline()
if (line1 != '; SPIR-V\n' or
line2 != '; Version: 1.0\n' or
(not line3.startswith('; Generator: Google Shaderc over Glslang;'))):
return False, 'Incorrect SPV assembly'
return True, ''
class ValidObjectFile(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.0
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidObjectFile1_3(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.3
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10300)
if not success:
return False, message
return True, ''
class ValidObjectFile1_4(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.4
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10400)
if not success:
return False, message
return True, ''
class ValidObjectFile1_5(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.5
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10500)
if not success:
return False, message
return True, ''
class ValidObjectFile1_6(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid SPIR-V 1.6
object file following the object file naming rule, and there is no output on
stdout/stderr."""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename),
0x10600)
if not success:
return False, message
return True, ''
class ValidObjectFileWithAssemblySubstr(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that every input file generates a valid object
file following the object file naming rule, there is no output on
stdout/stderr, and the disassmbly contains a specified substring per input."""
def check_object_file_disassembly(self, status):
for an_input in status.inputs:
object_filename = get_object_filename(an_input.filename)
obj_file = str(os.path.join(status.directory, object_filename))
success, message = self.verify_object_file_preamble(obj_file)
if not success:
return False, message
cmd = [status.test_manager.disassembler_path, '--no-color', obj_file]
process = subprocess.Popen(
args=cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, cwd=status.directory)
output = process.communicate(None)
disassembly = output[0]
if not isinstance(an_input.assembly_substr, str):
return False, "Missing assembly_substr member"
if bytes(an_input.assembly_substr, 'utf-8') not in disassembly:
return False, ('Incorrect disassembly output:\n{asm}\n'
'Expected substring not found:\n{exp}'.format(
asm=disassembly, exp=an_input.assembly_substr))
return True, ''
class ValidNamedObjectFile(SuccessfulReturn, CorrectObjectFilePreamble):
"""Mixin class for checking that a list of object files with the given
names are correctly generated, and there is no output on stdout/stderr.
To mix in this class, subclasses need to provide expected_object_filenames
as the expected object filenames.
"""
def check_object_file_preamble(self, status):
for object_filename in self.expected_object_filenames:
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidFileContents(GlslCTest):
"""Mixin class to test that a specific file contains specific text
To mix in this class, subclasses need to provide expected_file_contents as
the contents of the file and target_filename to determine the location."""
def check_file(self, status):
target_filename = os.path.join(status.directory, self.target_filename)
if not os.path.isfile(target_filename):
return False, 'Cannot find file: ' + target_filename
with open(target_filename, 'r') as target_file:
file_contents = target_file.read()
if isinstance(self.expected_file_contents, str):
if file_contents == self.expected_file_contents:
return True, ''
return False, ('Incorrect file output: \n{act}\n'
'Expected:\n{exp}'
'With diff:\n{diff}'.format(
act=file_contents,
exp=self.expected_file_contents,
diff='\n'.join(list(difflib.unified_diff(
self.expected_file_contents.split('\n'),
file_contents.split('\n'),
fromfile='expected_output',
tofile='actual_output')))))
elif isinstance(self.expected_file_contents, type(re.compile(''))):
if self.expected_file_contents.search(file_contents):
return True, ''
return False, (
'Incorrect file output: \n{act}\n'
'Expected matching regex pattern:\n{exp}'.format(
act=file_contents,
exp=self.expected_file_contents.pattern))
return False, ('Could not open target file ' + target_filename +
' for reading')
class ValidAssemblyFile(SuccessfulReturn, CorrectAssemblyFilePreamble):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, and there is no output on
stdout/stderr."""
def check_assembly_file_preamble(self, status):
for input_filename in status.input_filenames:
assembly_filename = get_assembly_filename(input_filename)
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
return True, ''
class ValidAssemblyFileWithSubstr(ValidAssemblyFile):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, there is no output on
stdout/stderr, and all assembly files have the given substring specified
by expected_assembly_substr.
To mix in this class, subclasses need to provde expected_assembly_substr
as the expected substring.
"""
def check_assembly_with_substr(self, status):
for input_filename in status.input_filenames:
assembly_filename = get_assembly_filename(input_filename)
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
with open(assembly_filename, 'r') as f:
content = f.read()
if self.expected_assembly_substr not in convert_to_unix_line_endings(content):
return False, ('Incorrect assembly output:\n{asm}\n'
'Expected substring not found:\n{exp}'.format(
asm=content, exp=self.expected_assembly_substr))
return True, ''
class ValidAssemblyFileWithoutSubstr(ValidAssemblyFile):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, there is no output on
stdout/stderr, and no assembly files have the given substring specified
by unexpected_assembly_substr.
To mix in this class, subclasses need to provde unexpected_assembly_substr
as the substring we expect not to see.
"""
def check_assembly_for_substr(self, status):
for input_filename in status.input_filenames:
assembly_filename = get_assembly_filename(input_filename)
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
with open(assembly_filename, 'r') as f:
content = f.read()
if self.unexpected_assembly_substr in convert_to_unix_line_endings(content):
return False, ('Incorrect assembly output:\n{asm}\n'
'Unexpected substring found:\n{unexp}'.format(
asm=content, exp=self.unexpected_assembly_substr))
return True, ''
class ValidNamedAssemblyFile(SuccessfulReturn, CorrectAssemblyFilePreamble):
"""Mixin class for checking that a list of assembly files with the given
names are correctly generated, and there is no output on stdout/stderr.
To mix in this class, subclasses need to provide expected_assembly_filenames
as the expected assembly filenames.
"""
def check_object_file_preamble(self, status):
for assembly_filename in self.expected_assembly_filenames:
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
return True, ''
class ErrorMessage(GlslCTest):
"""Mixin class for tests that fail with a specific error message.
To mix in this class, subclasses need to provide expected_error as the
expected error message.
The test should fail if the subprocess was terminated by a signal.
"""
def check_has_error_message(self, status):
if not status.returncode:
return False, ('Expected error message, but returned success from '
'glslc')
if status.returncode < 0:
# On Unix, a negative value -N for Popen.returncode indicates
# termination by signal N.
# https://docs.python.org/2/library/subprocess.html
return False, ('Expected error message, but glslc was terminated by '
'signal ' + str(status.returncode))
if not status.stderr:
return False, 'Expected error message, but no output on stderr'
if self.expected_error != convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected:\n{exp}'.format(
act=status.stderr, exp=self.expected_error))
return True, ''
class ErrorMessageSubstr(GlslCTest):
"""Mixin class for tests that fail with a specific substring in the error
message.
To mix in this class, subclasses need to provide expected_error_substr as
the expected error message substring.
The test should fail if the subprocess was terminated by a signal.
"""
def check_has_error_message_as_substring(self, status):
if not status.returncode:
return False, ('Expected error message, but returned success from '
'glslc')
if status.returncode < 0:
# On Unix, a negative value -N for Popen.returncode indicates
# termination by signal N.
# https://docs.python.org/2/library/subprocess.html
return False, ('Expected error message, but glslc was terminated by '
'signal ' + str(status.returncode))
if not status.stderr:
return False, 'Expected error message, but no output on stderr'
if self.expected_error_substr not in convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected substring not found in stderr:\n{exp}'.format(
act=status.stderr, exp=self.expected_error_substr))
return True, ''
class WarningMessage(GlslCTest):
"""Mixin class for tests that succeed but have a specific warning message.
To mix in this class, subclasses need to provide expected_warning as the
expected warning message.
"""
def check_has_warning_message(self, status):
if status.returncode:
return False, ('Expected warning message, but returned failure from'
' glslc')
if not status.stderr:
return False, 'Expected warning message, but no output on stderr'
if self.expected_warning != convert_to_unix_line_endings(convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{act}\n'
'Expected:\n{exp}'.format(
act=status.stderr, exp=self.expected_warning))
return True, ''
class ValidObjectFileWithWarning(
NoOutputOnStdout, CorrectObjectFilePreamble, WarningMessage):
"""Mixin class for checking that every input file generates a valid object
file following the object file naming rule, with a specific warning message.
"""
def check_object_file_preamble(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
success, message = self.verify_object_file_preamble(
os.path.join(status.directory, object_filename))
if not success:
return False, message
return True, ''
class ValidAssemblyFileWithWarning(
NoOutputOnStdout, CorrectAssemblyFilePreamble, WarningMessage):
"""Mixin class for checking that every input file generates a valid assembly
file following the assembly file naming rule, with a specific warning
message."""
def check_assembly_file_preamble(self, status):
for input_filename in status.input_filenames:
assembly_filename = get_assembly_filename(input_filename)
success, message = self.verify_assembly_file_preamble(
os.path.join(status.directory, assembly_filename))
if not success:
return False, message
return True, ''
class StdoutMatch(GlslCTest):
"""Mixin class for tests that can expect output on stdout.
To mix in this class, subclasses need to provide expected_stdout as the
expected stdout output.
For expected_stdout, if it's True, then they expect something on stdout but
will not check what it is. If it's a string, expect an exact match. If it's
anything else, expect expected_stdout.search(stdout) to be true.
"""
def check_stdout_match(self, status):
# "True" in this case means we expect something on stdout, but we do not
# care what it is, we want to distinguish this from "blah" which means we
# expect exactly the string "blah".
if self.expected_stdout is True:
if not status.stdout:
return False, 'Expected something on stdout'
elif type(self.expected_stdout) == str:
if self.expected_stdout != convert_to_unix_line_endings(
convert_to_string(status.stdout)):
return False, ('Incorrect stdout output:\n{ac}\n'
'Expected:\n{ex}'.format(
ac=status.stdout, ex=self.expected_stdout))
else:
if not self.expected_stdout.search(convert_to_unix_line_endings(
convert_to_string(status.stdout))):
return False, ('Incorrect stdout output:\n{ac}\n'
'Expected to match regex:\n{ex}'.format(
ac=convert_to_string(status.stdout),
ex=self.expected_stdout.pattern))
return True, ''
class StderrMatch(GlslCTest):
"""Mixin class for tests that can expect output on stderr.
To mix in this class, subclasses need to provide expected_stderr as the
expected stderr output.
For expected_stderr, if it's True, then they expect something on stderr,
but will not check what it is. If it's a string, expect an exact match.
"""
def check_stderr_match(self, status):
# "True" in this case means we expect something on stderr, but we do not
# care what it is, we want to distinguish this from "blah" which means we
# expect exactly the string "blah".
if self.expected_stderr is True:
if not status.stderr:
return False, 'Expected something on stderr'
else:
if self.expected_stderr != convert_to_unix_line_endings(
convert_to_string(status.stderr)):
return False, ('Incorrect stderr output:\n{ac}\n'
'Expected:\n{ex}'.format(
ac=status.stderr, ex=self.expected_stderr))
return True, ''
class StdoutNoWiderThan80Columns(GlslCTest):
"""Mixin class for tests that require stdout to 80 characters or narrower.
To mix in this class, subclasses need to provide expected_stdout as the
expected stdout output.
"""
def check_stdout_not_too_wide(self, status):
if not status.stdout:
return True, ''
else:
for line in status.stdout.splitlines():
if len(line) > 80:
return False, ('Stdout line longer than 80 columns: %s'
% line)
return True, ''
class NoObjectFile(GlslCTest):
"""Mixin class for checking that no input file has a corresponding object
file."""
def check_no_object_file(self, status):
for input_filename in status.input_filenames:
object_filename = get_object_filename(input_filename)
full_object_file = os.path.join(status.directory, object_filename)
print("checking %s" % full_object_file)
if os.path.isfile(full_object_file):
return False, ('Expected no object file, but found: %s'
% full_object_file)
return True, ''
class NoNamedOutputFiles(GlslCTest):
"""Mixin class for checking that no specified output files exist.
The expected_output_filenames member should be full pathnames."""
def check_no_named_output_files(self, status):
for object_filename in self.expected_output_filenames:
if os.path.isfile(object_filename):
return False, ('Expected no output file, but found: %s'
% object_filename)
return True, ''

View File

@@ -0,0 +1,83 @@
# Copyright 2019 The Shaderc Authors. All rights reserved.
#
# 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.
"""Tests for the expect module."""
import expect
from glslc_test_framework import TestStatus
import re
import unittest
class TestStdoutMatchADotC(expect.StdoutMatch):
expected_stdout = re.compile('a.c')
class TestExpect(unittest.TestCase):
def test_get_object_name(self):
"""Tests get_object_filename()."""
source_and_object_names = [('a.vert', 'a.vert.spv'),
('b.frag', 'b.frag.spv'),
('c.tesc', 'c.tesc.spv'),
('d.tese', 'd.tese.spv'),
('e.geom', 'e.geom.spv'),
('f.comp', 'f.comp.spv'),
('file', 'file.spv'), ('file.', 'file.spv'),
('file.uk',
'file.spv'), ('file.vert.',
'file.vert.spv'),
('file.vert.bla',
'file.vert.spv')]
actual_object_names = [
expect.get_object_filename(f[0]) for f in source_and_object_names
]
expected_object_names = [f[1] for f in source_and_object_names]
self.assertEqual(actual_object_names, expected_object_names)
def test_stdout_match_regex_has_match(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'0abc1',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertTrue(test.check_stdout_match(status)[0])
def test_stdout_match_regex_no_match(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'ab',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertFalse(test.check_stdout_match(status)[0])
def test_stdout_match_regex_empty_stdout(self):
test = TestStdoutMatchADotC()
status = TestStatus(
test_manager=None,
returncode=0,
stdout=b'',
stderr=None,
directory=None,
inputs=None,
input_filenames=None)
self.assertFalse(test.check_stdout_match(status)[0])

View File

@@ -0,0 +1,86 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import GlslCTest, inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('FileExtension')
class VerifyVertExtension(expect.ValidObjectFile):
"""Tests glslc accepts vertex shader extension (.vert)."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyFragExtension(expect.ValidObjectFile):
"""Tests glslc accepts fragment shader extension (.frag)."""
shader = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyTescExtension(expect.ValidObjectFile):
"""Tests glslc accepts tessellation control shader extension (.tesc)."""
shader = FileShader(
'#version 440 core\n layout(vertices = 3) out;\n void main() {}',
'.tesc')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyTeseExtension(expect.ValidObjectFile):
"""Tests glslc accepts tessellation evaluation shader extension (.tese)."""
shader = FileShader(
'#version 440 core\n layout(triangles) in;\n void main() {}', '.tese')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyGeomExtension(expect.ValidObjectFile):
"""Tests glslc accepts geomtry shader extension (.geom)."""
shader = FileShader(
'#version 150 core\n layout (triangles) in;\n'
'layout (line_strip, max_vertices = 4) out;\n void main() {}',
'.geom')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class VerifyCompExtension(expect.ValidObjectFile):
"""Tests glslc accepts compute shader extension (.comp)."""
shader = FileShader(empty_es_310_shader(), '.comp')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('FileExtension')
class InvalidExtension(expect.ErrorMessage):
"""Tests the error message if a file extension cannot be determined."""
shader = FileShader('#version 150\n', '.fraga')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': file not recognized: File format not recognized\n"]

View File

@@ -0,0 +1,355 @@
#!/usr/bin/env python
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
"""Manages and runs tests from the current working directory.
This will traverse the current working directory and look for python files that
contain subclasses of GlslCTest.
If a class has an @inside_glslc_testsuite decorator, an instance of that
class will be created and serve as a test case in that testsuite. The test
case is then run by the following steps:
1. A temporary directory will be created.
2. The glslc_args member variable will be inspected and all placeholders in it
will be expanded by calling instantiate_for_glslc_args() on placeholders.
The transformed list elements are then supplied as glslc arguments.
3. If the environment member variable exists, its write() method will be
invoked.
4. All expected_* member variables will be inspected and all placeholders in
them will be expanded by calling instantiate_for_expectation() on those
placeholders. After placeholder expansion, if the expected_* variable is
a list, its element will be joined together with '' to form a single
string. These expected_* variables are to be used by the check_*() methods.
5. glslc will be run with the arguments supplied in glslc_args.
6. All check_*() member methods will be called by supplying a TestStatus as
argument. Each check_*() method is expected to return a (Success, Message)
pair where Success is a boolean indicating success and Message is an error
message.
7. If any check_*() method fails, the error message is outputted and the
current test case fails.
If --leave-output was not specified, all temporary files and directories will
be deleted.
"""
import argparse
import fnmatch
import inspect
import os
import shutil
import subprocess
import sys
import tempfile
from collections import defaultdict
from placeholder import PlaceHolder
EXPECTED_BEHAVIOR_PREFIX = 'expected_'
VALIDATE_METHOD_PREFIX = 'check_'
def get_all_variables(instance):
"""Returns the names of all the variables in instance."""
return [v for v in dir(instance) if not callable(getattr(instance, v))]
def get_all_methods(instance):
"""Returns the names of all methods in instance."""
return [m for m in dir(instance) if callable(getattr(instance, m))]
def get_all_superclasses(cls):
"""Returns all superclasses of a given class. Omits root 'object' superclass.
Returns:
A list of superclasses of the given class. The order guarantees that
* A Base class precedes its derived classes, e.g., for "class B(A)", it
will be [..., A, B, ...].
* When there are multiple base classes, base classes declared first
precede those declared later, e.g., for "class C(A, B), it will be
[..., A, B, C, ...]
"""
classes = []
for superclass in cls.__bases__:
for c in get_all_superclasses(superclass):
if c is not object and c not in classes:
classes.append(c)
for superclass in cls.__bases__:
if superclass is not object and superclass not in classes:
classes.append(superclass)
return classes
def get_all_test_methods(test_class):
"""Gets all validation methods.
Returns:
A list of validation methods. The order guarantees that
* A method defined in superclass precedes one defined in subclass,
e.g., for "class A(B)", methods defined in B precedes those defined
in A.
* If a subclass has more than one superclass, e.g., "class C(A, B)",
then methods defined in A precedes those defined in B.
"""
classes = get_all_superclasses(test_class)
classes.append(test_class)
all_tests = [m for c in classes
for m in get_all_methods(c)
if m.startswith(VALIDATE_METHOD_PREFIX)]
unique_tests = []
for t in all_tests:
if t not in unique_tests:
unique_tests.append(t)
return unique_tests
class GlslCTest:
"""Base class for glslc test cases.
Subclasses define test cases' facts (shader source code, glslc command,
result validation), which will be used by the TestCase class for running
tests. Subclasses should define glslc_args (specifying glslc command
arguments), and at least one check_*() method (for result validation) for
a full-fledged test case. All check_*() methods should take a TestStatus
parameter and return a (Success, Message) pair, in which Success is a
boolean indicating success and Message is an error message. The test passes
iff all check_*() methods returns true.
Often, a test case class will delegate the check_* behaviors by inheriting
from other classes.
"""
def name(self):
return self.__class__.__name__
class TestStatus:
"""A struct for holding run status of a test case."""
def __init__(self, test_manager, returncode, stdout, stderr, directory, inputs, input_filenames):
self.test_manager = test_manager
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
# temporary directory where the test runs
self.directory = directory
# List of inputs, as PlaceHolder objects.
self.inputs = inputs
# the names of input shader files (potentially including paths)
self.input_filenames = input_filenames
class GlslCTestException(Exception):
"""GlslCTest exception class."""
pass
def inside_glslc_testsuite(testsuite_name):
"""Decorator for subclasses of GlslCTest.
This decorator checks that a class meets the requirements (see below)
for a test case class, and then puts the class in a certain testsuite.
* The class needs to be a subclass of GlslCTest.
* The class needs to have glslc_args defined as a list.
* The class needs to define at least one check_*() methods.
* All expected_* variables required by check_*() methods can only be
of bool, str, or list type.
* Python runtime will throw an exception if the expected_* member
attributes required by check_*() methods are missing.
"""
def actual_decorator(cls):
if not inspect.isclass(cls):
raise GlslCTestException('Test case should be a class')
if not issubclass(cls, GlslCTest):
raise GlslCTestException(
'All test cases should be subclasses of GlslCTest')
if 'glslc_args' not in get_all_variables(cls):
raise GlslCTestException('No glslc_args found in the test case')
if not isinstance(cls.glslc_args, list):
raise GlslCTestException('glslc_args needs to be a list')
if not any([
m.startswith(VALIDATE_METHOD_PREFIX)
for m in get_all_methods(cls)]):
raise GlslCTestException(
'No check_*() methods found in the test case')
if not all([
isinstance(v, (bool, str, list))
for v in get_all_variables(cls)]):
raise GlslCTestException(
'expected_* variables are only allowed to be bool, str, or '
'list type.')
cls.parent_testsuite = testsuite_name
return cls
return actual_decorator
class TestManager:
"""Manages and runs a set of tests."""
def __init__(self, executable_path, disassembler_path):
self.executable_path = executable_path
self.disassembler_path = disassembler_path
self.num_successes = 0
self.num_failures = 0
self.num_tests = 0
self.leave_output = False
self.tests = defaultdict(list)
def notify_result(self, test_case, success, message):
"""Call this to notify the manager of the results of a test run."""
self.num_successes += 1 if success else 0
self.num_failures += 0 if success else 1
counter_string = str(
self.num_successes + self.num_failures) + '/' + str(self.num_tests)
print('%-10s %-40s ' % (counter_string, test_case.test.name()) +
('Passed' if success else '-Failed-'))
if not success:
print(' '.join(test_case.command))
print(message)
def add_test(self, testsuite, test):
"""Add this to the current list of test cases."""
self.tests[testsuite].append(TestCase(test, self))
self.num_tests += 1
def run_tests(self):
for suite in self.tests:
print('Glslc test suite: "{suite}"'.format(suite=suite))
for x in self.tests[suite]:
x.runTest()
class TestCase:
"""A single test case that runs in its own directory."""
def __init__(self, test, test_manager):
self.test = test
self.test_manager = test_manager
self.inputs = [] # inputs, as PlaceHolder objects.
self.file_shaders = [] # filenames of shader files.
self.stdin_shader = None # text to be passed to glslc as stdin
def setUp(self):
"""Creates environment and instantiates placeholders for the test case."""
self.directory = tempfile.mkdtemp(dir=os.getcwd())
glslc_args = self.test.glslc_args
# Instantiate placeholders in glslc_args
self.test.glslc_args = [
arg.instantiate_for_glslc_args(self)
if isinstance(arg, PlaceHolder) else arg
for arg in self.test.glslc_args]
# Get all shader files' names
self.inputs = [arg for arg in glslc_args if isinstance(arg, PlaceHolder)]
self.file_shaders = [arg.filename for arg in self.inputs]
if 'environment' in get_all_variables(self.test):
self.test.environment.write(self.directory)
expectations = [v for v in get_all_variables(self.test)
if v.startswith(EXPECTED_BEHAVIOR_PREFIX)]
# Instantiate placeholders in expectations
for expectation_name in expectations:
expectation = getattr(self.test, expectation_name)
if isinstance(expectation, list):
expanded_expections = [
element.instantiate_for_expectation(self)
if isinstance(element, PlaceHolder) else element
for element in expectation]
setattr(
self.test, expectation_name,
''.join(expanded_expections))
elif isinstance(expectation, PlaceHolder):
setattr(self.test, expectation_name,
expectation.instantiate_for_expectation(self))
def tearDown(self):
"""Removes the directory if we were not instructed to do otherwise."""
if not self.test_manager.leave_output:
shutil.rmtree(self.directory)
def runTest(self):
"""Sets up and runs a test, reports any failures and then cleans up."""
self.setUp()
success = False
message = ''
try:
self.command = [self.test_manager.executable_path]
self.command.extend(self.test.glslc_args)
process = subprocess.Popen(
args=self.command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
cwd=self.directory)
output = process.communicate(self.stdin_shader)
test_status = TestStatus(
self.test_manager,
process.returncode, output[0], output[1],
self.directory, self.inputs, self.file_shaders)
run_results = [getattr(self.test, test_method)(test_status)
for test_method in get_all_test_methods(
self.test.__class__)]
success, message = list(zip(*run_results))
success = all(success)
message = '\n'.join(message)
except Exception as e:
success = False
message = str(e)
self.test_manager.notify_result(self, success, message)
self.tearDown()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('glslc', metavar='path/to/glslc', type=str, nargs=1,
help='Path to glslc')
parser.add_argument('spirvdis', metavar='path/to/glslc', type=str, nargs=1,
help='Path to spirv-dis')
parser.add_argument('--leave-output', action='store_const', const=1,
help='Do not clean up temporary directories')
parser.add_argument('--test-dir', nargs=1,
help='Directory to gather the tests from')
args = parser.parse_args()
default_path = sys.path
root_dir = os.getcwd()
if args.test_dir:
root_dir = args.test_dir[0]
manager = TestManager(args.glslc[0], args.spirvdis[0])
if args.leave_output:
manager.leave_output = True
for root, _, filenames in os.walk(root_dir):
for filename in fnmatch.filter(filenames, '*.py'):
if filename.endswith('unittest.py'):
# Skip unit tests, which are for testing functions of
# the test framework.
continue
sys.path = default_path
sys.path.append(root)
try:
mod = __import__(os.path.splitext(filename)[0])
for _, obj, in inspect.getmembers(mod):
if inspect.isclass(obj) and hasattr(obj, 'parent_testsuite'):
manager.add_test(obj.parent_testsuite, obj())
except:
print("Failed to load " + filename)
raise
manager.run_tests()
if manager.num_failures > 0:
sys.exit(-1)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,159 @@
# Copyright 2019 The Shaderc Authors. All rights reserved.
#
# 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.
"""Tests for the glslc_test_framework module."""
from glslc_test_framework import get_all_test_methods, get_all_superclasses
import unittest
# Classes to be used in testing get_all_{superclasses|test_methods}()
class Root:
def check_root(self):
pass
class A(Root):
def check_a(self):
pass
class B(Root):
def check_b(self):
pass
class C(Root):
def check_c(self):
pass
class D(Root):
def check_d(self):
pass
class E(Root):
def check_e(self):
pass
class H(B, C, D):
def check_h(self):
pass
class I(E):
def check_i(self):
pass
class O(H, I):
def check_o(self):
pass
class U(A, O):
def check_u(self):
pass
class X(U, A):
def check_x(self):
pass
class R1:
def check_r1(self):
pass
class R2:
def check_r2(self):
pass
class Multi(R1, R2):
def check_multi(self):
pass
class TestSpirvTestFramework(unittest.TestCase):
def test_get_all_superclasses(self):
self.assertEqual(get_all_superclasses(A), [Root])
self.assertEqual(get_all_superclasses(B), [Root])
self.assertEqual(get_all_superclasses(C), [Root])
self.assertEqual(get_all_superclasses(D), [Root])
self.assertEqual(get_all_superclasses(E), [Root])
self.assertEqual(get_all_superclasses(H), [Root, B, C, D])
self.assertEqual(get_all_superclasses(I), [Root, E])
self.assertEqual(get_all_superclasses(O), [Root, B, C, D, E, H, I])
self.assertEqual(get_all_superclasses(
U), [Root, B, C, D, E, H, I, A, O])
self.assertEqual(get_all_superclasses(
X), [Root, B, C, D, E, H, I, A, O, U])
self.assertEqual(get_all_superclasses(Multi), [R1, R2])
def test_get_all_methods(self):
self.assertEqual(get_all_test_methods(A), ['check_root', 'check_a'])
self.assertEqual(get_all_test_methods(B), ['check_root', 'check_b'])
self.assertEqual(get_all_test_methods(C), ['check_root', 'check_c'])
self.assertEqual(get_all_test_methods(D), ['check_root', 'check_d'])
self.assertEqual(get_all_test_methods(E), ['check_root', 'check_e'])
self.assertEqual(
get_all_test_methods(H),
['check_root', 'check_b', 'check_c', 'check_d', 'check_h'])
self.assertEqual(get_all_test_methods(
I), ['check_root', 'check_e', 'check_i'])
self.assertEqual(
get_all_test_methods(O), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_o'
])
self.assertEqual(
get_all_test_methods(U), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_a', 'check_o', 'check_u'
])
self.assertEqual(
get_all_test_methods(X), [
'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h',
'check_i', 'check_a', 'check_o', 'check_u', 'check_x'
])
self.assertEqual(
get_all_test_methods(Multi), ['check_r1', 'check_r2', 'check_multi'])

555
3rdparty/shaderc/glslc/test/include.py vendored Normal file
View File

@@ -0,0 +1,555 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import SpecializedString
from environment import File, Directory
@inside_glslc_testsuite('Include')
class VerifyIncludeOneSibling(expect.StdoutMatch):
"""Tests #including a sibling file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b"\n'),
File('b', 'content b\n')])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "b"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyIncludeNotFound(expect.ErrorMessage):
"""Tests #including a not existing sibling file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b"\n')])
glslc_args = ['-E', 'a.vert']
expected_error = [
"a.vert:3: error: '#include' : Cannot find or open include file. for header name: b\n",
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeOneSibling(expect.ValidObjectFile):
"""Tests #including a sibling file via full compilation."""
environment = Directory('.', [
File('a.vert', '#version 140\nvoid foo(){}\n#include "b"\n'),
File('b', 'void main(){foo();}\n')])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeWithoutNewline(expect.ErrorMessageSubstr):
"""Tests a #include without a newline."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b"'),
File('b', 'content b\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = 'expected newline after header name: b'
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeWithoutNewline(expect.ValidObjectFile):
"""Tests a #include without a newline via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
void main
#include "b"
"""),
File('b',
"""#define PAR ()
PAR{}
""")])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeTwoSiblings(expect.StdoutMatch):
"""Tests #including two sibling files."""
environment = Directory('.', [
File('b.vert', '#version 140\n#include "a"\ncontent b\n#include "c"\n'),
File('a', 'content a\n'),
File('c', 'content c\n')])
glslc_args = ['-E', 'b.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "b.vert"
#line 0 "a"
content a
#line 2 "b.vert"
content b
#line 0 "c"
content c
#line 4 "b.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeTwoSiblings(expect.ValidObjectFile):
"""Tests #including two sibling files via full compilation."""
environment = Directory('.', [
File('b.vert',
"""#version 140
#include "a"
void bfun(){afun();}
#include "c"
"""),
File('a',
"""void afun(){}
#define BODY {}
"""),
File('c', 'void main() BODY\n')])
glslc_args = ['b.vert']
@inside_glslc_testsuite('Include')
class VerifyNestedIncludeAmongSiblings(expect.StdoutMatch):
"""Tests #include inside #included sibling files."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b"\ncontent a\n'),
File('b', 'content b\n#include "c"\n'),
File('c', 'content c\n')])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b"
content b
#line 0 "c"
content c
#line 2 "b"
#line 2 "a.vert"
content a
"""
@inside_glslc_testsuite('Include')
class VerifyCompileNestedIncludeAmongSiblings(expect.ValidObjectFile):
"""Tests #include inside #included sibling files via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "b"
void main(){cfun();}
"""),
File('b',
"""void bfun() BODY
#include "c"
"""),
File('c',
"""#define BF bfun()
void cfun(){BF;}
""")])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeSubdir(expect.StdoutMatch):
"""Tests #including a file from a subdirectory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a1\n#include "subdir/a"\ncontent a2\n'),
Directory('subdir', [File('a', 'content suba\n')])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a1
#line 0 "subdir/a"
content suba
#line 3 "a.vert"
content a2
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeSubdir(expect.ValidObjectFile):
"""Tests #including a file from a subdirectory via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "subdir/a"
void afun()BODY
"""),
Directory('subdir', [File('a', 'void main() BODY\n')])])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class VerifyIncludeDeepSubdir(expect.StdoutMatch):
"""Tests #including a file from a subdirectory nested a few levels down."""
environment = Directory('.', [
File('a.vert',
'#version 140\ncontent a1\n#include "dir/subdir/subsubdir/a"\ncontent a2\n'),
Directory('dir', [
Directory('subdir', [
Directory('subsubdir', [File('a', 'content incl\n')])])])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a1
#line 0 "dir/subdir/subsubdir/a"
content incl
#line 3 "a.vert"
content a2
"""
@inside_glslc_testsuite('Include')
class VerifyCompileIncludeDeepSubdir(expect.ValidObjectFile):
"""Tests #including a file from a subdirectory nested a few levels down
via full compilation."""
environment = Directory('.', [
File('a.vert',
"""#version 140
#define BODY {}
#include "dir/subdir/subsubdir/a"
void afun()BODY
"""),
Directory('dir', [
Directory('subdir', [
Directory('subsubdir', [File('a', 'void main() BODY\n')])])])])
glslc_args = ['a.vert']
@inside_glslc_testsuite('Include')
class TestWrongPoundVersionInIncludingFile(expect.ValidObjectFileWithWarning):
"""Tests that warning message for #version directive in the including file
has the correct filename."""
environment = Directory('.', [
File('a.vert', '#version 100000000\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-c', '-std=400', 'a.vert']
expected_warning = [
'a.vert: warning: (version, profile) forced to be (400, none),'
' while in source code it is (100000000, none)\n'
'1 warning generated.\n'
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
# TODO(dneto): I'm not sure what the expected result should be.
@inside_glslc_testsuite('Include')
class TestWrongPoundVersionInIncludedFile(expect.ErrorMessage):
"""Tests that warning message for #version directive in the included file
has the correct filename."""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 10000000\n')])
glslc_args = ['-E', 'a.vert']
expected_error = [
"b.glsl:1: error: '#version' : must occur first in shader\n",
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyRelativeInclude(expect.StdoutMatch):
"""Tests #including a relative sibling."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
File('c.glsl', 'content c\n')
])])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyNestedRelativeInclude(expect.StdoutMatch):
"""Tests #including a relative child file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "bar/c.glsl"\ncontent b\n'),
Directory('bar', [
File('c.glsl', 'content c\n')
])
])
])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/bar/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeIncludeWithDashI(expect.StdoutMatch):
"""Tests #including a relative file from a -I directory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "bar/b.glsl"\n'),
Directory('foo', [
Directory('bar', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
]),
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/bar/b.glsl"
#line 0 "foo/c.glsl"
content c
#line 1 "foo/bar/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeOverridesDashI(expect.StdoutMatch):
"""Tests that relative includes override -I parameters."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('b.glsl', 'content base_b\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n'),
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "b.glsl"
content base_b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeParent(expect.StdoutMatch):
"""Tests #including a parent file."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('c.glsl', 'content c\n'),
Directory('foo', [
File('b.glsl', '#include "../c.glsl"\ncontent b\n')
])
])
glslc_args = ['-E', 'a.vert', '-Ifoo']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/../c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeNeighbourDirectory(expect.StdoutMatch):
"""Tests #including a relative file in a neighbour directory."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
Directory('foo', [
File('b.glsl', '#include "../bar/c.glsl"\ncontent b\n')
]),
Directory('bar', [
File('c.glsl', 'content c\n')
])
])
glslc_args = ['-E', 'a.vert']
expected_stdout = \
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "foo/b.glsl"
#line 0 "foo/../bar/c.glsl"
content c
#line 1 "foo/b.glsl"
content b
#line 3 "a.vert"
"""
@inside_glslc_testsuite('Include')
class VerifyRelativeOnlyToSelf(expect.ErrorMessage):
"""Tests that a relative includes are only relative to yourself."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "foo/b.glsl"\n'),
File('c.glsl', 'content c\n'),
Directory('foo', [
File('b.glsl', '#include "c.glsl"\ncontent b\n')
]),
])
glslc_args = ['-E', 'a.vert']
expected_error = [
"foo/b.glsl:1: error: '#include' : "
'Cannot find or open include file. for header name: c.glsl\n',
'1 error generated.\n'
]
@inside_glslc_testsuite('Include')
class VerifyRelativeFromAbsolutePath(expect.StdoutMatch):
"""Tests that absolute files can relatively include."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
File('b.glsl', 'content b\n')
])
glslc_args = ['-E', SpecializedString('$directory/a.vert')]
expected_stdout = SpecializedString(
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "$directory/a.vert"
content a
#line 0 "$directory/b.glsl"
content b
#line 3 "$directory/a.vert"
""")
@inside_glslc_testsuite('Include')
class VerifyDashIAbsolutePath(expect.StdoutMatch):
"""Tests that -I parameters can be absolute paths."""
environment = Directory('.', [
File('a.vert', '#version 140\ncontent a\n#include "b.glsl"\n'),
Directory('foo', {
File('b.glsl', 'content b\n')
})
])
glslc_args = ['-E', 'a.vert', '-I', SpecializedString('$directory/foo')]
expected_stdout = SpecializedString(
"""#version 140
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
content a
#line 0 "$directory/foo/b.glsl"
content b
#line 3 "a.vert"
""")

303
3rdparty/shaderc/glslc/test/line.py vendored Normal file
View File

@@ -0,0 +1,303 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from environment import Directory, File
from glslc_test_framework import inside_glslc_testsuite
@inside_glslc_testsuite('#line')
class TestPoundVersion310InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior of version 310
(specifying the line number for the next line) when we find a
#version 310 directive in the including file."""
environment = Directory('.', [
File('a.vert', '#version 310 es\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundVersion150InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior of version 150
(specifying the line number for itself) when we find a #version 150
directive in the including file."""
environment = Directory('.', [
File('a.vert', '#version 150\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundVersionSyntaxErrorInIncludingFile(expect.ErrorMessageSubstr):
"""Tests that error message for #version directive has the correct
filename and line number."""
environment = Directory('.', [
File('a.vert', '#version abc def\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"a.vert:1: error: '#version' : must occur first in shader\n",
"a.vert:1: error: '#version' : must be followed by version number\n",
"a.vert:1: error: '#version' : bad profile name; use es, core, or "
"compatibility\n",
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
@inside_glslc_testsuite('#line')
class TestPoundVersion310InIncludedFile(expect.ErrorMessageSubstr):
"""Tests that #line directives follows the behavior of version 310
(specifying the line number for the next line) when we find a
#version 310 directive in the included file."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 310 es\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"b.glsl:1: error: '#version' : must occur first in shader\n"
]
# TODO(antiagainst): now #version in included files results in an error.
# Fix this after #version in included files are supported.
@inside_glslc_testsuite('#line')
class TestPoundVersion150InIncludedFile(expect.ErrorMessageSubstr):
"""Tests that #line directives follows the behavior of version 150
(specifying the line number for itself) when we find a #version 150
directive in the included file."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\nvoid main() {}'),
File('b.glsl', '#version 150\n')])
glslc_args = ['-E', 'a.vert']
expected_error_substr = [
"b.glsl:1: error: '#version' : must occur first in shader\n"
]
@inside_glslc_testsuite('#line')
class TestSpaceAroundPoundVersion310InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that spaces around #version & #include directive doesn't matter."""
environment = Directory('.', [
File('a.vert', '\t # \t version 310 \t es\n#\tinclude "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestSpaceAroundPoundVersion150InIncludingFile(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that spaces around #version & #include directive doesn't matter."""
environment = Directory('.', [
File('a.vert', ' \t #\t\tversion\t 150\t \n# include \t "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedVersion310(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=310es', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 2 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedVersion150(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line."""
environment = Directory('.', [
File('a.vert', '#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=150', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#extension GL_GOOGLE_include_directive : enable
#line 0 "a.vert"
#line 0 "b.glsl"
void main() { }
#line 1 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestPoundLineWithForcedDifferentVersion(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line directives follows the behavior for the version
specified via command-line, even if there is a version specification
in the source code."""
environment = Directory('.', [
File('a.vert', '#version 150\n#include "b.glsl"\n'),
File('b.glsl', 'void main() {}\n')])
glslc_args = ['-E', '-std=310es', 'a.vert']
expected_stderr = ''
expected_stdout = \
"""#version 150
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 1 "b.glsl"
void main() { }
#line 3 "a.vert"
"""
@inside_glslc_testsuite('#line')
class TestErrorsFromMultipleFiles(expect.ErrorMessage):
"""Tests that errors from different files have the correct error message
filename specification."""
including_file = '''#version 310 es
#include "error.glsl"
int no_return() {}
#include "main.glsl"
'''
environment = Directory('.', [
File('a.vert', including_file),
File('error.glsl', 'int unknown_identifier(int) { return a; }'),
File('main.glsl', 'void main() {\n int b = 1.5;\n}')])
glslc_args = ['-c', 'a.vert']
expected_error = [
"error.glsl:1: error: 'a' : undeclared identifier\n",
"error.glsl:1: error: 'return' : type does not match, or is not "
"convertible to, the function's return type\n",
"a.vert:3: error: '' : function does not return a value: no_return\n",
"main.glsl:2: error: '=' : cannot convert from ' const float' to "
"' temp highp int'\n",
"4 errors generated.\n"]
@inside_glslc_testsuite('#line')
class TestExplicitPoundLineWithPoundInclude(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that #line works correctly in the presence of #include (which
itself will generate some #line directives."""
including_file = '''#version 310 es
#line 10000 "injected.glsl"
int plus1(int a) { return a + 1; }
#include "inc.glsl"
int plus2(int a) { return a + 2; }
#line 55555
#include "main.glsl"
'''
environment = Directory('.', [
File('a.vert', including_file),
File('inc.glsl', 'int inc(int a) { return a + 1; }'),
File('main.glsl', 'void main() {\n gl_Position = vec4(1.);\n}')])
glslc_args = ['-E', 'a.vert']
expected_stderr = ''
expected_stdout = '''#version 310 es
#extension GL_GOOGLE_include_directive : enable
#line 1 "a.vert"
#line 10000 "injected.glsl"
int plus1(int a) { return a + 1; }
#line 1 "inc.glsl"
int inc(int a) { return a + 1; }
#line 10002 "injected.glsl"
int plus2(int a) { return a + 2; }
#line 55555
#line 1 "main.glsl"
void main() {
gl_Position = vec4(1.);
}
#line 55556 "injected.glsl"
'''

View File

@@ -0,0 +1,311 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('ErrorMessages')
class MultipleErrors(expect.ErrorMessage):
"""Test Multiple error messages generated."""
shader = FileShader('#version 140\nint main() {}', '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: 'int' : entry point cannot return a value\n",
shader, ":2: error: '' : function does not return a value: main\n",
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class OneError(expect.ErrorMessage):
"""Tests that only one error message is generated correctly."""
shader = FileShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class ManyLineError(expect.ErrorMessage):
"""Tests that only one error message is generated correctly."""
shader = FileShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ":12: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class GlobalWarning(expect.WarningMessage):
"""Tests that a warning message without file/line number is emitted."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n1 warning generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedGlobalWarning(expect.SuccessfulReturn):
"""Tests that warning messages without file/line numbers are suppressed
with -w."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-w']
@inside_glslc_testsuite('ErrorMessages')
class GlobalWarningAsError(expect.ErrorMessage):
"""Tests that with -Werror an error warning message without file/line
number is emitted instead of a warning."""
shader = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-Werror']
expected_error= [
shader, ': error: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningOnLine(expect.WarningMessage):
"""Tests that a warning message with a file/line number is emitted."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader]
expected_warning = [
shader, ':2: warning: attribute deprecated in version 130; ',
'may be removed in future release\n1 warning generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningOnLine(expect.SuccessfulReturn):
"""Tests that a warning message with a file/line number is suppressed in the
presence of -w."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w']
@inside_glslc_testsuite('ErrorMessages')
class WarningOnLineAsError(expect.ErrorMessage):
"""Tests that with -Werror an error message with a file/line
number is emitted instead of a warning."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-Werror']
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAndError(expect.ErrorMessage):
"""Tests that both warnings and errors are emitted together."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader]
expected_error = [
shader, ':2: warning: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'1 warning and 2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningAndError(expect.ErrorMessage):
"""Tests that only warnings are suppressed in the presence of -w."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w']
expected_error = [
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAsErrorAndError(expect.ErrorMessage):
"""Tests that with -Werror an warnings and errors are emitted as errors."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
int main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-Werror']
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader, ":3: error: 'int' : entry point cannot return a value\n",
shader, ":3: error: '' : function does not return a value: main\n",
'3 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class StdinErrorMessages(expect.StdoutMatch, expect.StderrMatch):
"""Tests that error messages using input from stdin are correct."""
shader = StdinShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""")
glslc_args = ['-c', '-fshader-stage=vertex', shader]
expected_stdout = ''
expected_stderr = [
"<stdin>:2: error: '' : function does not return a value: a\n",
'1 error generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class WarningAsErrorMultipleFiles(expect.ErrorMessage):
"""Tests that with -Werror multiple files emit errors instead of warnings.
"""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
shader2 = FileShader(
"""#version 550
void main() {
}
""", '.vert')
glslc_args = ['-c', '-std=400', shader, '-Werror', shader2]
expected_error = [
shader, ':2: error: attribute deprecated in version 130; ',
'may be removed in future release\n',
shader2, ': error: (version, profile) forced to be (400, none),'
' while in source code it is (550, none)\n',
'2 errors generated.\n']
@inside_glslc_testsuite('ErrorMessages')
class SuppressedWarningAsError(expect.SuccessfulReturn):
"""Tests that nothing is returned in the presence of -w -Werror."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-c', shader, '-w', '-Werror']
@inside_glslc_testsuite('ErrorMessages')
class MultipleSuppressed(expect.SuccessfulReturn):
"""Tests that multiple -w arguments are supported."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-w', '-c', shader, '-w', '-w', '-w']
@inside_glslc_testsuite('ErrorMessages')
class MultipleSuppressedFiles(expect.SuccessfulReturn):
"""Tests that -w suppresses warnings from all files."""
shader = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
shader2 = FileShader(
"""#version 400
layout(location = 0) attribute float x;
void main() {
}
""", '.vert')
glslc_args = ['-w', '-c', shader, shader2]

View File

@@ -0,0 +1,365 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDNoArg(expect.ErrorMessage):
"""Tests -D without macroname."""
glslc_args = ['-D']
expected_error = [
"glslc: error: argument to '-D' is missing\n",
'glslc: error: no input files\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDXeqY(expect.ValidObjectFile):
"""Tests -DX=Y."""
shader = FileShader('#version 150\nvoid main(){X=vec4(1.);}', '.vert')
glslc_args = ['-c', '-DX=gl_Position', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDXeq(expect.ValidObjectFile):
"""Tests -DX=."""
shader = FileShader('#version 150\nvoid main(){X}', '.vert')
glslc_args = ['-c', '-DX=', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDX(expect.ValidObjectFile):
"""Tests -DX."""
shader = FileShader('#version 150\nvoid main(){X}', '.vert')
glslc_args = ['-c', '-DX', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDeq(expect.ErrorMessage):
"""Tests -D=.
This is actually allowed by clang, though the resulting #define
causes a preprocessing error.
"""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
glslc_args = ['-c', '-D=', shader]
# TODO(antiagainst): figure out what should we report as the line number
# for errors in predefined macros and fix here.
expected_error = [
"<command line>:2: error: '#define' : must be followed by macro name\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestMultipleDashCapD(expect.ValidObjectFile):
"""Tests multiple -D occurrences."""
shader = FileShader('#version 150\nvoid main(){X Y a=Z;}', '.vert')
glslc_args = ['-c', '-DX', '-DY=int', '-DZ=(1+2)', shader]
@inside_glslc_testsuite('OptionCapD')
class TestMultipleDashCapDOfSameName(expect.ValidObjectFile):
"""Tests multiple -D occurrences with same macro name."""
shader = FileShader('#version 150\nvoid main(){X Y a=Z;}', '.vert')
glslc_args = ['-c', '-DX=main', '-DY=int', '-DZ=(1+2)', '-DX', shader]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDGL_(expect.ErrorMessage):
"""Tests that we cannot -D macros beginning with GL_."""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
glslc_args = ['-DGL_ES=1', shader]
expected_error = [
"glslc: error: names beginning with 'GL_' cannot be "
'defined: -DGL_ES=1\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDReservedMacro(expect.WarningMessage):
"""Tests that we cannot -D GLSL's predefined macros."""
shader = FileShader('#version 150\nvoid main(){}', '.vert')
# Consecutive underscores are banned anywhere in the name.
glslc_args = [
'-D__LINE__=1', '-Dmid__dle', '-Dend__', '-D_single_is_valid_', shader]
w = 'glslc: warning: names containing consecutive underscores are reserved: '
expected_warning = [w, '-D__LINE__=1\n', w, '-Dmid__dle\n', w, '-Dend__\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithVersion(expect.ErrorMessage):
"""Tests -D works well when #version is present."""
shader = FileShader(
"""#version 310 es
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":3: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithCommentBeforeVersion(expect.ErrorMessage):
"""Tests -D works well with #version preceded by comments."""
shader = FileShader(
"""// comment 1
/*
* comment 2
*/
#version 450 core
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithCommentAfterVersion(expect.ErrorMessage):
"""Tests -D works well with #version followed by comments."""
shader = FileShader(
"""
#version 150 core /*
comment
*/
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', shader]
expected_error = [
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStd(expect.ErrorMessageSubstr):
"""Tests -D works well with -std."""
shader = FileShader('void main(){X}\nvoid foo(){Y}', '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=310es', shader]
expected_error_substr = [
shader, ":2: error: 'return' : void function cannot return a value\n",
'1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStdAndVersion(expect.ErrorMessage):
"""Tests -D works well with both -std and #version."""
shader = FileShader(
"""#version 310 es
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=450core', shader]
expected_error = [
shader, ': warning: (version, profile) forced to be (450, ',
'core), while in source code it is (310, es)\n',
shader, ":3: error: 'return' : void function cannot return a value\n",
'1 warning and 1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashStdAndVersionAndComments(expect.ErrorMessage):
"""Tests -D works well with -std, #version, and comments around it."""
shader = FileShader(
"""// comment before
#version 310 es /* comment after
*/
void main(){X}
void foo(){Y}""", '.vert')
glslc_args = ['-DX=', '-DY=return 3;', '-std=450core', shader]
expected_error = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n',
shader, ":7: error: 'return' : void function cannot return a value\n",
'1 warning and 1 error generated.\n']
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashE(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E outputs expanded -D macros."""
shader = FileShader(
"""
void main(){Y}
""", '.vert')
glslc_args = ['-DY=return 3;', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEIfDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX #ifdefs correctly."""
shader = FileShader(
"""
#ifdef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEIfNDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX #ifndefs correctly."""
shader = FileShader(
"""
#ifndef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { int x; }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEEqIfDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX= #ifdefs correctly."""
shader = FileShader(
"""
#ifdef X
void f() { }
#else
void f() { int x; }
#endif
void main() { return 3; }
""", '.vert')
glslc_args = ['-DX=', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEEqIfNDef(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -DX= #ifndefs correctly."""
shader = FileShader(
"""
#ifndef X
void f() { }
#else
void f() { int x; }
#endif
void main(){ return 3; }
""", '.vert')
glslc_args = ['-DX=', '-E', '-std=450core', shader]
expected_stdout = [
"""
void f() { int x; }
void main() { return 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashEFunctionMacro(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes -D function macros correctly."""
shader = FileShader(
"""
void main(){ return FOO(3); }
""", '.vert')
glslc_args = ['-DFOO(x)=(2*x+1)*x*x', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return(2 * 3 + 1) * 3 * 3; }
"""]
@inside_glslc_testsuite('OptionCapD')
class TestDashCapDWithDashENestedMacro(expect.ReturnCodeIsZero,
expect.StdoutMatch):
"""Tests -E processes referencing -D options correctly."""
shader = FileShader(
"""
void main() { return X; }
""", '.vert')
glslc_args = ['-DY=4', '-DX=Y', '-E', '-std=450core', shader]
expected_stdout = [
"""
void main() { return 4; }
"""]

View File

@@ -0,0 +1,348 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('OptionCapE')
class TestDashCapENoDefs(expect.StdoutMatch):
"""Tests -E without any defines."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEGlslFileAccepted(expect.StdoutMatch):
"""Tests -E if we provide a .glsl file without an explicit stage."""
shader = FileShader('#version 140\nvoid main(){}', '.glsl')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapESingleDefine(expect.StdoutMatch):
"""Tests -E with command-line define."""
shader = FileShader('#version 140\nvoid main(){ int a = X; }', '.vert')
expected_stdout = '#version 140\nvoid main() { int a = 4; }\n'
glslc_args = ['-DX=4', '-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEExpansion(expect.StdoutMatch):
"""Tests -E with macro expansion."""
shader = FileShader('''#version 140
#define X 4
void main() {
int a = X;
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
int a = 4;
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEFunctionMacro(expect.StdoutMatch):
"""Tests -E with function-style macro expansion."""
shader = FileShader('''#version 140
#define X(A) 4+A
void main() {
int a = X(1);
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
int a = 4 + 1;
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEPragma(expect.StdoutMatch):
"""Tests -E to make sure pragmas get retained."""
shader = FileShader('''#version 140
#pragma optimize(off)
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#pragma optimize(off)
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEExtension(expect.StdoutMatch):
"""Tests -E to make sure extensions get retained."""
shader = FileShader('''#version 140
#extension foo: require
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#extension foo : require
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapELine(expect.StdoutMatch):
"""Tests -E to make sure line numbers get retained."""
shader = FileShader('''#version 140
#define X 4
#line X
#line 2 3
void main() {
}
''', '.vert')
expected_stdout = '''#version 140
#line 4
#line 2 3
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEError(expect.ErrorMessage):
"""Tests -E to make sure #errors get retained."""
shader = FileShader('''#version 140
#if 1
#error This is an error
#endif
void main() {
}
''', '.vert')
expected_error = [
shader, ':3: error: \'#error\' : This is an error\n',
'1 error generated.\n']
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdin(expect.StdoutMatch):
"""Tests to make sure -E works with stdin."""
shader = StdinShader('''#version 140
void main() {
}
''')
expected_stdout = '''#version 140
void main() {
}
'''
glslc_args = ['-E', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdinDoesNotRequireShaderStage(expect.StdoutMatch):
"""Tests to make sure -E works with stdin even when no shader-stage
is specified."""
shader = StdinShader('''#version 140
void main() {
}
''')
expected_stdout = '''#version 140
void main() {
}
'''
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEMultipleFiles(expect.StdoutMatch):
"""Tests to make sure -E works with multiple files."""
shader = StdinShader('''#version 140
void main() {
}
''')
shader2 = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', '-fshader-stage=vertex', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEMultipleFilesWithoutStage(expect.StdoutMatch):
"""Tests to make sure -E works with multiple files even if we do not
specify a stage."""
shader = StdinShader('''#version 140
void main() {
}
''')
shader2 = FileShader('''#version 140
void function() {
}
''', '.glsl')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEOutputFile(expect.SuccessfulReturn, expect.ValidFileContents):
"""Tests to make sure -E works with output files."""
shader = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_file_contents = '''#version 140
void function() {
}
'''
target_filename = 'foo'
glslc_args = ['-E', shader, '-ofoo']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithS(expect.StdoutMatch):
"""Tests -E in the presence of -S."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', '-S', shader]
@inside_glslc_testsuite('OptionCapE')
class TestMultipileDashCapE(expect.StdoutMatch):
"""Tests that using -E multiple times works."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = ['-E', '-E', shader, '-E']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEAfterFile(expect.StdoutMatch):
"""Tests that using -E after the filename also works."""
shader = FileShader('#version 140\nvoid main(){}', '.vert')
expected_stdout = '#version 140\nvoid main() { }\n'
glslc_args = [shader, '-E']
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithDashC(expect.StdoutMatch):
"""Tests to make sure -E works in the presence of -c."""
shader = FileShader('''#version 140
void main() {
}
''', '.vert')
shader2 = FileShader('''#version 140
void function() {
}
''', '.vert')
expected_stdout = '''#version 140
void main() {
}
#version 140
void function() {
}
'''
glslc_args = ['-E', '-c', shader, shader2]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEWithPPErrors(expect.ErrorMessage):
"""Tests to make sure -E outputs error messages for preprocessing errors."""
shader = FileShader('''#version 310 es
#extension s enable // missing :
#defin A // Bad define
#if X // In glsl X must be defined for X to work.
// Lack of endif.
void main() {
}
''', '.vert')
expected_error = [
shader, ':2: error: \'#extension\' : \':\' missing after extension',
' name\n',
shader, ':3: error: \'#\' : invalid directive: defin\n',
shader, ':4: error: \'preprocessor evaluation\' : undefined macro in',
' expression not allowed in es profile X\n',
shader, ':8: error: \'\' : missing #endif\n',
'4 errors generated.\n']
glslc_args = ['-E', shader]
@inside_glslc_testsuite('OptionCapE')
class TestDashCapEStdinErrors(expect.ErrorMessage):
"""Tests that -E outputs error messages correctly for stdin input."""
shader = StdinShader('''#version 310 es
#extension s enable // missing :
void main() {
}
''')
expected_error = [
'<stdin>:2: error: \'#extension\' : \':\' missing after extension',
' name\n',
'1 error generated.\n']
glslc_args = ['-E', shader]

View File

@@ -0,0 +1,754 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import os.path
import sys
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
from glslc_test_framework import GlslCTest
MINIMAL_SHADER = '#version 140\nvoid main() {}'
EMPTY_SHADER_IN_CURDIR = Directory('.', [File('shader.vert', MINIMAL_SHADER)])
EMPTY_SHADER_IN_SUBDIR = Directory('subdir',
[File('shader.vert', MINIMAL_SHADER)])
def process_test_specified_dependency_info_rules(test_specified_rules):
"""A helper function to process the expected dependency info rules
specified in tests before checking the actual dependency rule output.
This is required because the filename and path of temporary files created
through FileShader is unknown at the time the expected dependency info rules
are declared.
Note this function process the given rule list in-place.
"""
for rule in test_specified_rules:
# If the 'target' value is not a hard-coded file name but a
# FileShader, we need its full path, append extension to it and
# strip the directory component from it to get the complete target
# name.
if isinstance(rule['target'], FileShader):
rule['target'] = rule['target'].filename
if 'target_extension' in rule:
if rule['target_extension'] is not None:
rule['target'] = rule['target'] + rule['target_extension']
rule.pop('target_extension')
rule['target'] = os.path.basename(rule['target'])
# The dependency set may have FileShader too, we need to replace
# them with their absolute paths.
dependent_file_name_set = set()
for dependent_file in rule['dependency']:
if isinstance(dependent_file, FileShader):
dependent_file_name_set.add(dependent_file.filename)
else:
dependent_file_name_set.add(dependent_file)
rule['dependency'] = dependent_file_name_set
def parse_text_rules(text_lines):
""" A helper function to read text lines and construct and returns a list of
dependency rules which can be used for comparison.
The list is built with the text order. Each rule is described in the
following way:
{'target': <target name>, 'dependency': <set of dependent filenames>}
"""
rules = []
for line in text_lines:
if line.strip() == "":
continue
rule = {'target': line.split(': ')[0].strip(),
'dependency': set(line.split(': ')[-1].strip().split(' '))}
rules.append(rule)
return rules
class DependencyInfoStdoutMatch(GlslCTest):
"""Mixin class for tests that can expect dependency info in Stdout.
To mix in this class, the subclass needs to provide
dependency_rules_expected as a list of dictionaries, each dictionary
describes one expected make rule for a target file. A expected rule should
be specified in the following way:
rule = {'target': <target name>,
'target_extension': <.spv, .spvasm or None>,
'dependency': <dependent file names>}
The 'target_extension' field is optional, its value will be appended to
'target' to get complete target name.
And the list 'dependency_rules_expected' is a list of such rules and the
order of the rules does matter.
"""
def check_stdout_dependency_info(self, status):
if not status.stdout:
return False, 'Expect dependency rules on stdout'
if sys.version_info[0] == 2:
rules = parse_text_rules(status.stdout.decode('utf-8').split('\n'))
elif sys.version_info[0] == 3:
rules = parse_text_rules(str(status.stdout,
encoding='utf-8',
errors='ignore').split('\n'))
process_test_specified_dependency_info_rules(
self.dependency_rules_expected)
if self.dependency_rules_expected != rules:
return False, ('Incorrect dependency info:\n{ac_rules}\n'
'Expected:\n{ex_rules}\n'
'Stdout output:\n{ac_stdout}\n'.format(
ac_rules=rules,
ex_rules=self.dependency_rules_expected,
ac_stdout=status.stdout))
return True, ''
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathNoInclude(DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in relative path.
e.g. glslc -M shader.vert
=> shader.vert.spv: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert']
dependency_rules_expected = [{'target': "shader.vert.spv",
'dependency': {"shader.vert"}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputAbsolutePathNoInclude(DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in absolute path.
e.g. glslc -M /usr/local/shader.vert
=> shader.vert.spv: /usr/local/shader.vert
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-M', shader]
dependency_rules_expected = [{'target': shader,
'target_extension': '.spv',
'dependency': {shader}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does contain #include and is
represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert b.vert
"""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.vert"\nvoid main(){}\n'),
File('b.vert', 'void foo(){}\n'),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithIncludeSubdir(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does #include another file in a
subdirectory of current directory and is represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert include/b.vert
"""
environment = Directory('.', [
File('a.vert', ('#version 140\n#include "include/b.vert"'
'\nvoid main(){}\n')),
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'include/b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithDashI(DependencyInfoStdoutMatch):
"""Tests -M with single input file works with -I option. The #include
directive does not specify 'include/' for the file to be include.
e.g. glslc -M a.vert -I include
=> a.vert.spv: a.vert include/b.vert
"""
environment = Directory('.', [
File('a.vert', ('#version 140\n#include "b.vert"'
'\nvoid main(){}\n')),
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
glslc_args = ['-M', 'a.vert', '-I', 'include']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert', 'include/b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputRelativePathWithNestedInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file under nested #include case. The input file
is represented in relative path.
e.g. glslc -M a.vert
=> a.vert.spv: a.vert b.vert c.vert
"""
environment = Directory('.', [
File('a.vert', '#version 140\n#include "b.vert"\nvoid main(){}\n'),
File('b.vert', 'void foo(){}\n#include "c.vert"\n'),
File('c.vert', 'void bar(){}\n'),
])
glslc_args = ['-M', 'a.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency':
{'a.vert', 'b.vert', 'c.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMultipleInputRelativePathNoInclude(
DependencyInfoStdoutMatch):
"""Tests -M with multiple input file which don't contain #include and are
represented in relative paths.
e.g. glslc -M a.vert b.vert
=> a.vert.spv: a.vert
b.vert.spv: b.vert
"""
environment = Directory('.', [
File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER),
])
glslc_args = ['-M', 'a.vert', 'b.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert'}},
{'target': 'b.vert.spv',
'dependency': {'b.vert'}}, ]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMultipleInputAbsolutePathNoInclude(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which doesn't contain #include and is
represented in absolute path.
e.g. glslc -M /usr/local/a.vert /usr/local/b.vert
=> a.vert.spv: /usr/local/a.vert
b.vert.spv: /usr/local/b.vert
"""
shader_a = FileShader(MINIMAL_SHADER, '.vert')
shader_b = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-M', shader_a, shader_b]
dependency_rules_expected = [{'target': shader_a,
'target_extension': '.spv',
'dependency': {shader_a}},
{'target': shader_b,
'target_extension': '.spv',
'dependency': {shader_b}}, ]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDashCapMT(DependencyInfoStdoutMatch):
"""Tests -MT works with -M. User can specify the target object name in the
generated dependency info.
e.g. glslc -M shader.vert -MT target
=> target: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert', '-MT', 'target']
dependency_rules_expected = [{'target': 'target',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMInputAbsolutePathWithInclude(DependencyInfoStdoutMatch):
"""Tests -M have included files represented in absolute paths when the input
file is represented in absolute path.
E.g. Assume a.vert has '#include "b.vert"'
glslc -M /usr/local/a.vert
=> a.vert.spv: /usr/local/a.vert /usr/local/b.vert
"""
environment = Directory('.', [File('b.vert', 'void foo(){}\n')])
shader_main = FileShader(
'#version 140\n#include "b.vert"\nvoid main(){}\n', '.vert')
glslc_args = ['-M', shader_main]
dependency_rules_expected = [{
'target': shader_main,
'target_extension': '.spv',
'dependency': {shader_main}
# The dependency here is not complete. we can not get the absolute path
# of b.vert here. It will be added in check_stdout_dependency_info()
}]
def check_stdout_dependency_info(self, status):
# Add the absolute path of b.vert to the dependency set
self.dependency_rules_expected[0]['dependency'].add(os.path.dirname(
self.shader_main.filename) + '/b.vert')
return DependencyInfoStdoutMatch.check_stdout_dependency_info(self,
status)
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMSingleInputAbsolutePathWithIncludeSubdir(
DependencyInfoStdoutMatch):
"""Tests -M with single input file which does #include another file in a
subdirectory of current directory and is represented in absolute path.
e.g. glslc -M /usr/local/a.vert
=> a.vert.spv: /usr/local/a.vert /usr/local/include/b.vert
"""
environment = Directory('.', [
Directory('include', [File('b.vert', 'void foo(){}\n')]),
])
shader_main = FileShader('#version 140\n#include "include/b.vert"\n',
'.vert')
glslc_args = ['-M', shader_main]
dependency_rules_expected = [{
'target': shader_main,
'target_extension': '.spv',
'dependency': {shader_main}
# The dependency here is not complete. we can not get the absolute
# path of include/b.vert here. It will be added in
# check_stdout_dependency_info()
}]
def check_stdout_dependency_info(self, status):
# Add the absolute path of include/b.vert to the dependency set
self.dependency_rules_expected[0]['dependency'].add(os.path.dirname(
self.shader_main.filename) + '/include/b.vert')
return DependencyInfoStdoutMatch.check_stdout_dependency_info(self,
status)
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMOverridesOtherModes(DependencyInfoStdoutMatch):
"""Tests -M overrides other compiler mode options, includeing -E, -c and -S.
"""
environment = Directory('.', [
File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER),
])
glslc_args = ['-M', '-E', '-c', '-S', 'a.vert', 'b.vert']
dependency_rules_expected = [{'target': 'a.vert.spv',
'dependency': {'a.vert'}},
{'target': 'b.vert.spv',
'dependency': {'b.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMEquivalentToCapM(DependencyInfoStdoutMatch):
"""Tests that -MM behaves as -M.
e.g. glslc -MM shader.vert
=> shader.vert.spv: shader.vert
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MM', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMImpliesDashCapE(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -E, a .glsl file without an explict stage should
not generate an error.
e.g. glslc -M shader.glsl
=> shader.spv: shader.glsl
<no error message should be generated>
"""
environment = Directory('.', [File('shader.glsl', MINIMAL_SHADER)])
glslc_args = ['-M', 'shader.glsl']
dependency_rules_expected = [{'target': 'shader.spv',
'dependency': {'shader.glsl'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMImpliesDashW(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -w, a deprecated attribute should not generate
warning message.
e.g. glslc -M shader.vert
=> shader.vert.spv: shader.vert
<no warning message should be generated>
"""
environment = Directory('.', [File(
'shader.vert', """#version 400
layout(location=0) attribute float x;
void main() {}""")])
glslc_args = ['-M', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMImpliesDashCapE(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -M implies -E, a .glsl file without an explict stage should
not generate an error.
e.g. glslc -MM shader.glsl
=> shader.spv: shader.glsl
<no error message should be generated>
"""
environment = Directory('.', [File('shader.glsl', MINIMAL_SHADER)])
glslc_args = ['-MM', 'shader.glsl']
dependency_rules_expected = [{'target': 'shader.spv',
'dependency': {'shader.glsl'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMMImpliesDashW(DependencyInfoStdoutMatch,
expect.NoOutputOnStderr):
"""Tests that -MM implies -w, a deprecated attribute should not generate
warning message.
e.g. glslc -MM shader.vert
=> shader.vert.spv: shader.vert
<no warning message should be generated>
"""
environment = Directory('.', [File(
'shader.vert', """
#version 400
layout(location = 0) attribute float x;
void main() {}""")])
glslc_args = ['-MM', 'shader.vert']
dependency_rules_expected = [{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}]
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMD(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MD generates dependency info file and compilation output.
e.g. glslc -MD shader.vert
=> <a.spv: valid SPIR-V object file>
=> <shader.vert.spv.d: dependency info>
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert']
expected_object_filenames = ('a.spv', )
target_filename = 'shader.vert.spv.d'
expected_file_contents = ['shader.vert.spv: shader.vert\n']
class DependencyInfoFileMatch(GlslCTest):
"""Mixin class for tests that can expect dependency info files.
To mix in this class, subclasses need to provide dependency_info_filenames
and dependency_info_files_expected_contents which are two lists.
list dependency_info_filenames contains the dependency info file names and
list dependency_info_files_expected_contents contains the expected matching
dependency rules.
The item order of the two lists should match, which means:
dependency_info_files_expected_contents[i] should describe the
dependency rules saved in dependency_info_filenames[i]
The content of each dependency info file is described in same 'list of dict'
structure explained in class DependencyInfoStdoutMatch's doc string.
"""
def check_dependency_info_files(self, status):
dep_info_files = \
[os.path.join(status.directory,
f) for f in self.dependency_info_filenames]
for i, df in enumerate(dep_info_files):
if not os.path.isfile(df):
return False, 'Cannot find file: ' + df
try:
with open(df, 'r') as dff:
content = dff.read()
rules = parse_text_rules(content.split('\n'))
process_test_specified_dependency_info_rules(
self.dependency_info_files_expected_contents[i])
if self.dependency_info_files_expected_contents[
i] != rules:
return False, (
'Incorrect dependency info:\n{ac_rules}\n'
'Expected:\n{ex_rules}\n'
'Incorrect file output:\n{ac_out}\n'
'Incorrect dependency info file:\n{ac_file}\n'.format(
ac_rules=rules,
ex_rules=self.dependency_rules_expected,
ac_stdout=content,
ac_file=df))
except IOError:
return False, ('Could not open dependency info file ' + df +
' for reading')
return True, ''
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMWorksWithDashO(DependencyInfoFileMatch):
"""Tests -M works with -o option. When user specifies an output file name
with -o, the dependency info should be dumped to the user specified output
file.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', 'shader.vert', '-o', 'dep_info']
dependency_info_filenames = ('dep_info', )
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append(
[{'target': 'shader.vert.spv',
'dependency': {'shader.vert'}}])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFile(expect.ValidNamedObjectFile,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files.
e.g. glslc -MD a.vert b.vert -c
=> <a.vert.spv: valid SPIR-V object file>
=> <a.vert.spv.d: dependency info: "a.vert.spv: a.vert">
=> <b.vert.spv: valid SPIR-V object file>
=> <b.vert.spv.d: dependency info: "b.vert.spv: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-c']
expected_object_filenames = ('a.vert.spv', 'b.vert.spv', )
dependency_info_filenames = ['a.vert.spv.d', 'b.vert.spv.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spv',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spv',
'dependency': {'b.vert'}}
])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFilePreprocessingOnlyMode(expect.StdoutMatch,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files in
preprocessing only mode.
e.g. glslc -MD a.vert b.vert -E
=> stdout: preprocess result of a.vert and b.vert
=> <a.vert.spv.d: dependency info: "a.vert.spv: a.vert">
=> <b.vert.spv.d: dependency info: "b.vert.spv: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-E']
dependency_info_filenames = ['a.vert.spv.d', 'b.vert.spv.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spv',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spv',
'dependency': {'b.vert'}}
])
expected_stdout = ("#version 140\nvoid main() { }\n"
"#version 140\nvoid main() { }\n")
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDMultipleFileDisassemblyMode(expect.ValidNamedAssemblyFile,
DependencyInfoFileMatch):
"""Tests that -MD generates dependency info file for multiple files in
disassembly mode.
e.g. glslc -MD a.vert b.vert -S
=> <a.vert.spvasm: valid SPIR-V assembly file>
=> <a.vert.spvasm.d: dependency info: "a.vert.spvasm: a.vert">
=> <b.vert.spvasm: valid SPIR-V assembly file>
=> <b.vert.spvasm.d: dependency info: "b.vert.spvasm: b.vert">
"""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-S']
expected_assembly_filenames = ('a.vert.spvasm', 'b.vert.spvasm', )
dependency_info_filenames = ['a.vert.spvasm.d', 'b.vert.spvasm.d']
dependency_info_files_expected_contents = []
dependency_info_files_expected_contents.append([{'target': 'a.vert.spvasm',
'dependency': {'a.vert'}}
])
dependency_info_files_expected_contents.append([{'target': 'b.vert.spvasm',
'dependency': {'b.vert'}}
])
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMT(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MT generates dependency info file with specified target label.
e.g. glslc -MD shader.vert -MT target_label
=> <a.spv: valid SPIR-V object file>
=> <shader.vert.spv.d: dependency info: "target_label: shader.vert">
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert', '-MT', 'target_label']
expected_object_filenames = ('a.spv', )
target_filename = 'shader.vert.spv.d'
expected_file_contents = ['target_label: shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMF(expect.ValidFileContents, expect.ValidNamedObjectFile):
"""Tests that -MF dumps dependency info into specified file.
e.g. glslc -MD shader.vert -MF dep_file
=> <a.spv: valid SPIR-V object file>
=> <dep_file: dependency info: "shader.vert.spv: shader.vert">
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', 'shader.vert', '-MF', 'dep_file']
expected_object_filenames = ('a.spv', )
target_filename = 'dep_file'
expected_file_contents = ['shader.vert.spv: shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDSpecifyOutputFileName(expect.ValidFileContents,
expect.ValidNamedObjectFile):
"""Tests that -MD has the default dependency info file name and target
label correct when -o <output_file_name> appears in the command line.
The default dependency info file name and target label should be deduced
from the linking-disabled compilation output.
e.g. glslc -MD subdir/shader.vert -c -o output
=> <./output: valid SPIR-V object file>
=> <./output.d: dependency info: "output: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-c', '-o', 'output']
expected_object_filenames = ('output', )
target_filename = 'output.d'
expected_file_contents = ['output: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDWithDashMFDashMTDashO(expect.ValidFileContents,
expect.ValidNamedObjectFile):
"""Tests that -MD, -MF, -MT and -o gernates dependency info file and
compilation output file correctly
e.g. glslc -MD subdir/shader.vert -c -o subdir/out -MF dep_info -MT label
=> <subdir/out: valid SPIR-V object file>
=> <dep_info: dependency info: "label: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-c', '-o', 'subdir/out', '-MF',
'dep_info', '-MT', 'label']
expected_object_filenames = ('subdir/out', )
target_filename = 'dep_info'
expected_file_contents = ['label: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestDashCapMDWithDashMFDashMTDashODisassemblyMode(
expect.ValidFileContents, expect.ValidNamedAssemblyFile):
"""Tests that -MD, -MF, -MT and -o gernates dependency info file and
compilation output file correctly in disassembly mode
e.g. glslc -MD subdir/shader.vert -s -o subdir/out -MF dep_info -MT label
=> <subdir/out: valid SPIR-V object file>
=> <dep_info: dependency info: "label: shader.vert">
"""
environment = EMPTY_SHADER_IN_SUBDIR
glslc_args = ['-MD', 'subdir/shader.vert', '-S', '-o', 'subdir/out', '-MF',
'dep_info', '-MT', 'label']
expected_assembly_filenames = ('subdir/out', )
target_filename = 'dep_info'
expected_file_contents = ['label: subdir/shader.vert\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorSetBothDashCapMAndDashCapMD(expect.StderrMatch):
"""Tests that when both -M (or -MM) and -MD are specified, glslc should exit
with an error message complaining the case and neither dependency info
output nor compilation output. This test has -MD before -M flag.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MD', '-M', 'shader.vert']
expected_stderr = ['glslc: error: both -M (or -MM) and -MD are specified. '
'Only one should be used at one time.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorSetBothDashCapMDAndDashCapM(expect.StderrMatch):
"""Tests that when both -M (or -MM) and -MD are specified, glslc should exit
with an error message complaining the case and neither dependency info
output nor compilation output. This test has -M before -MD flag.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-M', '-MD', 'shader.vert']
expected_stderr = ['glslc: error: both -M (or -MM) and -MD are specified. '
'Only one should be used at one time.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMFWithMultipleInputFiles(expect.StderrMatch):
"""Tests that when -MF option is specified, only one input file should be
provided."""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-MD', 'a.vert', 'b.vert', '-c', '-MF', 'dep_info']
expected_stderr = ['glslc: error: '
'to specify dependency info file name or dependency '
'info target, only one input file is allowed.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMTWithMultipleInputFiles(expect.StderrMatch):
"""Tests that when -MT option is specified, only one input file should be
provided."""
environment = Directory('.', [File('a.vert', MINIMAL_SHADER),
File('b.vert', MINIMAL_SHADER)])
glslc_args = ['-M', 'a.vert', 'b.vert', '-c', '-MT', 'target']
expected_stderr = ['glslc: error: '
'to specify dependency info file name or dependency '
'info target, only one input file is allowed.\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMFMissingDashMAndDashMD(expect.StderrMatch):
"""Tests that when only -MF is specified while -M and -MD are not specified,
glslc should emit an error complaining that the user must specifiy either
-M (-MM) or -MD to generate dependency info.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MF', 'dep_info', 'shader.vert', '-c']
expected_stderr = ['glslc: error: '
'to generate dependencies you must specify either -M '
'(-MM) or -MD\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorDashCapMTMissingDashMAndMDWith(expect.StderrMatch):
"""Tests that when only -MF and -MT is specified while -M and -MD are not
specified, glslc should emit an error complaining that the user must
specifiy either -M (-MM) or -MD to generate dependency info.
"""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['-MF', 'dep_info', '-MT', 'target', 'shader.vert', '-c']
expected_stderr = ['glslc: error: '
'to generate dependencies you must specify either -M '
'(-MM) or -MD\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorMissingDependencyInfoFileName(expect.StderrMatch):
"""Tests that dependency file name is missing when -MF is specified."""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['target', 'shader.vert', '-c', '-MF']
expected_stderr = ['glslc: error: '
'missing dependency info filename after \'-MF\'\n']
@inside_glslc_testsuite('OptionsCapM')
class TestErrorMissingDependencyTargetName(expect.StderrMatch):
"""Tests that dependency target name is missing when -MT is specified."""
environment = EMPTY_SHADER_IN_CURDIR
glslc_args = ['target', 'shader.vert', '-c', '-MT']
expected_stderr = ['glslc: error: '
'missing dependency info target after \'-MT\'\n']

View File

@@ -0,0 +1,165 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
def simple_vertex_shader():
return """#version 310 es
void main() {
gl_Position = vec4(1., 2., 3., 4.);
}"""
def simple_fragment_shader():
return """#version 310 es
void main() {
gl_FragDepth = 10.;
}"""
def simple_compute_shader():
return """#version 310 es
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleDashCapSSingleFile(expect.ValidAssemblyFile):
"""Tests that -S works with a single file."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', shader]
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleFileSingleDashCapS(expect.ValidAssemblyFile):
"""Tests that the position of -S doesn't matter."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = [shader, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestSingleDashCapSMultipleFiles(expect.ValidAssemblyFile):
"""Tests that -S works with multiple files."""
shader1 = FileShader(simple_vertex_shader(), '.vert')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', shader1, shader2, shader3]
@inside_glslc_testsuite('OptionDashCapS')
class TestMultipleDashCapSSingleFile(expect.ValidAssemblyFile):
"""Tests that multiple -Ss works as one."""
shader = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', '-S', shader, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestMultipleDashCapSMultipleFiles(expect.ValidAssemblyFile):
"""Tests a mix of -Ss and files."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_compute_shader(), '.comp')
glslc_args = ['-S', shader1, '-S', '-S', shader2, '-S', shader3, '-S']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashC(expect.ValidAssemblyFile):
"""Tests that -S overwrites -c."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-c', '-S', shader1, '-c', '-c', shader2]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashFShaderStage(expect.ValidAssemblyFile):
"""Tests that -S works with -fshader-stage=."""
shader1 = FileShader(simple_fragment_shader(), '.glsl')
shader2 = FileShader(simple_vertex_shader(), '.glsl')
shader3 = FileShader(simple_compute_shader(), '.glsl')
glslc_args = ['-S',
'-fshader-stage=fragment', shader1,
'-fshader-stage=vertex', shader2,
'-fshader-stage=compute', shader3]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashStd(expect.ValidAssemblyFileWithWarning):
"""Tests that -S works with -std=."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
shader3 = FileShader(simple_compute_shader(), '.comp')
glslc_args = ['-S', '-std=450', shader1, shader2, shader3]
w = (': warning: (version, profile) forced to be (450, none), '
'while in source code it is (310, es)\n')
expected_warning = [
shader1, w, shader2, w, shader3, w, '3 warnings generated.\n']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashOSingleFile(expect.SuccessfulReturn,
expect.CorrectAssemblyFilePreamble):
"""Tests that -S works with -o on a single file."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', '-o', 'blabla', shader]
def check_output_blabla(self, status):
output_name = os.path.join(status.directory, 'blabla')
return self.verify_assembly_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithDashOMultipleFiles(expect.ErrorMessage):
"""Tests that -S works with -o on a single file."""
shader1 = FileShader(simple_fragment_shader(), '.frag')
shader2 = FileShader(simple_vertex_shader(), '.vert')
glslc_args = ['-S', '-o', 'blabla', shader1, shader2]
expected_error = ['glslc: error: cannot specify -o when '
'generating multiple output files\n']
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithStdIn(expect.ValidAssemblyFile):
"""Tests that -S works with stdin."""
shader = StdinShader(simple_fragment_shader())
glslc_args = ['-S', '-fshader-stage=fragment', shader]
@inside_glslc_testsuite('OptionDashCapS')
class TestDashCapSWithStdOut(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests that -S works with stdout."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-S', '-o', '-', shader]
expected_stdout = True
expected_stderr = ''

View File

@@ -0,0 +1,55 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('OptionC')
class TestSingleDashCSingleFile(expect.ValidObjectFile):
"""Tests that glslc accepts -c [filename]."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionC')
class TestSingleFileSingleDashC(expect.ValidObjectFile):
"""Tests that glslc accepts [filename] -c."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = [shader, '-c']
@inside_glslc_testsuite('OptionC')
class TestMultipleFiles(expect.ValidObjectFile):
"""Tests that glslc accepts -c and multiple source files."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader1, shader2]
@inside_glslc_testsuite('OptionC')
class TestMultipleDashC(expect.ValidObjectFile):
"""Tests that glslc accepts multiple -c and treated them as one."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', shader1, '-c', '-c', shader2]

View File

@@ -0,0 +1,180 @@
# Copyright 2016 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = '#version 310 es\nvoid main() {}'
EMPTY_SHADER_IN_CWD = Directory('.', [File('shader.vert', MINIMAL_SHADER)])
ASSEMBLY_WITH_DEBUG_SOURCE = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 7
; Schema: 0
OpCapability Shader
%2 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
%1 = OpString "shader.vert"
OpSource ESSL 310 %1 "// OpModuleProcessed entry-point main
// OpModuleProcessed client vulkan100
// OpModuleProcessed target-env vulkan1.0
// OpModuleProcessed entry-point main
#line 1
#version 310 es
void main() {}"
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
%void = OpTypeVoid
%4 = OpTypeFunction %void
OpLine %1 2 11
%main = OpFunction %void None %4
%6 = OpLabel
OpLine %1 2 0
OpReturn
OpFunctionEnd
"""
]
ASSEMBLY_O0 = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpName %main "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
ASSEMBLY_O = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%4 = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
ASSEMBLY_Os = [
"""; SPIR-V
; Version: 1.0
; Generator: Google Shaderc over Glslang; 11
; Bound: 6
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %4 "main"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%4 = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
"""]
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapO0(expect.ValidFileContents):
"""Tests that -O0 works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-O0', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O0
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOPerformance(expect.ValidFileContents):
"""Tests -O works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-O', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOs(expect.ValidFileContents):
"""Tests that -Os works."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_Os
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOOverriding(expect.ValidFileContents):
"""Tests that if there are multiple -O's, only the last one takes effect."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', '-O0', '-Os', '-O0', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_O0
@inside_glslc_testsuite('OptionDashCapO')
class TestDashCapOWithDashG(expect.ValidFileContents):
"""Tests that -g restrains -O from turning on strip debug info."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-Os', '-g', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_WITH_DEBUG_SOURCE
@inside_glslc_testsuite('OptionDashCapO')
class TestDashGWithDashCapO(expect.ValidFileContents):
"""Tests that -g restrains -O from turning on strip debug info."""
environment = EMPTY_SHADER_IN_CWD
glslc_args = ['-S', '-g', '-Os', 'shader.vert']
target_filename = 'shader.vert.spvasm'
expected_file_contents = ASSEMBLY_WITH_DEBUG_SOURCE
@inside_glslc_testsuite('OptionDashCapO')
class TestWrongOptLevel(expect.NoGeneratedFiles, expect.ErrorMessage):
"""Tests erroring out with wrong optimization level."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-c', '-O2', shader]
expected_error = "glslc: error: invalid value '2' in '-O2'\n"

View File

@@ -0,0 +1,44 @@
# Copyright 2017 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with uniforms without explicit bindings.
GLSL_SHADER = """#version 450
layout(set=0, binding=0)
buffer B { float x; vec3 y; } my_ssbo;
void main() {
my_ssbo.x = 1.0;
}"""
@inside_glslc_testsuite('OptionFHlslOffsets')
class StandardOffsetsByDefault(expect.ValidAssemblyFileWithSubstr):
"""Tests that standard GLSL packign is used by default."""
shader = FileShader(GLSL_SHADER, '.vert')
glslc_args = ['-S', shader]
expected_assembly_substr = "OpMemberDecorate %B 1 Offset 16"
@inside_glslc_testsuite('OptionFHlslOffsets')
class HlslOffsetsWhenRequested(expect.ValidAssemblyFileWithSubstr):
"""Tests that standard GLSL packign is used by default."""
shader = FileShader(GLSL_SHADER, '.vert')
glslc_args = ['-S', '-fhlsl-offsets', shader]
expected_assembly_substr = "OpMemberDecorate %B 1 Offset 4"

View File

@@ -0,0 +1,69 @@
# Copyright 2019 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader using the clamp, max, and min builtin functions.
GLSL_FRAG_SHADER_WITH_CLAMP = """#version 450
layout(location=0) in vec4 i;
layout(location=0) out vec4 o;
void main() {
o = clamp(i, vec4(0.5), vec4(1.0))
+ max(i, vec4(0.5))
+ min(i, vec4(0.5));
}
"""
@inside_glslc_testsuite('OptionFNanClamp')
class TestClampMapsToFClampByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FClamp'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMaxMapsToFMaxByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FMax'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMinMapsToFMinByDefault(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 FMin'
@inside_glslc_testsuite('OptionFNanClamp')
class TestClampMapsToNClampWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NClamp'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMaxMapsToNMaxWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NMax'
@inside_glslc_testsuite('OptionFNanClamp')
class TestMinMapsToNMinWithFlag(expect.ValidAssemblyFileWithSubstr):
shader = FileShader(GLSL_FRAG_SHADER_WITH_CLAMP, '.frag')
glslc_args = ['-S', '-fnan-clamp', shader]
expected_assembly_substr = 'OpExtInst %v4float %1 NMin'

View File

@@ -0,0 +1,55 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def empty_es_310_shader():
return '#version 310 es\n void main() {}\n'
@inside_glslc_testsuite('OptionG')
class TestSingleDashGSingleFile(expect.ValidObjectFile):
"""Tests that glslc accepts -g [filename]. Need -c for now too."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', '-g', shader]
@inside_glslc_testsuite('OptionG')
class TestSingleFileSingleDashG(expect.ValidObjectFile):
"""Tests that glslc accepts [filename] -g -c."""
shader = FileShader(empty_es_310_shader(), '.vert')
glslc_args = [shader, '-g', '-c']
@inside_glslc_testsuite('OptionG')
class TestMultipleFiles(expect.ValidObjectFile):
"""Tests that glslc accepts -g and multiple source files."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.frag')
glslc_args = ['-c', shader1, '-g', shader2]
@inside_glslc_testsuite('OptionG')
class TestMultipleDashG(expect.ValidObjectFile):
"""Tests that glslc accepts multiple -g and treated them as one."""
shader1 = FileShader(empty_es_310_shader(), '.vert')
shader2 = FileShader(empty_es_310_shader(), '.vert')
glslc_args = ['-c', '-g', shader1, '-g', '-g', shader2]

View File

@@ -0,0 +1,98 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, TempFileName
from builtins import bytes
@inside_glslc_testsuite('OptionDashO')
class TestOptionDashOConcatenatedArg(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that we can concatenate -o and the output filename."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-ofoo', shader]
def check_output_foo(self, status):
output_name = os.path.join(status.directory, 'foo')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashO')
class ManyOutputFilesWithDashO(expect.ErrorMessage):
"""Tests -o and -c with several files generates an error."""
shader1 = FileShader('', '.vert')
shader2 = FileShader('', '.frag')
glslc_args = ['-o', 'foo', '-c', shader1, shader2]
expected_error = [
'glslc: error: cannot specify -o when '
'generating multiple output files\n']
@inside_glslc_testsuite('OptionDashO')
class OutputFileLocation(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that the -o flag puts a file in a new location."""
shader = FileShader('#version 310 es\nvoid main() {}', '.frag')
glslc_args = [shader, '-o', TempFileName('a.out')]
def check_output_a_out(self, status):
output_name = os.path.join(status.directory, 'a.out')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('OptionDashO')
class DashOMissingArgumentIsAnError(expect.ErrorMessage):
"""Tests that -o without an argument is an error."""
glslc_args = ['-o']
expected_error = ['glslc: error: argument to \'-o\' is missing ' +
'(expected 1 value)\n']
@inside_glslc_testsuite('OptionDashO')
class OutputFileBinaryAvoidsCRLFTranslation(expect.ReturnCodeIsZero,
expect.NoOutputOnStderr,
expect.NoGeneratedFiles,
expect.CorrectBinaryLengthAndPreamble):
"""Tests that the -o flag emits a binary file without CR/LF translation.
"""
# A shader whose compiled output has three bytes that are newlines.
# If the output stream converts the newlines to CR/LF, then we end up
# with a file that is 4k + 3 bytes long. That will be caught by the
# object file checks.
SHADER_WITH_THREE_NEWLINES_IN_BINARY = """#version 450
layout(location = 0) out uint ovar;
void main() { ovar = 9; }
"""
shader = FileShader(SHADER_WITH_THREE_NEWLINES_IN_BINARY, '.vert')
glslc_args = [shader, '-o', '-']
def check_stdout_binary(self, status):
binary = bytes(status.stdout)
newlines = [x for x in binary if x == ord('\n')]
num_newlines = len(newlines)
if num_newlines % 4 == 0:
return False, "Bad test. Need nontrivial number of newlines"
if num_newlines != 2:
return False, ("Update this test. Expected 3 newlines in the "
"binary, but found {}").format(num_newlines)
return self.verify_binary_length_and_header(bytes(status.stdout))

View File

@@ -0,0 +1,145 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = "#version 140\nvoid main(){}"
# This one is valid GLSL but not valid HLSL.
GLSL_VERTEX_SHADER = "#version 140\nvoid main(){ gl_Position = vec4(1.0);}"
# This one is GLSL but without leading #version. Should result in
# a parser error when compiled as HLSL.
GLSL_VERTEX_SHADER_WITHOUT_VERSION = "void main(){ gl_Position = vec4(1.0);}"
# This one is valid HLSL but not valid GLSL.
# Use entry point "main" so we don't have to specify -fentry-point
HLSL_VERTEX_SHADER = "float4 main() : SV_POSITION { return float4(1.0); }"
@inside_glslc_testsuite('OptionDashX')
class TestDashXNoArg(expect.ErrorMessage):
"""Tests -x with nothing."""
glslc_args = ['-x']
expected_error = [
"glslc: error: argument to '-x' is missing (expected 1 value)\n",
'glslc: error: no input files\n']
@inside_glslc_testsuite('OptionDashX')
class TestDashXGlslOnGlslShader(expect.ValidObjectFile):
"""Tests -x glsl on a GLSL shader."""
shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-x', 'glsl', '-c', shader]
@inside_glslc_testsuite('OptionDashX')
class TestDashXGlslOnHlslShader(expect.ErrorMessageSubstr):
"""Tests -x glsl on an HLSL shader."""
shader = FileShader(HLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-x', 'glsl', '-c', shader]
expected_error_substr = ["error: #version: Desktop shaders for Vulkan SPIR-V"
" require version 140 or higher\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXHlslOnGlslShader(expect.ErrorMessageSubstr):
"""Tests -x hlsl on a GLSL shader."""
shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-x', 'hlsl', '-c', shader]
expected_error_substr = ["error: '#version' : invalid preprocessor command\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXHlslOnGlslShaderWithoutVertex(expect.ErrorMessageSubstr):
"""Tests -x hlsl on a GLSL shader without leading #version."""
shader = FileShader(GLSL_VERTEX_SHADER_WITHOUT_VERSION, '.vert')
glslc_args = ['-x', 'hlsl', '-c', shader]
expected_error_substr = ["error: 'vec4' : no matching overloaded function found\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXWrongParam(expect.ErrorMessage):
"""Tests -x with wrong parameter."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', 'gl', shader]
expected_error = ["glslc: error: language not recognized: 'gl'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashX(expect.ValidObjectFile):
"""Tests that multiple -x works with a single language."""
shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-c', '-x', 'glsl', '-x', 'glsl', shader, '-x', 'glsl']
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashXMixedLanguages(expect.ValidObjectFile):
"""Tests that multiple -x works with different languages."""
glsl_shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
hlsl_shader = FileShader(HLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-c', '-x', 'hlsl', hlsl_shader,
'-x', 'glsl', glsl_shader,
'-x', 'hlsl', hlsl_shader,
'-x', 'glsl', glsl_shader]
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashXCorrectWrong(expect.ErrorMessage):
"""Tests -x glsl -x [wrong-language]."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', 'glsl', '-x', 'foo', shader]
expected_error = ["glslc: error: language not recognized: 'foo'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestMultipleDashXWrongCorrect(expect.ErrorMessage):
"""Tests -x [wrong-language] -x glsl."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xbar', '-x', 'glsl', shader]
expected_error = ["glslc: error: language not recognized: 'bar'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXGlslConcatenated(expect.ValidObjectFile):
"""Tests -xglsl."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xglsl', shader, '-c']
@inside_glslc_testsuite('OptionDashX')
class TestDashXWrongParamConcatenated(expect.ErrorMessage):
"""Tests -x concatenated with a wrong language."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-xsl', shader]
expected_error = ["glslc: error: language not recognized: 'sl'\n"]
@inside_glslc_testsuite('OptionDashX')
class TestDashXEmpty(expect.ErrorMessage):
"""Tests -x ''."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-x', '', shader]
expected_error = ["glslc: error: language not recognized: ''\n"]

View File

@@ -0,0 +1,44 @@
# Copyright 2016 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
import re
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsShaderc(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'shaderc'."""
glslc_args = ['--version']
expected_stdout = re.compile('^shaderc')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsSpirvTools(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'spirv-tools'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nspirv-tools')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsGlslang(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'glslang'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nglslang')
@inside_glslc_testsuite('OptionDashDashVersion')
class TestVersionContainsTarget(expect.StdoutMatch, expect.ReturnCodeIsZero):
"""Tests --version output contains 'Target:'."""
glslc_args = ['--version']
expected_stdout = re.compile('\nTarget: SPIR-V \d+\.\d+')

View File

@@ -0,0 +1,431 @@
# Copyright 2017 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with uniforms without explicit bindings.
GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS = """#version 450
#extension GL_ARB_sparse_texture2 : enable
uniform texture2D my_tex;
uniform sampler my_sam;
layout(rgba32f) uniform image2D my_img;
layout(rgba32f) uniform imageBuffer my_imbuf;
uniform block { float x; float y; } my_ubo;
buffer B { float z; } my_ssbo;
void main() {
texture(sampler2D(my_tex,my_sam),vec2(1.0));
vec4 t;
sparseImageLoadARB(my_img,ivec2(0),t);
imageLoad(my_imbuf,42);
float x = my_ubo.x;
my_ssbo.z = 1.1;
}"""
# An HLSL shader with uniforms without explicit bindings.
# The counter buffer has an associated counter that needs a
# binding. Compile this shader with --auto-bind-uniforms to
# give it a binding, since Glslang does not support attribute
# [[vk::counter_binding(N))]].
# See https://github.com/KhronosGroup/glslang/issues/1616
HLSL_SHADER_WITHOUT_BINDINGS = """
SamplerState s1 : register(s1);
SamplerComparisonState s2 : register(s2);
Texture1D t1 : register(t11);
Texture2D <float4> t2 : register(t12);
Texture3D <float2> t3 : register(t13);
StructuredBuffer<float4> t4 : register(t14);
ByteAddressBuffer t5 : register(t15);
Buffer<float4> t6 : register(t16);
RWTexture1D <float4> u1 : register(u21);
RWTexture1D <float4> u2 : register(u22);
RWTexture1D <float4> u3 : register(u23);
RWBuffer <float4> u4 : register(u24);
RWByteAddressBuffer u5 : register(u25);
RWStructuredBuffer<float> u6 : register(u26);
AppendStructuredBuffer<float> u7 : register(u27);
ConsumeStructuredBuffer<float> u8 : register(u28);
float4 main() : SV_Target0 {
s1;
s2;
t1;
t2;
t3;
t4[2];
t5.Load(8);
t6;
u1;
u2;
u3;
u4[1];
u5.Load(15);
u6[2];
u7;
u8;
return float4(u8.Consume() + t2.SampleCmp(s2, 1.0, 2.0)) + t1.Sample(s1, 1.0)
+ t6.Load(1);
}
"""
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class UniformBindingsNotCreatedByDefault(expect.ErrorMessageSubstr):
"""Tests that compilation fails when uniforms have no binding."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader]
expected_error_substr = "sampler/texture/image requires layout(binding=X)"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FAutoBindingUniformsGeneratesBindings(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates bindings for uniforms upon request ."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms']
# Sufficient to just check one of the uniforms.
expected_assembly_substr = "OpDecorate %my_sam Binding 1"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseOptionRespectedOnImage(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseOptionRespectedOnImageBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base value is respected on image buffers."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_imbuf Binding 45"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-ftexture-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_tex Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fsampler-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_sam Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseOptionRespectedOnBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fubo-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fubo-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_ubo Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FCbufferBindingBaseOptionRespectedOnBuffer(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fcbuffer-binding-base value is respected."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fcbuffer-binding-base', '44']
expected_assembly_substr = "OpDecorate %my_ubo Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base']
expected_error_substr = "error: Option -fimage-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base']
expected_error_substr = "error: Option -ftexture-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base']
expected_error_substr = "error: Option -fsampler-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires a value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base']
expected_error_substr = "error: Option -fubo-binding-base requires at least one argument"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsNumberValueIfNotStage(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fimage-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -ftexture-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fsampler-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires a number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base', '9x']
expected_error_substr = "error: invalid offset value 9x for -fubo-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fimage-binding-base requires an unsigned number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fimage-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fimage-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FTextureBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -ftexture-binding-base requires an unsigned number value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-ftexture-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -ftexture-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSamplerBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fsampler-binding-base requires an unsigned value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fsampler-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fsampler-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FUboBindingBaseNeedsUnsignedNumberValue(expect.ErrorMessageSubstr):
"""Tests that -fubo-binding-base requires an unsigned value."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fubo-binding-base', '-6']
expected_error_substr = "error: invalid offset value -6 for -fubo-binding-base"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForVertOptionRespectedOnImageCompileAsVert(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with vert stage value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'vert', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForVertOptionIgnoredOnImageCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with vert stage value is ignored when cmopiled as
fragment."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'vert', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 2"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FImageBindingBaseForFragOptionRespectedOnImageCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fimage-binding-base with frag stage value is respected on images."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fimage-binding-base', 'frag', '44']
expected_assembly_substr = "OpDecorate %my_img Binding 44"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseRespectedOnSsboCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is respected on SSBOs."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 100"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseForFragOptionRespectedOnSsboCompileAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is respected on SSBOs."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 100"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class FSsboBindingBaseForFragOptionIgnoredOnSsboCompileAsVert(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fssbo-binding-base with frag stage value is ignored on SSBOs
when compiling as a vertex shader."""
shader = FileShader(GLSL_SHADER_WITH_UNIFORMS_WITHOUT_BINDINGS, '.vert')
glslc_args = ['-S', shader, '-fauto-bind-uniforms', '-fssbo-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %my_ssbo Binding 5"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class AutomaticHlslIoMapping(expect.ValidAssemblyFileWithSubstr):
"""Tests that HLSL IO Mapping uses the register values in the source code."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = "OpDecorate %u8 Binding 28"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base sets binding base for samplers in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 102"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base for frag sets binding base for samplers
in HLSL compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 102"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFSamplerBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fsampler-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fsampler-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %s2 Binding 2"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base sets binding base for textures in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 116"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base for frag sets binding base for textures
in HLSL compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 116"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFTextureBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -ftexture-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-ftexture-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %t6 Binding 16"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base sets binding base for UAVs in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 128"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseForFragOptionRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base for frag sets binding base for UAVs in HLSL
compilation."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', 'frag', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 128"
@inside_glslc_testsuite('OptionFAutoBindUniforms')
class HlslFUavBindingBaseForComputeOptionIgnoredWhenCompilingAsFrag(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fuav-binding-base for compute is ignored when compiling
as a fragment shader."""
shader = FileShader(HLSL_SHADER_WITHOUT_BINDINGS, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-iomap', shader,
'-fauto-bind-uniforms', '-fuav-binding-base', 'compute', '100']
expected_assembly_substr = "OpDecorate %u8 Binding 28"

View File

@@ -0,0 +1,59 @@
# Copyright 2018 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with a separate sampler and texture2D object
GLSL_SHADER_SEPARATE_IMAGE_SAMPLER = """#version 460
layout (location=0) in vec2 in_UV;
layout (location=0) out vec4 out_Color;
layout (set=0,binding=0) uniform sampler u_Sampler;
layout (set=0,binding=0) uniform texture2D u_Tex;
void main() {
out_Color = texture(sampler2D(u_Tex, u_Sampler), in_UV);
}"""
# An HLSL fragment shader with the usual Texture2D and SamplerState pair
HLSL_SHADER_SEPARATE_IMAGE_SAMPLER = """
Texture2D u_Tex;
SamplerState u_Sampler;
float4 Frag(float2 uv) : COLOR0 {
return u_Tex.Sample(u_Sampler, uv);
}"""
@inside_glslc_testsuite('OptionFAutoCombinedImageSampler')
class FAutoCombinedImageSamplerCheckGLSL(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler combines GLSL sampler and texture2D objects."""
shader = FileShader(GLSL_SHADER_SEPARATE_IMAGE_SAMPLER, '.frag')
glslc_args = ['-S', '-fauto-combined-image-sampler', shader]
expected_assembly_substr = """%10 = OpTypeImage %float 2D 0 0 0 1 Unknown
%11 = OpTypeSampledImage %10
%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11
%u_Tex = OpVariable %_ptr_UniformConstant_11 UniformConstant"""
@inside_glslc_testsuite('OptionFAutoCombinedImageSampler')
class FAutoCombinedImageSamplerCheckHLSL(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler combines HLSL Texture2D and SamplerState objects into SPIRV SampledImage."""
shader = FileShader(HLSL_SHADER_SEPARATE_IMAGE_SAMPLER, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Frag', '-fauto-combined-image-sampler', shader]
expected_assembly_substr = """%14 = OpTypeImage %float 2D 0 0 0 1 Unknown
%15 = OpTypeSampledImage %14
%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
%u_Tex = OpVariable %_ptr_UniformConstant_15 UniformConstant"""

View File

@@ -0,0 +1,87 @@
# Copyright 2018 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with inputs and outputs explicit locations.
GLSL_SHADER_IO_WITHOUT_LOCATIONS = """#version 310 es
in vec4 m_in;
in vec4 m_in1;
out vec4 m_out;
out vec4 m_out1;
void main() {
m_out = m_in;
m_out1 = m_in1;
}"""
# An HLSL fragment shader with inputs and outputs explicit locations.
HLSL_SHADER_IO_WITHOUT_LOCATIONS = """
float4 Foo(float4 a, float4 b) : COLOR0 {
return a + b;
}"""
@inside_glslc_testsuite('OptionFAutoMapLocations')
class MissingLocationsResultsInError(expect.ErrorMessageSubstr):
"""Tests that compilation fails when inputs or outputs have no location."""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader]
expected_error_substr = "SPIR-V requires location for user input/output"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class FAutoMapLocationsGeneratesLocationsCheckInput(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates locations upon request: Input 0"""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader, '-fauto-map-locations']
expected_assembly_substr = "OpDecorate %m_in Location 0"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class FAutoMapLocationsGeneratesLocationsCheckOutput0(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler generates locations upon request: Output 0"""
shader = FileShader(GLSL_SHADER_IO_WITHOUT_LOCATIONS, '.vert')
glslc_args = ['-S', shader, '-fauto-map-locations']
expected_assembly_substr = "OpDecorate %m_out Location 0"
# Currently Glslang only generates Location 0.
# See https://github.com/KhronosGroup/glslang/issues/1261
# TODO(dneto): Write tests that check Location 1 is generated for inputs and
# outputs.
# Glslang's HLSL compiler automatically assigns locations inptus and outputs.
@inside_glslc_testsuite('OptionFAutoMapLocations')
class HLSLCompilerGeneratesLocationsCheckInput0(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler generates locations automatically: Input 0."""
shader = FileShader(HLSL_SHADER_IO_WITHOUT_LOCATIONS, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Foo', shader]
expected_assembly_substr = "OpDecorate %a Location 0"
@inside_glslc_testsuite('OptionFAutoMapLocations')
class HLSLCompilerGeneratesLocationsCheckOutput(expect.ValidAssemblyFileWithSubstr):
"""Tests that the HLSL compiler generates locations automatically: Output."""
shader = FileShader(HLSL_SHADER_IO_WITHOUT_LOCATIONS, '.hlsl')
glslc_args = ['-S', '-fshader-stage=frag', '-fentry-point=Foo', shader]
expected_assembly_substr = "OpDecorate %_entryPointOutput Location 0"

View File

@@ -0,0 +1,113 @@
# Copyright 2016 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = "#version 140\nvoid main(){}"
# This one is valid GLSL but not valid HLSL.
GLSL_VERTEX_SHADER = "#version 140\nvoid main(){ gl_Position = vec4(1.0);}"
# This one is valid HLSL but not valid GLSL.
HLSL_VERTEX_SHADER = "float4 EntryPoint() : SV_POSITION { return float4(1.0); }"
HLSL_VERTEX_SHADER_WITH_MAIN = "float4 main() : SV_POSITION { return float4(1.0); }"
HLSL_VERTEX_SHADER_WITH_FOOBAR = "float4 Foobar() : SV_POSITION { return float4(1.0); }"
# Expected assembly code within certain shaders.
ASSEMBLY_ENTRY_POINT = "OpEntryPoint Vertex %EntryPoint \"EntryPoint\""
ASSEMBLY_MAIN = "OpEntryPoint Vertex %main \"main\""
ASSEMBLY_FOOBAR = "OpEntryPoint Vertex %Foobar \"Foobar\""
@inside_glslc_testsuite('OptionFEntryPoint')
class TestEntryPointDefaultsToMainForGlsl(expect.ValidAssemblyFileWithSubstr):
"""Tests that entry point name defaults to "main" in a GLSL shader."""
shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-S', shader]
expected_assembly_substr = ASSEMBLY_MAIN
@inside_glslc_testsuite('OptionFEntryPoint')
class TestEntryPointDefaultsToMainForHlsl(expect.ValidAssemblyFileWithSubstr):
"""Tests that entry point name defaults to "main" in an HLSL shader."""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_MAIN, '.vert')
glslc_args = ['-x', 'hlsl', '-S', shader]
expected_assembly_substr = ASSEMBLY_MAIN
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointMainOnGlslShader(expect.ValidAssemblyFileWithSubstr):
"""Tests -fentry-point=main with a GLSL shader."""
shader = FileShader(GLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-fentry-point=main', '-S', shader]
expected_assembly_substr = ASSEMBLY_MAIN
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointMainOnHlslShaderNotMatchingSource(expect.ValidObjectFileWithWarning):
"""Tests -x hlsl on an HLSL shader with -fentry-point=main
not matching the source."""
shader = FileShader(HLSL_VERTEX_SHADER, '.vert')
glslc_args = ['-x', 'hlsl', '-fentry-point=main', '-c', shader]
expected_warning = [shader,
': warning: Linking vertex stage: Entry point not found\n'
'1 warning generated.\n']
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointSpecifiedOnHlslShaderInDisassembly(expect.ValidObjectFileWithAssemblySubstr):
"""Tests -x hlsl on an HLSL shader with -fentry-point=EntryPoint
matching source."""
shader = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT)
glslc_args = ['-x', 'hlsl', '-fentry-point=EntryPoint', '-c', shader]
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointAffectsSubsequentShaderFiles(expect.ValidObjectFileWithAssemblySubstr):
"""Tests -x hlsl affects several subsequent shader source files."""
shader1 = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT)
shader2 = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT)
glslc_args = ['-x', 'hlsl', '-fentry-point=EntryPoint', '-c', shader1, shader2]
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointOverridesItself(expect.ValidObjectFileWithAssemblySubstr):
"""Tests that a later -fentry-point option overrides an earlier use."""
shader = FileShader(HLSL_VERTEX_SHADER, '.vert', assembly_substr=ASSEMBLY_ENTRY_POINT)
glslc_args = ['-x', 'hlsl', '-fentry-point=foobar', '-fentry-point=EntryPoint',
'-c', shader]
@inside_glslc_testsuite('OptionFEntryPoint')
class TestFEntryPointDefaultAndTwoOthers(expect.ValidObjectFileWithAssemblySubstr):
"""Tests three shaders with different entry point names. The first uses "main"
with default entry point processing, and the remaining shaders get their
own -fentry-point argument."""
shaderMain = FileShader(HLSL_VERTEX_SHADER_WITH_MAIN, '.vert',
assembly_substr=ASSEMBLY_MAIN)
shaderEntryPoint = FileShader(HLSL_VERTEX_SHADER, '.vert',
assembly_substr=ASSEMBLY_ENTRY_POINT)
shaderFoobar = FileShader(HLSL_VERTEX_SHADER_WITH_FOOBAR, '.vert',
assembly_substr=ASSEMBLY_FOOBAR)
glslc_args = ['-x', 'hlsl', '-c', shaderMain,
'-fentry-point=EntryPoint', shaderEntryPoint,
'-fentry-point=Foobar', shaderFoobar]

View File

@@ -0,0 +1,46 @@
# Copyright 2018 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
HLSL_SHADER_WITH_HALF_TYPE = """
float4 main() : SV_Target0 {
half h0 = (half)0.0;
half h1 = (half)1.0;
half h2 = (half)2.0;
half h3 = (half)3.0;
half4 v = (half4)(h0,h1,h2,h3) * (half)2.0;
return (float4)(v);
}
"""
@inside_glslc_testsuite('OptionFHlsl16BitTypes')
class TestHlsl16BitTypes_EnablesCapability(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_16bit_types enables the 16bit floating point capability."""
shader = FileShader(HLSL_SHADER_WITH_HALF_TYPE, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-16bit-types', '-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpCapability Float16';
@inside_glslc_testsuite('OptionFHlsl16BitTypes')
class TestHlsl16BitTypes_CreatesType(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_16bit_types creates the 16bit floating point capability."""
shader = FileShader(HLSL_SHADER_WITH_HALF_TYPE, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl-16bit-types', '-fauto-bind-uniforms', shader]
expected_assembly_substr = '= OpTypeFloat 16';

View File

@@ -0,0 +1,71 @@
# Copyright 2018 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# An HLSL shader with a counter buffer with a counter increment.
# Glslang doesn't automatically assign a binding to the counter, and
# it doesn't understand [[vk::counter_binding(n)]], so compile this
# with --auto-bind-uniforms.
# See https://github.com/KhronosGroup/glslang/issues/1616
HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER = """
RWStructuredBuffer<int> Ainc;
float4 main() : SV_Target0 {
return float4(Ainc.IncrementCounter(), 0, 1, 2);
}
"""
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslFunctionality1MentionsExtension(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_functionality1 enabled SPV_GOOGLE_hlsl_functionality1."""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpExtension "SPV_GOOGLE_hlsl_functionality1"'
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslFunctionality1DecoratesCounter(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl_functionality1 decorates the output target"""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpDecorateString'
## Next tests use the option with the hypen instead of underscore.
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslHyphenFunctionality1MentionsExtension(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl-functionality1 enabled SPV_GOOGLE_hlsl_functionality1."""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpExtension "SPV_GOOGLE_hlsl_functionality1"'
@inside_glslc_testsuite('OptionFHlslFunctionality1')
class TestHlslHyphenFunctionality1DecoratesCounter(expect.ValidAssemblyFileWithSubstr):
"""Tests that -fhlsl-functionality1 decorates the output target"""
shader = FileShader(HLSL_VERTEX_SHADER_WITH_COUNTER_BUFFER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', '-fhlsl_functionality1',
'-fauto-bind-uniforms', shader]
expected_assembly_substr = 'OpDecorateString'

View File

@@ -0,0 +1,378 @@
# Copyright 2016 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def shader_source_with_tex_offset(offset):
"""Returns a vertex shader using a texture access with the given offset."""
return """#version 450
layout (binding=0) uniform sampler1D tex;
void main() { vec4 x = textureOffset(tex, 1.0, """ + str(offset) + "); }"
def shader_with_tex_offset(offset):
"""Returns a vertex FileShader using a texture access with the given offset."""
return FileShader(shader_source_with_tex_offset(offset), ".vert")
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitNoEqual(expect.ErrorMessage):
"""Tests -flimit without equal."""
glslc_args = ['-flimit']
expected_error = ["glslc: error: unknown argument: '-flimit'\n"]
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitJustEqual(expect.ValidObjectFile):
"""Tests -flimit= with no argument."""
shader = shader_with_tex_offset(0);
glslc_args = ['-c', shader, '-flimit=']
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitJustEqualMaxOffset(expect.ValidObjectFile):
"""Tests -flimit= with no argument. The shader uses max offset."""
shader = shader_with_tex_offset(7);
glslc_args = ['-c', shader, '-flimit=']
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitJustEqualMinOffset(expect.ValidObjectFile):
"""Tests -flimit= with no argument. The shader uses min offset."""
shader = shader_with_tex_offset(-8);
glslc_args = ['-c', shader, '-flimit=']
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitJustEqualBelowMinOffset(expect.ErrorMessageSubstr):
"""Tests -flimit= with no argument. The shader uses below min default offset."""
shader = shader_with_tex_offset(-9);
glslc_args = ['-c', shader, '-flimit=']
expected_error_substr = ["'texel offset' : value is out of range"]
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitLowerThanDefaultMinOffset(expect.ValidObjectFile):
"""Tests -flimit= with lower than default argument. The shader uses below min offset."""
shader = shader_with_tex_offset(-9);
glslc_args = ['-c', shader, '-flimit= MinProgramTexelOffset -9 ']
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitIgnoredLangFeatureSettingSample(expect.ValidObjectFile):
"""Tests -flimit= an ignored option."""
shader = FileShader("#version 150\nvoid main() { while(true); }", '.vert')
glslc_args = ['-c', shader, '-flimit=whileLoops 0']
@inside_glslc_testsuite('OptionFLimit')
class TestFLimitLowerThanDefaultMinOffset(expect.ValidObjectFile):
"""Tests -flimit= with lower than default argument. The shader uses that offset."""
shader = shader_with_tex_offset(-9);
glslc_args = ['-c', shader, '-flimit= MinProgramTexelOffset -9 ']
@inside_glslc_testsuite('OptionFLimitFile')
class TestFLimitFileNoArg(expect.ErrorMessage):
"""Tests -flimit-file without an argument"""
shader = shader_with_tex_offset(-9);
glslc_args = ['-c', shader, '-flimit-file']
expected_error = "glslc: error: argument to '-flimit-file' is missing\n"
@inside_glslc_testsuite('OptionFLimitFile')
class TestFLimitFileMissingFile(expect.ErrorMessageSubstr):
"""Tests -flimit-file without an argument"""
shader = shader_with_tex_offset(-9);
glslc_args = ['-c', shader, '-flimit-file', 'i do not exist']
expected_error_substr = "glslc: error: cannot open input file: 'i do not exist'";
@inside_glslc_testsuite('OptionFLimitFile')
class TestFLimitFileSetsLowerMinTexelOffset(expect.ValidObjectFile):
"""Tests -flimit-file with lower than default argument. The shader uses that offset."""
limits_file = File('limits.txt', 'MinProgramTexelOffset -9')
shader = File('shader.vert', shader_source_with_tex_offset(-9));
environment = Directory('.', [limits_file, shader])
glslc_args = ['-c', shader.name, '-flimit-file', limits_file.name]
@inside_glslc_testsuite('OptionFLimitFile')
class TestFLimitFileInvalidContents(expect.ErrorMessage):
"""Tests -flimit-file bad file contents."""
limits_file = File('limits.txt', 'thisIsBad')
shader = File('shader.vert', shader_source_with_tex_offset(-9));
environment = Directory('.', [limits_file, shader])
glslc_args = ['-c', shader.name, '-flimit-file', limits_file.name]
expected_error = 'glslc: error: -flimit-file error: invalid resource limit: thisIsBad\n'
## Mesh shading
def mesh_shader_with_params(kwargs):
"""Returns a mesh shader as a FileShader, with given parameters"""
import sys
source = """#version 450
#extension {} : enable
layout(local_size_x={}) in;
layout(local_size_y={}) in;
layout(local_size_z={}) in;
layout(triangles) out;
layout(max_vertices={}) out;
layout(max_primitives={}) out;
layout(triangles) out;
void main() {{ }}
""".format(kwargs['extension'],kwargs['x'],kwargs['y'],kwargs['z'],kwargs['max_vert'],kwargs['max_prim'])
return FileShader(source,".mesh")
def task_shader_with_params(kwargs):
"""Returns a task shader as a FileShader, with given parameters"""
import sys
source = """#version 450
#extension {} : enable
layout(local_size_x={}) in;
layout(local_size_y={}) in;
layout(local_size_z={}) in;
void main() {{ }}
""".format(kwargs['extension'],kwargs['x'],kwargs['y'],kwargs['z'])
return FileShader(source,".task")
def meshDefaults(nv_or_ext,show=False):
result = dict({
# See Glslang's glslang/ResourceLimits/ResourceLimits.cpp
'nv': { 'extension': 'GL_NV_mesh_shader', 'x': 32, 'y': 1, 'z': 1, 'max_vert': 256, 'max_prim': 512 },
'ext': { 'extension': 'GL_EXT_mesh_shader', 'x': 128, 'y': 128, 'z': 128, 'max_vert': 256, 'max_prim': 256 }
})[nv_or_ext]
if show:
import sys
print(result,file=sys.stderr)
return result
## GL_NV_mesh_shader
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_X_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_NV 32']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_X_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_NV 31']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Y_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_NV 1']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Y_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['y'] = 3
shader = mesh_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_NV 2']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Z_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_NV 1']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_Z_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['z'] = 3
shader = mesh_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_NV 2']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxVert_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesNV 256']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxVert_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'max_vertices' : too large, must be less than gl_MaxMeshOutputVerticesNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesNV 255']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxPrim_ok(expect.ValidObjectFile):
shader = mesh_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesNV 512']
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_NV_MaxPrim_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'max_primitives' : too large, must be less than gl_MaxMeshOutputPrimitivesNV"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesNV 511']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_X_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_NV 32']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_X_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('nv'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_NV 31']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Y_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_NV 1']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Y_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['y'] = 3
shader = task_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_NV 2']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Z_ok(expect.ValidObjectFile):
shader = task_shader_with_params(meshDefaults('nv'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_NV 1']
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_NV_Z_bad(expect.ErrorMessageSubstr):
d = meshDefaults('nv')
d['z'] = 3
shader = task_shader_with_params(d)
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeNV"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_NV 2']
# TODO: Test MaxMeshViewCountNV
## GL_EXT_mesh_shader
## It requires SPIR-V 1.4
s14 = '--target-spv=spv1.4'
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_X_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_X_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeX_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Y_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Y_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeY_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Z_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_Z_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxMeshWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshWorkGroupSizeZ_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxVert_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesEXT 256', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxVert_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'max_vertices' : too large, must be less than gl_MaxMeshOutputVerticesEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputVerticesEXT 255', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxPrim_ok(expect.ValidObjectFile1_4):
shader = mesh_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesEXT 256', s14]
@inside_glslc_testsuite('OptionFLimit_Mesh')
class TestFLimitMeshShader_EXT_MaxPrim_bad(expect.ErrorMessageSubstr):
shader = mesh_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'max_primitives' : too large, must be less than gl_MaxMeshOutputPrimitivesEXT"
glslc_args = ['-c', shader, '-flimit= MaxMeshOutputPrimitivesEXT 255', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_X_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_X_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeX_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Y_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Y_bad(expect.ErrorMessageSubstr):
import sys
d = meshDefaults('ext',True)
print("TaskShader_EXT_Y_bad {}".format(str(d)),file=sys.stderr)
shader = task_shader_with_params(meshDefaults('ext',True))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeY_EXT 127', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Z_ok(expect.ValidObjectFile1_4):
shader = task_shader_with_params(meshDefaults('ext'))
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_EXT 128', s14]
@inside_glslc_testsuite('OptionFLimit_Task')
class TestFLimitTaskShader_EXT_Z_bad(expect.ErrorMessageSubstr):
shader = task_shader_with_params(meshDefaults('ext'))
expected_error_substr = "'local_size' : too large, see gl_MaxTaskWorkGroupSizeEXT"
glslc_args = ['-c', shader, '-flimit= MaxTaskWorkGroupSizeZ_EXT 127', s14]
# TODO: Test MaxMeshViewCountEXT

View File

@@ -0,0 +1,70 @@
# Copyright 2023 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# A GLSL shader with unused bindings.
GLSL_SHADER_WITH_UNUSED_BINDINGS = """#version 450
layout(binding=0) buffer InputA { vec4 x[]; } inputA;
layout(binding=1) buffer InputB { vec4 x[]; } inputB;
layout(binding=2) buffer Output { vec4 x[]; } outputO;
void main() {}
"""
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsInputA(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 0"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsInputB(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 1"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFPreserveBindingsOutputO(expect.ValidAssemblyFileWithSubstr):
"""Tests that the compiler preserves bindings when optimizations are
enabled."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader, '-fpreserve-bindings']
# Check the first buffer.
expected_assembly_substr = "Binding 2"
@inside_glslc_testsuite('OptionFPreserveBindings')
class TestFNoPreserveBindings(expect.ValidAssemblyFileWithoutSubstr):
"""Tests that the compiler removes bindings when -fpreserve-bindings is not
set."""
shader = FileShader(GLSL_SHADER_WITH_UNUSED_BINDINGS, '.comp')
glslc_args = ['-S', '-O', shader]
# Check that all binding decorations are gone.
unexpected_assembly_substr = "OpDecorate"

View File

@@ -0,0 +1,121 @@
# Copyright 2017 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
# An HLSL shader with uniforms without explicit bindings.
HLSL_SHADER = """
Buffer<float4> t4 : register(t4);
Buffer<float4> t5 : register(t5);
float4 main() : SV_Target0 {
return float4(t4.Load(0) + t5.Load(1));
}
"""
NEED_THREE_ARGS_ERR = "error: Option -fresource-set-binding requires at least 3 arguments"
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForFragRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on specific shader two textures"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 17
OpDecorate %t5 Binding 18"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForFragRespectedJustOneTriple(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on specific shader just one texture specified."""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '16']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 0
OpDecorate %t5 Binding 5"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForWrongStageIgnored(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on wrong shader ignored"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'vert',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 0
OpDecorate %t4 Binding 4
OpDecorate %t5 DescriptorSet 0
OpDecorate %t5 Binding 5"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingForAllRespected(expect.ValidAssemblyFileWithSubstr):
"""Tests -fresource-set-binding on all stages respected"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding',
't4', '9', '16',
't5', '17', '18']
expected_assembly_substr = """OpDecorate %t4 DescriptorSet 9
OpDecorate %t4 Binding 16
OpDecorate %t5 DescriptorSet 17
OpDecorate %t5 Binding 18"""
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingTooFewArgs(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with too few arguments"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9']
expected_error_substr = NEED_THREE_ARGS_ERR
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingInvalidSetNumber(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with inavlid set number"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '-9', '16']
expected_error_substr = NEED_THREE_ARGS_ERR
@inside_glslc_testsuite('OptionFRegisterSetBinding')
class FRegisterSetBindingInvalidBindingNumber(expect.ErrorMessageSubstr):
"""Tests -fresource-set-binding with inavlid binding number"""
shader = FileShader(HLSL_SHADER, '.frag')
glslc_args = ['-S', '-x', 'hlsl', shader,
'-fresource-set-binding', 'frag',
't4', '9', '-16']
expected_error_substr = NEED_THREE_ARGS_ERR

View File

@@ -0,0 +1,195 @@
# Copyright 2016 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import re
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = '#version 140\nvoid main() {}'
# Regular expression patterns for the minimal shader. The magic number should
# match exactly, and there should not be a trailing comma at the end of the
# list. When -mfmt=c is specified, curly brackets should be presented.
MINIMAL_SHADER_NUM_FORMAT_PATTERN = "^0x07230203.*[0-9a-f]$"
MINIMAL_SHADER_C_FORMAT_PATTERN = "^\{0x07230203.*[0-9a-f]\}"
ERROR_SHADER = '#version 140\n#error\nvoid main() {}'
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWorksWithDashC(expect.ValidFileContents):
"""Tests that -mfmt=c works with -c for single input file. SPIR-V binary
code output should be emitted as a C-style initializer list in the output
file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=c', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWorksWithDashC(expect.ValidFileContents):
"""Tests that -mfmt=num works with -c for single input file. SPIR-V binary
code output should be emitted as a list of hex numbers in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=num', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinWorksWithDashC(expect.ValidObjectFile):
"""Tests that -mfmt=bin works with -c for single input file. This test
should simply have the SPIR-V binary generated.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-c', '-mfmt=bin']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWithLinking(expect.ValidFileContents):
"""Tests that -mfmt=c works when linkding is enabled (no -c specified).
SPIR-V binary code should be emitted as a C-style initializer list in the
output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c']
target_filename = 'a.spv'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWithLinking(expect.ValidFileContents):
"""Tests that -mfmt=num works when linkding is enabled (no -c specified).
SPIR-V binary code should be emitted as a C-style initializer list in the
output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num']
target_filename = 'a.spv'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=c' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-S', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a C-style "
"initializer list when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=num' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-S', '-o', 'output_file']
expected_error = (
"glslc: error: cannot emit output as a list of hex numbers "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinErrorWhenOutputDisasembly(expect.ErrorMessage):
"""Tests that specifying '-mfmt=bin' when the compiler is set to
disassembly mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=bin', '-S', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a binary "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumErrorWhenOutputPreprocess(expect.ErrorMessage):
"""Tests that specifying '-mfmt=num' when the compiler is set to
preprocessing only mode should trigger an error.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-E', '-o', 'output_file']
expected_error = (
"glslc: error: cannot emit output as a list of hex numbers "
"when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCErrorWithDashCapM(expect.ErrorMessage):
"""Tests that specifying '-mfmt=c' should trigger an error when the
compiler is set to dump dependency info as the output (-M or -MM is
specified).
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-M', '-o', 'output_file']
expected_error = ("glslc: error: cannot emit output as a C-style "
"initializer list when only preprocessing the source\n")
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCWorksWithDashCapMD(expect.ValidFileContents):
"""Tests that -mfmt=c works with '-c -MD'. SPIR-V binary code
should be emitted as a C-style initializer list in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c', '-c', '-MD', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_C_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumWorksWithDashCapMD(expect.ValidFileContents):
"""Tests that -mfmt=num works with '-c -MD'. SPIR-V binary code
should be emitted as a C-style initializer list in the output file.
"""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num', '-c', '-MD', '-o', 'output_file']
target_filename = 'output_file'
expected_file_contents = re.compile(MINIMAL_SHADER_NUM_FORMAT_PATTERN, re.S)
@inside_glslc_testsuite('OptionMfmt')
class TestFmtCExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=c when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=c']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtNumExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=num when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=num']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']
@inside_glslc_testsuite('OptionMfmt')
class TestFmtBinExitsElegantlyWithErrorInShader(expect.ErrorMessage):
"""Tests that the compiler fails elegantly with -mfmt=binary when there are
errors in the input shader.
"""
shader = FileShader(ERROR_SHADER, '.vert')
glslc_args = [shader, '-mfmt=bin']
expected_error = [shader, ':3: error: \'#error\' :\n',
'1 error generated.\n']

View File

@@ -0,0 +1,224 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def simple_vertex_shader():
return """#version 310 es
void main() {
gl_Position = vec4(1., 2., 3., 4.);
}"""
def simple_hlsl_vertex_shader():
# Use "main" so we don't have to specify -fentry-point
return """float4 main() : SV_POSITION { return float4(1.0); } """
def simple_fragment_shader():
return """#version 310 es
void main() {
gl_FragDepth = 10.;
}"""
def simple_tessellation_control_shader():
return """#version 440 core
layout(vertices = 3) out;
void main() { }"""
def simple_tessellation_evaluation_shader():
return """#version 440 core
layout(triangles) in;
void main() { }"""
def simple_geometry_shader():
return """#version 150 core
layout (triangles) in;
layout (line_strip, max_vertices = 4) out;
void main() { }"""
def simple_compute_shader():
return """#version 310 es
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithGlslExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with .glsl extension."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithHlslExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with .hlsl extension."""
shader = FileShader(simple_hlsl_vertex_shader(), '.hlsl')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithKnownExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with known extension."""
shader = FileShader(simple_fragment_shader(), '.frag')
glslc_args = ['-c', '-fshader-stage=fragment', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithUnknownExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with unknown extension."""
shader = FileShader(simple_vertex_shader(), '.unknown')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithNoExtension(expect.ValidObjectFile):
"""Tests -fshader-stage with no extension."""
shader = FileShader(simple_vertex_shader(), '')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestAllShaderStages(expect.ValidObjectFile):
"""Tests all possible -fshader-stage values."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
shader2 = FileShader(simple_fragment_shader(), '.glsl')
shader3 = FileShader(simple_tessellation_control_shader(), '.glsl')
shader4 = FileShader(simple_tessellation_evaluation_shader(), '.glsl')
shader5 = FileShader(simple_geometry_shader(), '.glsl')
shader6 = FileShader(simple_compute_shader(), '.glsl')
glslc_args = [
'-c',
'-fshader-stage=vertex', shader1,
'-fshader-stage=fragment', shader2,
'-fshader-stage=tesscontrol', shader3,
'-fshader-stage=tesseval', shader4,
'-fshader-stage=geometry', shader5,
'-fshader-stage=compute', shader6]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageOverwriteFileExtension(expect.ValidObjectFile):
"""Tests -fshader-stage has precedence over file extension."""
# a vertex shader camouflaged with .frag extension
shader = FileShader(simple_vertex_shader(), '.frag')
# Command line says it's vertex shader. Should compile successfully
# as a vertex shader.
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageLatterOverwriteFormer(expect.ValidObjectFile):
"""Tests a latter -fshader-stage overwrite a former one."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = [
'-c', '-fshader-stage=fragment', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWithMultipleFiles(expect.ValidObjectFile):
"""Tests -fshader-stage covers all subsequent files."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
# a vertex shader with .frag extension
shader2 = FileShader(simple_vertex_shader(), '.frag')
shader3 = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = ['-c', '-fshader-stage=vertex', shader1, shader2, shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageMultipleShaderStage(expect.ValidObjectFile):
"""Tests multiple -fshader-stage."""
shader1 = FileShader(simple_vertex_shader(), '.glsl')
shader2 = FileShader(simple_fragment_shader(), '.frag')
shader3 = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = [
'-c',
'-fshader-stage=vertex', shader1,
'-fshader-stage=fragment', shader2,
'-fshader-stage=vertex', shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestFileExtensionBeforeShaderStage(expect.ValidObjectFile):
"""Tests that file extensions before -fshader-stage are not affected."""
# before -fshader-stage
shader1 = FileShader(simple_vertex_shader(), '.vert')
# after -fshader-stage
shader2 = FileShader(simple_fragment_shader(), '.frag')
shader3 = FileShader(simple_fragment_shader(), '.vert')
glslc_args = ['-c', shader1, '-fshader-stage=fragment', shader2, shader3]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageWrongShaderStageValue(expect.ErrorMessage):
"""Tests that wrong shader stage value results in an error."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = ['-c', '-fshader-stage=unknown', shader]
expected_error = ["glslc: error: stage not recognized: 'unknown'\n"]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageGlslExtensionMissingShaderStage(expect.ErrorMessage):
"""Tests that missing -fshader-stage for .glsl extension results in
an error."""
shader = FileShader(simple_vertex_shader(), '.glsl')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': .glsl file encountered but no -fshader-stage specified ahead\n"]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageHlslExtensionMissingShaderStage(expect.ErrorMessage):
"""Tests that missing -fshader-stage for .hlsl extension results in
an error."""
shader = FileShader(simple_hlsl_vertex_shader(), '.hlsl')
glslc_args = ['-c', '-x', 'hlsl', shader]
expected_error = [
"glslc: error: '", shader,
"': .hlsl file encountered but no -fshader-stage specified ahead\n"]
@inside_glslc_testsuite('OptionShaderStage')
class TestShaderStageUnknownExtensionMissingShaderStage(expect.ErrorMessage):
"""Tests that missing -fshader-stage for unknown extension results in
an error."""
shader = FileShader(simple_vertex_shader(), '.a_vert_shader')
glslc_args = ['-c', shader]
expected_error = [
"glslc: error: '", shader,
"': file not recognized: File format not recognized\n"]

View File

@@ -0,0 +1,312 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def core_vert_shader_without_version():
# gl_ClipDistance doesn't exist in es profile (at least until 3.10).
return 'void main() { gl_ClipDistance[0] = 5.; }'
def core_frag_shader_without_version():
# gl_SampleID appears in core profile from 4.00.
# gl_sampleID doesn't exsit in es profile (at least until 3.10).
return 'void main() { int temp = gl_SampleID; }'
def hlsl_compute_shader_with_barriers():
# Use "main" to avoid the need for -fentry-point
return 'void main() { AllMemoryBarrierWithGroupSync(); }'
@inside_glslc_testsuite('OptionStd')
class TestStdNoArg(expect.ErrorMessage):
"""Tests -std alone."""
glslc_args = ['-std']
expected_error = ["glslc: error: unknown argument: '-std'\n"]
@inside_glslc_testsuite('OptionStd')
class TestStdEqNoArg(expect.ErrorMessage):
"""Tests -std= with no argument."""
glslc_args = ['-std=']
expected_error = ["glslc: error: invalid value '' in '-std='\n"]
@inside_glslc_testsuite('OptionStd')
class TestStdEqSpaceArg(expect.ErrorMessage):
"""Tests -std= <version-profile>."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=', '450core', shader]
expected_error = ["glslc: error: invalid value '' in '-std='\n"]
# TODO(dneto): The error message changes with different versions of glslang.
@inside_glslc_testsuite('OptionStd')
class TestMissingVersionAndStd(expect.ErrorMessageSubstr):
"""Tests that missing both #version and -std results in errors."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', shader]
expected_error_substr = ['error:']
@inside_glslc_testsuite('OptionStd')
class TestMissingVersionButHavingStd(expect.ValidObjectFile):
"""Tests that correct -std fixes missing #version."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450core', shader]
@inside_glslc_testsuite('OptionStd')
class TestGLSL460(expect.ValidObjectFile):
"""Tests that GLSL version 4.6 is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=460', shader]
@inside_glslc_testsuite('OptionStd')
class TestGLSL460Core(expect.ValidObjectFile):
"""Tests that GLSL version 4.6 core profile is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=460core', shader]
@inside_glslc_testsuite('OptionStd')
class TestESSL320(expect.ValidObjectFile):
"""Tests that ESSL version 3.2 is supported."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=320es', shader]
@inside_glslc_testsuite('OptionStd')
class TestStdIgnoredInHlsl(expect.ValidObjectFile):
"""Tests HLSL compilation ignores -std."""
# Compute shaders are not available in OpenGL 150
shader = FileShader(hlsl_compute_shader_with_barriers(), '.comp')
glslc_args = ['-c', '-x', 'hlsl', '-std=150', shader]
@inside_glslc_testsuite('OptionStd')
class TestMissingVersionAndWrongStd(expect.ErrorMessage):
"""Tests missing #version and wrong -std results in errors."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=310es', shader]
expected_error = [
shader, ":1: error: 'gl_SampleID' : required extension not requested: "
'GL_OES_sample_variables\n1 error generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestConflictingVersionAndStd(expect.ValidObjectFileWithWarning):
"""Tests that with both #version and -std, -std takes precedence."""
# Wrong #version here on purpose.
shader = FileShader(
'#version 310 es\n' + core_frag_shader_without_version(), '.frag')
# -std overwrites the wrong #version.
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestMultipleStd(expect.ValidObjectFile):
"""Tests that for multiple -std, the last one takes effect."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=100', '-std=310es', shader, '-std=450core']
@inside_glslc_testsuite('OptionStd')
class TestMultipleFiles(expect.ValidObjectFileWithWarning):
"""Tests that -std covers all files."""
shader1 = FileShader(core_frag_shader_without_version(), '.frag')
shader2 = FileShader(core_vert_shader_without_version(), '.vert')
shader3 = FileShader(
'#version 310 es\n' + core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450core', shader1, shader2, shader3]
expected_warning = [
shader3, ': warning: (version, profile) forced to be (450, '
'core), while in source code it is (310, es)\n'
'1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestUnkownProfile(expect.ErrorMessage):
"""Tests that -std rejects unknown profile."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=450google', shader]
expected_error = [
"glslc: error: invalid value '450google' in '-std=450google'\n"]
@inside_glslc_testsuite('OptionStd')
class TestUnkownVersion(expect.ErrorMessage):
"""Tests that -std rejects unknown version."""
shader = FileShader(core_frag_shader_without_version(), '.frag')
glslc_args = ['-c', '-std=42core', shader]
expected_error = [
"glslc: error: invalid value '42core' in '-std=42core'\n"]
@inside_glslc_testsuite('OptionStd')
class TestTotallyWrongStdValue(expect.ErrorMessage):
"""Tests that -std rejects totally wrong -std value."""
shader = FileShader(core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=wrong42', shader]
expected_error = [
"glslc: error: invalid value 'wrong42' in '-std=wrong42'\n"]
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideSlashSlashComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The second #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'// #version 310 es\n#version 310 es\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideSlashStarComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The second #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'/* #version 310 es */\n#version 310 es\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestCommentBeforeVersion(expect.ValidObjectFileWithWarning):
"""Tests that comments before #version (same line) is correctly handled."""
shader = FileShader(
'/* some comment */ #version 150\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, none), while '
'in source code it is (150, none)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestCommentAfterVersion(expect.ValidObjectFileWithWarning):
"""Tests that multiple-line comments after #version is correctly handled."""
shader = FileShader(
'#version 150 compatibility ' +
'/* start \n second line \n end */\n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (150, compatibility)\n1 warning generated.\n']
# The following test case is disabled because of a bug in glslang.
# When checking non-newline whitespaces, glslang only recognizes
# ' ' and '\t', leaving '\v' and '\f' unhandled. The following test
# case exposes this problem. It should be turned on once a fix for
# glslang is landed.
#@inside_glslc_testsuite('OptionStd')
class TestSpaceAroundVersion(expect.ValidObjectFileWithWarning):
"""Tests that space around #version is correctly handled."""
shader = FileShader(
'\t \t # \t \f\f version \v \t\t 310 \v\v \t es \n' +
core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionInsideCrazyComment(expect.ValidObjectFileWithWarning):
"""Tests that -std substitutes the correct #version string."""
# The fourth #version string should be substituted and this shader
# should compile successfully with -std=450core.
shader = FileShader(
'/* */ /* // /* #version 310 es */\n' + # /*-style comment
'// /* */ /* /* // #version 310 es\n' + # //-style comment
'///*////*//*/*/ #version 310 es*/\n' + # //-style comment
'#version 310 es\n' + core_vert_shader_without_version(), '.vert')
glslc_args = ['-c', '-std=450core', shader]
expected_warning = [
shader, ': warning: (version, profile) forced to be (450, core), while '
'in source code it is (310, es)\n1 warning generated.\n']
@inside_glslc_testsuite('OptionStd')
class TestVersionMissingProfile(expect.ErrorMessage):
"""Tests that missing required profile in -std results in an error."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-c', '-std=310', shader]
expected_error = [
shader, ': error: #version: versions 300, 310, and 320 require ',
"specifying the 'es' profile\n1 error generated.\n"]
@inside_glslc_testsuite('OptionStd')
class TestVersionRedundantProfile(expect.ErrorMessageSubstr):
"""Tests that adding non-required profile in -std results in an error."""
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = ['-c', '-std=100core', shader]
expected_error_substr = [
shader, ': error: #version: versions before 150 do not allow '
'a profile token\n']

View File

@@ -0,0 +1,197 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def opengl_compat_fragment_shader():
return """#version 330
uniform highp sampler2D tex;
void main() {
gl_FragColor = texture2D(tex, vec2(0.0, 0.0));
}"""
def opengl_vertex_shader():
return """#version 330
void main() { int t = gl_VertexID; }"""
def vulkan_vertex_shader():
return """#version 310 es
void main() { int t = gl_VertexIndex; }"""
def vulkan_compute_subgroup_shader():
"""Returns a compute shader that requires Vulkan 1.1"""
return """#version 450
#extension GL_KHR_shader_subgroup_basic : enable
void main() { subgroupBarrier(); }"""
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglCompatWithOpenGlCompatShader(expect.ErrorMessageSubstr):
"""Tests that compiling OpenGL Compatibility Fragment shader with
--target-env=opengl_compat works correctly"""
shader = FileShader(opengl_compat_fragment_shader(), '.frag')
glslc_args = ['--target-env=opengl_compat', '-c', shader]
expected_error_substr = "error: opengl_compat is no longer supported"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglWithOpenGlCompatShader(expect.ErrorMessageSubstr):
"""Tests the error message of compiling OpenGL Compatibility Fragment shader
with --target-env=opengl"""
shader = FileShader(opengl_compat_fragment_shader(), '.frag')
glslc_args = ['--target-env=opengl', shader]
# Glslang does not give a pretty message. Make sure we get an error.
expected_error_substr = "errors generated"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglCompatWithOpenGlVertexShader(expect.ErrorMessageSubstr):
"""Tests that compiling OpenGL vertex shader with --target-env=opengl_compat
generates valid SPIR-V code"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl_compat', '-c', shader]
expected_error_substr = "error: opengl_compat is no longer supported"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenglWithOpenGlVertexShader(expect.ValidObjectFile):
"""Tests that compiling OpenGL vertex shader with --target-env=opengl
generates valid SPIR-V code"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestDefaultTargetEnvWithVulkanShader(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific shader with a default
target environment succeeds"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkanWithVulkan1_0ShaderSucceeds(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific Vulkan 1.0 shader succeeds with
--target-env=vulkan"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_0WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific Vulkan 1.0 shader succeeds with
--target-env=vulkan1.0"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.0', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_0WithVulkan1_1ShaderFails(expect.ErrorMessageSubstr):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.0', '-c', shader]
expected_error_substr = "error: 'subgroup op' : requires SPIR-V 1.3"
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_1WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_3):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.1', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_1WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_3):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.1', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_5):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.2', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_5):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.2', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_0ShaderSucceeds(expect.ValidObjectFile1_6):
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-env=vulkan1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqVulkan1_2WithVulkan1_1ShaderSucceeds(expect.ValidObjectFile1_6):
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-env=vulkan1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenGL4_5WithOpenGLShaderSucceeds(expect.ValidObjectFile):
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl4.5', '-c', shader]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqOpenGL4_6WithOpenGLShaderFailsUnsupported(expect.ErrorMessageSubstr):
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=opengl4.6', '-c', shader]
expected_error_substr = "invalid value 'opengl4.6' in '--target-env=opengl4.6'"
# Note: Negative tests are covered in the libshaderc_util unit tests.
# For example, that an OpenGL-specific shader should fail to compile
# for Vulkan, or a Vulkan-specific shader should fail to compile for
# OpenGL.
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqNoArg(expect.ErrorMessage):
"""Tests the error message of assigning empty string to --target-env"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=', shader]
expected_error = ["glslc: error: invalid value ",
"'' in '--target-env='\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvNoEqNoArg(expect.ErrorMessage):
"""Tests the error message of using --target-env without equal sign and
arguments"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-env'\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvNoEqWithArg(expect.ErrorMessage):
"""Tests the error message of using --target-env without equal sign but
arguments"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env', 'opengl', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-env'\n"]
@inside_glslc_testsuite('OptionTargetEnv')
class TestTargetEnvEqWrongArg(expect.ErrorMessage):
"""Tests the error message of using --target-env with wrong argument"""
shader = FileShader(opengl_vertex_shader(), '.vert')
glslc_args = ['--target-env=wrong_arg', shader]
expected_error = ["glslc: error: invalid value ",
"'wrong_arg' in '--target-env=wrong_arg'\n"]

View File

@@ -0,0 +1,125 @@
# Copyright 2019 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
def vulkan_vertex_shader():
return """#version 310 es
void main() { int t = gl_VertexIndex; }"""
def vulkan_compute_subgroup_shader():
"""Returns a compute shader that requires Vulkan 1.1 and SPIR-V 1.3"""
return """#version 450
#extension GL_KHR_shader_subgroup_basic : enable
void main() { subgroupBarrier(); }"""
@inside_glslc_testsuite('OptionTargetSpv')
class TestDefaultTargetSpvWithVulkanShader(expect.ValidObjectFile):
"""Tests that compiling a Vulkan-specific shader with a default
target environment succeeds"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestDefaultTargetSpvWithShaderRequiringSpv1p3Fails(expect.ErrorMessageSubstr):
"""Tests that compiling a shader requiring SPIR-V 1.3 with default SPIR-V
target should fail.
"""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['-c', shader]
expected_error_substr = ["error: 'subgroup op' : requires SPIR-V 1.3\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p2WithShaderRequiringSpv1p3Fails(expect.ErrorMessageSubstr):
"""Tests that compiling a shader requiring SPIR-V 1.3 but targeting 1.2
should fail.
"""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-spv=spv1.2', '-c', shader]
expected_error_substr = ["error: 'subgroup op' : requires SPIR-V 1.3\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p3(expect.ValidObjectFile1_3):
"""Tests that compiling to spv1.3 succeeds and generates SPIR-V 1.3 binary."""
shader = FileShader(vulkan_compute_subgroup_shader(), '.comp')
glslc_args = ['--target-spv=spv1.3', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p4(expect.ValidObjectFile1_4):
"""Tests that compiling to spv1.4 succeeds and generates SPIR-V 1.4 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.4', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p5(expect.ValidObjectFile1_5):
"""Tests that compiling to spv1.5 succeeds and generates SPIR-V 1.5 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.5', '-c', shader]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpv1p5(expect.ValidObjectFile1_6):
"""Tests that compiling to spv1.6 succeeds and generates SPIR-V 1.6 binary."""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=spv1.6', '-c', shader]
### Option parsing error cases
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoArg(expect.ErrorMessage):
"""Tests the error message of assigning empty string to --target-spv"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=', shader]
expected_error = ["glslc: error: invalid value ",
"'' in '--target-spv='\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoEqNoArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv without equal sign and
arguments"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-spv'\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvNoEqWithArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv without equal sign but
arguments"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv', 'spv1.3', shader]
expected_error = ["glslc: error: unsupported option: ",
"'--target-spv'\n"]
@inside_glslc_testsuite('OptionTargetSpv')
class TestTargetSpvEqWrongArg(expect.ErrorMessage):
"""Tests the error message of using --target-spv with wrong argument"""
shader = FileShader(vulkan_vertex_shader(), '.vert')
glslc_args = ['--target-spv=wrong_arg', shader]
expected_error = ["glslc: error: invalid value ",
"'wrong_arg' in '--target-spv=wrong_arg'\n"]

View File

@@ -0,0 +1,390 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
import os.path
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader, TempFileName
@inside_glslc_testsuite('File')
class SimpleFileCompiled(expect.ValidObjectFile):
"""Tests whether or not a simple glsl file compiles."""
shader = FileShader('#version 310 es\nvoid main() {}', '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('File')
class NotSpecifyingOutputName(expect.SuccessfulReturn,
expect.CorrectObjectFilePreamble):
"""Tests that when there is no -o and -E/-S/-c specified, output as a.spv."""
shader = FileShader('#version 140\nvoid main() {}', '.frag')
glslc_args = [shader]
def check_output_a_spv(self, status):
output_name = os.path.join(status.directory, 'a.spv')
return self.verify_object_file_preamble(output_name)
@inside_glslc_testsuite('Parameters')
class HelpParameters(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
"""Tests the --help flag outputs correctly and does not produce and error."""
glslc_args = ['--help']
expected_stdout = '''glslc - Compile shaders into SPIR-V
Usage: glslc [options] file...
An input file of - represents standard input.
Options:
-c Only run preprocess, compile, and assemble steps.
-Dmacro[=defn] Add an implicit macro definition.
-E Outputs only the results of the preprocessing step.
Output defaults to standard output.
-fauto-bind-uniforms
Automatically assign bindings to uniform variables that
don't have an explicit 'binding' layout in the shader
source.
-fauto-map-locations
Automatically assign locations to uniform variables that
don't have an explicit 'location' layout in the shader
source.
-fauto-combined-image-sampler
Removes sampler variables and converts existing textures
to combined image-samplers.
-fentry-point=<name>
Specify the entry point name for HLSL compilation, for
all subsequent source files. Default is "main".
-fhlsl-16bit-types
Enable 16-bit type support for HLSL.
-fhlsl_functionality1, -fhlsl-functionality1
Enable extension SPV_GOOGLE_hlsl_functionality1 for HLSL
compilation.
-fhlsl-iomap Use HLSL IO mappings for bindings.
-fhlsl-offsets Use HLSL offset rules for packing members of blocks.
Affects only GLSL. HLSL rules are always used for HLSL.
-finvert-y Invert position.Y output in vertex shader.
-flimit=<settings>
Specify resource limits. Each limit is specified by a limit
name followed by an integer value. Tokens should be
separated by whitespace. If the same limit is specified
several times, only the last setting takes effect.
-flimit-file <file>
Set limits as specified in the given file.
-fnan-clamp Generate code for max and min builtins so that, when given
a NaN operand, the other operand is returned. Similarly,
the clamp builtin will favour the non-NaN operands, as if
clamp were implemented as a composition of max and min.
-fpreserve-bindings
Preserve all binding declarations, even if those bindings
are not used.
-fresource-set-binding [stage] <reg0> <set0> <binding0>
[<reg1> <set1> <binding1>...]
Explicitly sets the descriptor set and binding for
HLSL resources, by register name. Optionally restrict
it to a single stage.
-fcbuffer-binding-base [stage] <value>
Same as -fubo-binding-base.
-fimage-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
images. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fsampler-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
samplers Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fssbo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
shader storage buffer objects (SSBO). Optionally only set
it for a single shader stage. Only affects GLSL.
-ftexture-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
textures. Optionally only set it for a single shader stage.
For HLSL, the resource register number is added to this
base.
-fuav-binding-base [stage] <value>
For automatically assigned bindings for unordered access
views (UAV), the register number is added to this base to
determine the binding number. Optionally only set it for
a single shader stage. Only affects HLSL.
-fubo-binding-base [stage] <value>
Sets the lowest automatically assigned binding number for
uniform buffer objects (UBO). Optionally only set it for
a single shader stage.
For HLSL, the resource register number is added to this
base.
-fshader-stage=<stage>
Treat subsequent input files as having stage <stage>.
Valid stages are vertex, vert, fragment, frag, tesscontrol,
tesc, tesseval, tese, geometry, geom, compute, and comp.
-g Generate source-level debug information.
-h Display available options.
--help Display available options.
-I <value> Add directory to include search path.
-mfmt=<format> Output SPIR-V binary code using the selected format. This
option may be specified only when the compilation output is
in SPIR-V binary code form. Available options are:
bin - SPIR-V binary words. This is the default.
c - Binary words as C initializer list of 32-bit ints
num - List of comma-separated 32-bit hex integers
-M Generate make dependencies. Implies -E and -w.
-MM An alias for -M.
-MD Generate make dependencies and compile.
-MF <file> Write dependency output to the given file.
-MT <target> Specify the target of the rule emitted by dependency
generation.
-O Optimize the generated SPIR-V code for better performance.
-Os Optimize the generated SPIR-V code for smaller size.
-O0 Disable optimization.
-o <file> Write output to <file>.
A file name of '-' represents standard output.
-std=<value> Version and profile for GLSL input files. Possible values
are concatenations of version and profile, e.g. 310es,
450core, etc. Ignored for HLSL files.
-S Emit SPIR-V assembly instead of binary.
--show-limits Display available limit names and their default values.
--target-env=<environment>
Set the target client environment, and the semantics
of warnings and errors. An optional suffix can specify
the client version. Values are:
vulkan1.0 # The default
vulkan1.1
vulkan1.2
vulkan1.3
vulkan # Same as vulkan1.0
opengl4.5
opengl # Same as opengl4.5
--target-spv=<spirv-version>
Set the SPIR-V version to be used for the generated SPIR-V
module. The default is the highest version of SPIR-V
required to be supported for the target environment.
For example, default for vulkan1.0 is spv1.0, and
the default for vulkan1.1 is spv1.3,
the default for vulkan1.2 is spv1.5.
the default for vulkan1.3 is spv1.6.
Values are:
spv1.0, spv1.1, spv1.2, spv1.3, spv1.4, spv1.5, spv1.6
--version Display compiler version information.
-w Suppresses all warning messages.
-Werror Treat all warnings as errors.
-x <language> Treat subsequent input files as having type <language>.
Valid languages are: glsl, hlsl.
For files ending in .hlsl the default is hlsl.
Otherwise the default is glsl.
'''
expected_stderr = ''
@inside_glslc_testsuite('Parameters')
class HelpIsNotTooWide(expect.StdoutNoWiderThan80Columns):
"""Tests that --help output is not too wide."""
glslc_args = ['--help']
@inside_glslc_testsuite('Parameters')
class UnknownSingleLetterArgument(expect.ErrorMessage):
"""Tests that an unknown argument triggers an error message."""
glslc_args = ['-a']
expected_error = ["glslc: error: unknown argument: '-a'\n"]
@inside_glslc_testsuite('Parameters')
class UnknownMultiLetterArgument(expect.ErrorMessage):
"""Tests that an unknown argument triggers an error message."""
glslc_args = ['-zzz']
expected_error = ["glslc: error: unknown argument: '-zzz'\n"]
@inside_glslc_testsuite('Parameters')
class UnsupportedOption(expect.ErrorMessage):
"""Tests that an unsupported option triggers an error message."""
glslc_args = ['--unsupported-option']
expected_error = [
"glslc: error: unsupported option: '--unsupported-option'\n"]
@inside_glslc_testsuite('File')
class FileNotFound(expect.ErrorMessage):
"""Tests the error message if a file cannot be found."""
blabla_file = TempFileName('blabla.frag')
glslc_args = [blabla_file]
expected_error = [
"glslc: error: cannot open input file: '", blabla_file,
"': No such file or directory\n"]
@inside_glslc_testsuite('Unsupported')
class LinkingNotSupported(expect.ErrorMessage):
"""Tests the error message generated by linking not supported yet."""
shader1 = FileShader('#version 140\nvoid main() {}', '.vert')
shader2 = FileShader('#version 140\nvoid main() {}', '.frag')
glslc_args = [shader1, shader2]
expected_error = [
'glslc: error: linking multiple files is not supported yet. ',
'Use -c to compile files individually.\n']
@inside_glslc_testsuite('Unsupported')
class MultipleStdinUnsupported(expect.ErrorMessage):
"""Tests the error message generated by having more than one - input."""
glslc_args = ['-c', '-fshader-stage=vertex', '-', '-']
expected_error = [
'glslc: error: specifying standard input "-" as input more'
' than once is not allowed.\n']
@inside_glslc_testsuite('Parameters')
class StdinWithoutShaderStage(expect.StdoutMatch, expect.StderrMatch):
"""Tests that you must use -fshader-stage when specifying - as input."""
shader = StdinShader(
"""#version 140
int a() {
}
void main() {
int x = a();
}
""")
glslc_args = [shader]
expected_stdout = ''
expected_stderr = [
"glslc: error: '-': -fshader-stage required when input is from "
'standard input "-"\n']
@inside_glslc_testsuite('Parameters')
class LimitsHelp(expect.StdoutMatch, expect.StderrMatch):
"""Tests --show-limits shows correct output."""
glslc_args = ['--show-limits']
expected_stderr = ''
expected_stdout = """MaxLights 8
MaxClipPlanes 6
MaxTextureUnits 2
MaxTextureCoords 8
MaxVertexAttribs 16
MaxVertexUniformComponents 4096
MaxVaryingFloats 60
MaxVertexTextureImageUnits 16
MaxCombinedTextureImageUnits 80
MaxTextureImageUnits 16
MaxFragmentUniformComponents 1024
MaxDrawBuffers 8
MaxVertexUniformVectors 256
MaxVaryingVectors 15
MaxFragmentUniformVectors 256
MaxVertexOutputVectors 16
MaxFragmentInputVectors 15
MinProgramTexelOffset -8
MaxProgramTexelOffset 7
MaxClipDistances 8
MaxComputeWorkGroupCountX 65535
MaxComputeWorkGroupCountY 65535
MaxComputeWorkGroupCountZ 65535
MaxComputeWorkGroupSizeX 1024
MaxComputeWorkGroupSizeY 1024
MaxComputeWorkGroupSizeZ 64
MaxComputeUniformComponents 512
MaxComputeTextureImageUnits 16
MaxComputeImageUniforms 8
MaxComputeAtomicCounters 8
MaxComputeAtomicCounterBuffers 1
MaxVaryingComponents 60
MaxVertexOutputComponents 64
MaxGeometryInputComponents 64
MaxGeometryOutputComponents 128
MaxFragmentInputComponents 128
MaxImageUnits 8
MaxCombinedImageUnitsAndFragmentOutputs 8
MaxCombinedShaderOutputResources 8
MaxImageSamples 0
MaxVertexImageUniforms 0
MaxTessControlImageUniforms 0
MaxTessEvaluationImageUniforms 0
MaxGeometryImageUniforms 0
MaxFragmentImageUniforms 8
MaxCombinedImageUniforms 8
MaxGeometryTextureImageUnits 16
MaxGeometryOutputVertices 256
MaxGeometryTotalOutputComponents 1024
MaxGeometryUniformComponents 512
MaxGeometryVaryingComponents 60
MaxTessControlInputComponents 128
MaxTessControlOutputComponents 128
MaxTessControlTextureImageUnits 16
MaxTessControlUniformComponents 1024
MaxTessControlTotalOutputComponents 4096
MaxTessEvaluationInputComponents 128
MaxTessEvaluationOutputComponents 128
MaxTessEvaluationTextureImageUnits 16
MaxTessEvaluationUniformComponents 1024
MaxTessPatchComponents 120
MaxPatchVertices 32
MaxTessGenLevel 64
MaxViewports 16
MaxVertexAtomicCounters 0
MaxTessControlAtomicCounters 0
MaxTessEvaluationAtomicCounters 0
MaxGeometryAtomicCounters 0
MaxFragmentAtomicCounters 8
MaxCombinedAtomicCounters 8
MaxAtomicCounterBindings 1
MaxVertexAtomicCounterBuffers 0
MaxTessControlAtomicCounterBuffers 0
MaxTessEvaluationAtomicCounterBuffers 0
MaxGeometryAtomicCounterBuffers 0
MaxFragmentAtomicCounterBuffers 0
MaxCombinedAtomicCounterBuffers 1
MaxAtomicCounterBufferSize 32
MaxTransformFeedbackBuffers 4
MaxTransformFeedbackInterleavedComponents 64
MaxCullDistances 8
MaxCombinedClipAndCullDistances 8
MaxSamples 4
MaxMeshOutputVerticesNV 256
MaxMeshOutputPrimitivesNV 512
MaxMeshWorkGroupSizeX_NV 32
MaxMeshWorkGroupSizeY_NV 1
MaxMeshWorkGroupSizeZ_NV 1
MaxTaskWorkGroupSizeX_NV 32
MaxTaskWorkGroupSizeY_NV 1
MaxTaskWorkGroupSizeZ_NV 1
MaxMeshViewCountNV 4
MaxMeshOutputVerticesEXT 256
MaxMeshOutputPrimitivesEXT 256
MaxMeshWorkGroupSizeX_EXT 128
MaxMeshWorkGroupSizeY_EXT 128
MaxMeshWorkGroupSizeZ_EXT 128
MaxTaskWorkGroupSizeX_EXT 128
MaxTaskWorkGroupSizeY_EXT 128
MaxTaskWorkGroupSizeZ_EXT 128
MaxMeshViewCountEXT 4
MaxDualSourceDrawBuffersEXT 1
"""

View File

@@ -0,0 +1,143 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
"""A number of placeholders and their rules for expansion when used in tests.
These placeholders, when used in glslc_args or expected_* variables of
GlslCTest, have special meanings. In glslc_args, they will be substituted by
the result of instantiate_for_glslc_args(), while in expected_*, by
instantiate_for_expectation(). A TestCase instance will be passed in as
argument to the instantiate_*() methods.
"""
import os
import tempfile
from string import Template
from builtins import bytes
class PlaceHolderException(Exception):
"""Exception class for PlaceHolder."""
pass
class PlaceHolder(object):
"""Base class for placeholders."""
def instantiate_for_glslc_args(self, testcase):
"""Instantiation rules for glslc_args.
This method will be called when the current placeholder appears in
glslc_args.
Returns:
A string to replace the current placeholder in glslc_args.
"""
raise PlaceHolderException('Subclass should implement this function.')
def instantiate_for_expectation(self, testcase):
"""Instantiation rules for expected_*.
This method will be called when the current placeholder appears in
expected_*.
Returns:
A string to replace the current placeholder in expected_*.
"""
raise PlaceHolderException('Subclass should implement this function.')
class FileShader(PlaceHolder):
"""Stands for a shader whose source code is in a file."""
def __init__(self, source, suffix, assembly_substr=None):
assert isinstance(source, str)
assert isinstance(suffix, str)
self.source = source
self.suffix = suffix
self.filename = None
# If provided, this is a substring which is expected to be in
# the disassembly of the module generated from this input file.
self.assembly_substr = assembly_substr
def instantiate_for_glslc_args(self, testcase):
"""Creates a temporary file and writes the source into it.
Returns:
The name of the temporary file.
"""
shader, self.filename = tempfile.mkstemp(
dir=testcase.directory, suffix=self.suffix)
shader_object = os.fdopen(shader, 'w')
shader_object.write(self.source)
shader_object.close()
return self.filename
def instantiate_for_expectation(self, testcase):
assert self.filename is not None
return self.filename
class StdinShader(PlaceHolder):
"""Stands for a shader whose source code is from stdin."""
def __init__(self, source):
assert isinstance(source, str)
self.source = source
self.filename = None
def instantiate_for_glslc_args(self, testcase):
"""Writes the source code back to the TestCase instance."""
testcase.stdin_shader = bytes(self.source, 'utf-8')
self.filename = '-'
return self.filename
def instantiate_for_expectation(self, testcase):
assert self.filename is not None
return self.filename
class TempFileName(PlaceHolder):
"""Stands for a temporary file's name."""
def __init__(self, filename):
assert isinstance(filename, str)
assert filename != ''
self.filename = filename
def instantiate_for_glslc_args(self, testcase):
return os.path.join(testcase.directory, self.filename)
def instantiate_for_expectation(self, testcase):
return os.path.join(testcase.directory, self.filename)
class SpecializedString(PlaceHolder):
"""Returns a string that has been specialized based on TestCase.
The string is specialized by expanding it as a string.Template
with all of the specialization being done with each $param replaced
by the associated member on TestCase.
"""
def __init__(self, filename):
assert isinstance(filename, str)
assert filename != ''
self.filename = filename
def instantiate_for_glslc_args(self, testcase):
return Template(self.filename).substitute(vars(testcase))
def instantiate_for_expectation(self, testcase):
return Template(self.filename).substitute(vars(testcase))

View File

@@ -0,0 +1,461 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from environment import Directory, File
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
VERTEX_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}"""
FRAGMENT_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(fragment)
void main() {
gl_FragDepth = 10.;
}"""
TESS_CONTROL_ONLY_SHADER_WITH_PRAGMA = \
"""#version 440 core
#pragma shader_stage(tesscontrol)
layout(vertices = 3) out;
void main() { }"""
TESS_EVAL_ONLY_SHADER_WITH_PRAGMA = \
"""#version 440 core
#pragma shader_stage(tesseval)
layout(triangles) in;
void main() { }"""
GEOMETRY_ONLY_SHDER_WITH_PRAGMA = \
"""#version 150 core
#pragma shader_stage(geometry)
layout (triangles) in;
layout (line_strip, max_vertices = 4) out;
void main() { }"""
COMPUTE_ONLY_SHADER_WITH_PRAGMA = \
"""#version 310 es
#pragma shader_stage(compute)
void main() {
uvec3 temp = gl_WorkGroupID;
}"""
# In the following tests,
# PSS stands for PragmaShaderStage, and OSS stands for OptionShaderStage.
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithGlslExtension(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with .glsl extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithUnkownExtension(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with unknown extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.unkown')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithStdin(expect.ValidObjectFile):
"""Tests #pragma shader_stage() with stdin."""
shader = StdinShader(VERTEX_ONLY_SHADER_WITH_PRAGMA)
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithSameShaderExtension(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() specifies the same stage as file
extesion."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.vert')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSOverrideShaderExtension(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() overrides file extension."""
shader = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.frag')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestOSSOverridePSS(expect.ValidObjectFile):
"""Tests that -fshader-stage overrides #pragma shader_stage()."""
# wrong pragma and wrong file extension
shader = FileShader(
"""#version 310 es
#pragma shader_stage(fragment)
void main() {
gl_Position = vec4(1.);
}""", '.frag')
# -fshader-stage to the rescue! ^.^
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestMultipleSamePSS(expect.ValidObjectFile):
"""Tests that multiple identical #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(vertex)
#pragma shader_stage(vertex)
void main() {
#pragma shader_stage(vertex)
gl_Position = vec4(1.);
#pragma shader_stage(vertex)
}
#pragma shader_stage(vertex)
#pragma shader_stage(vertex)
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestConflictingPSS(expect.ErrorMessage):
"""Conflicting #pragma shader_stage() directives result in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
#pragma shader_stage(fragment)
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":6: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'fragment' (was 'vertex' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestAllPSSValues(expect.ValidObjectFile):
"""Tests all possible #pragma shader_stage() values."""
shader1 = FileShader(VERTEX_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader2 = FileShader(FRAGMENT_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader3 = FileShader(TESS_CONTROL_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader4 = FileShader(TESS_EVAL_ONLY_SHADER_WITH_PRAGMA, '.glsl')
shader5 = FileShader(GEOMETRY_ONLY_SHDER_WITH_PRAGMA, '.glsl')
shader6 = FileShader(COMPUTE_ONLY_SHADER_WITH_PRAGMA, '.glsl')
glslc_args = ['-c', shader1, shader2, shader3, shader4, shader5, shader6]
@inside_glslc_testsuite('PragmaShaderStage')
class TestWrongPSSValue(expect.ErrorMessage):
"""Tests that #pragma shader_stage([wrong-stage]) results in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(superstage)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'superstage'\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestEmptyPSSValue(expect.ErrorMessage):
"""Tests that #pragma shader_stage([empty]) results in an error."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage()
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: ''\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestFirstPSSBeforeNonPPCode(expect.ErrorMessage):
"""Tests that the first #pragma shader_stage() should appear before
any non-preprocessing code."""
shader = FileShader(
"""#version 310 es
#ifndef REMOVE_UNUSED_FUNCTION
int inc(int i) { return i + 1; }
#endif
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":5: error: '#pragma': the first 'shader_stage' #pragma "
'must appear before any non-preprocessing code\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSMultipleErrors(expect.ErrorMessage):
"""Tests that if there are multiple errors, they are all reported."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(idontknow)
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
#pragma shader_stage(fragment)
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'idontknow'\n",
shader, ":3: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'vertex' (was 'idontknow' at ", shader, ':2)\n',
shader, ":7: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'fragment' (was 'idontknow' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestSpacesAroundPSS(expect.ValidObjectFile):
"""Tests that spaces around #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
# pragma shader_stage ( vertex )
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestTabsAroundPSS(expect.ValidObjectFile):
"""Tests that tabs around #pragma shader_stage() works."""
shader = FileShader(
"""#version 310 es
\t\t#\tpragma\t\t\tshader_stage\t\t(\t\t\t\tvertex\t\t)\t\t\t\t
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithMacro(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() works with macros."""
shader = FileShader(
"""#version 310 es
#if 0
some random stuff here which can cause a problem
#else
# pragma shader_stage(vertex)
#endif
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithCmdLineMacroDef(expect.ValidObjectFile):
"""Tests that macro definitions passed in from command line work."""
shader = FileShader(
"""#version 310 es
#ifdef IS_A_VERTEX_SHADER
# pragma shader_stage(vertex)
#else
# pragma shader_stage(fragment)
#endif
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', '-DIS_A_VERTEX_SHADER', shader]
@inside_glslc_testsuite('PragmaShaderStage')
class TestNoMacroExpansionInsidePSS(expect.ErrorMessage):
"""Tests that there is no macro expansion inside #pragma shader_stage()."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(STAGE_FROM_CMDLINE)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', '-DSTAGE_FROM_CMDLINE=vertex', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'STAGE_FROM_CMDLINE'\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithPoundLine310(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with #line."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(unknown)
#line 42
#pragma shader_stage(google)
#line 100
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
shader, ":42: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
shader, ":100: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithPoundLine150(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with #line.
For older desktop versions, a #line directive specify the line number of
the #line directive, not the next line.
"""
shader = FileShader(
"""#version 150
#pragma shader_stage(unknown)
#line 42
#pragma shader_stage(google)
#line 100
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
shader, ":43: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
shader, ":101: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']
@inside_glslc_testsuite('PragmaShaderStage')
class ErrorBeforePragma(expect.ErrorMessage):
"""Tests that errors before pragmas are emitted."""
shader = FileShader(
"""#version 310 es
#something
#pragma shader_stage(vertex)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [shader, ':2: error: \'#\' : invalid directive:',
' something\n'
'1 error generated.\n']
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSfromIncludedFile(expect.ValidObjectFile):
"""Tests that #pragma shader_stage() from included files works."""
environment = Directory('.', [
File('a.glsl', '#version 140\n#include "b.glsl"\n'
'void main() { gl_Position = vec4(1.); }\n'),
File('b.glsl', '#pragma shader_stage(vertex)')])
glslc_args = ['-c', 'a.glsl']
@inside_glslc_testsuite('PragmaShaderStage')
class TestConflictingPSSfromIncludingAndIncludedFile(expect.ErrorMessage):
"""Tests that conflicting #pragma shader_stage() from including and
included files results in an error with the correct location spec."""
environment = Directory('.', [
File('a.vert',
'#version 140\n'
'#pragma shader_stage(fragment)\n'
'void main() { gl_Position = vec4(1.); }\n'
'#include "b.glsl"\n'),
File('b.glsl', '#pragma shader_stage(vertex)')])
glslc_args = ['-c', 'a.vert']
expected_error = [
"b.glsl:1: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'vertex' (was 'fragment' at a.vert:2)\n"]
@inside_glslc_testsuite('PragmaShaderStage')
class TestPSSWithFileNameBasedPoundLine(expect.ErrorMessage):
"""Tests that #pragma shader_stage() works with filename-based #line."""
shader = FileShader(
"""#version 310 es
#pragma shader_stage(unknown)
#line 42 "abc"
#pragma shader_stage(google)
#line 100 "def"
#pragma shader_stage(elgoog)
void main() {
gl_Position = vec4(1.);
}
""", '.glsl')
glslc_args = ['-c', shader]
expected_error = [
shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
"#pragma: 'unknown'\n",
"abc:42: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'google' (was 'unknown' at ", shader, ':2)\n',
"def:100: error: '#pragma': conflicting stages for 'shader_stage' "
"#pragma: 'elgoog' (was 'unknown' at ", shader, ':2)\n']

View File

@@ -0,0 +1,37 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import expect
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader, StdinShader
@inside_glslc_testsuite('StdInOut')
class VerifyStdinWorks(expect.ValidObjectFile):
"""Tests glslc accepts vertex shader extension (.vert)."""
shader = StdinShader('#version 140\nvoid main() { }')
glslc_args = ['-c', '-fshader-stage=vertex', shader]
@inside_glslc_testsuite('StdInOut')
class VerifyStdoutWorks(
expect.ReturnCodeIsZero, expect.StdoutMatch, expect.StderrMatch):
shader = FileShader('#version 140\nvoid main() {}', '.vert')
glslc_args = [shader, '-o', '-']
# We expect SOME stdout, we just do not care what.
expected_stdout = True
expected_stderr = ''

View File

@@ -0,0 +1,221 @@
# Copyright 2015 The Shaderc Authors. All rights reserved.
#
# 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.
import os.path
import expect
from environment import File, Directory
from glslc_test_framework import inside_glslc_testsuite
from placeholder import FileShader
MINIMAL_SHADER = '#version 140\nvoid main() {}'
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirNoArg(expect.ErrorMessage):
"""Tests -working-directory. Behavior cribbed from Clang."""
glslc_args = ['-working-directory']
expected_error = [
"glslc: error: argument to '-working-directory' is missing "
'(expected 1 value)\n',
'glslc: error: no input files\n']
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqNoArg(expect.ErrorMessage):
"""Tests -working-directory=<empty>. Behavior cribbed from Clang."""
glslc_args = ['-working-directory=']
expected_error = ['glslc: error: no input files\n']
EMPTY_SHADER_IN_SUBDIR = Directory(
'subdir', [File('shader.vert', MINIMAL_SHADER)])
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqNoArgCompileFile(expect.ValidNamedObjectFile):
"""Tests -working-directory=<empty> when compiling input file."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=', 'subdir/shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestMultipleWorkDir(expect.ValidNamedObjectFile):
"""Tests that if there are multiple -working-directory=<dir> specified,
only the last one takes effect."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=i-dont-exist',
'-working-directory', 'i-think/me-neither',
'-working-directory=subdir', 'shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirPosition(expect.ValidNamedObjectFile):
"""Tests that -working-directory=<dir> affects all files before and after
it on the command line."""
environment = Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
File('cool.frag', MINIMAL_SHADER),
File('bla.vert', MINIMAL_SHADER)
])
glslc_args = ['-c', 'shader.vert', 'bla.vert',
'-working-directory=subdir', 'cool.frag']
# Output file should be generated into subdir/.
expected_object_filenames = (
'subdir/shader.vert.spv', 'subdir/cool.frag.spv', 'subdir/bla.vert.spv')
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirDeepDir(expect.ValidNamedObjectFile):
"""Tests that -working-directory=<dir> works with directory hierarchies."""
environment = Directory('subdir', [
Directory('subsubdir', [
File('one.vert', MINIMAL_SHADER),
File('two.frag', MINIMAL_SHADER)
]),
File('zero.vert', MINIMAL_SHADER)
])
glslc_args = ['-c', 'zero.vert', 'subsubdir/one.vert',
'subsubdir/two.frag', '-working-directory=subdir']
# Output file should be generated into subdir/.
expected_object_filenames = (
'subdir/zero.vert.spv', 'subdir/subsubdir/one.vert.spv',
'subdir/subsubdir/two.frag.spv')
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFile(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir> when compiling input file."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-c', '-working-directory=subdir', 'shader.vert']
# Output file should be generated into subdir/.
expected_object_filenames = ('subdir/shader.vert.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFileOutput(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir> when compiling input file and specifying
output filename."""
environment = Directory('.', [
Directory('subdir', [
Directory('bin', []),
File('shader.vert', MINIMAL_SHADER)
])
])
glslc_args = ['-c', '-o', 'bin/spv', '-working-directory=subdir',
'shader.vert']
# Output file should be generated into subdir/bin/.
expected_object_filenames = ('subdir/bin/spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirArgNoEq(expect.ValidNamedObjectFile):
"""Tests -working-directory <dir>."""
environment = Directory('.', [EMPTY_SHADER_IN_SUBDIR])
glslc_args = ['-working-directory', 'subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirEqInArg(expect.ValidNamedObjectFile):
"""Tests -working-directory=<dir-with-equal-sign-inside>."""
environment = Directory('.', [
Directory('=subdir', [File('shader.vert', MINIMAL_SHADER)]),
])
glslc_args = ['-working-directory==subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirCompileFileAbsolutePath(expect.ValidObjectFile):
"""Tests -working-directory=<dir> when compiling input file with absolute
path."""
shader = FileShader(MINIMAL_SHADER, '.vert')
glslc_args = ['-c', '-working-directory=subdir', shader]
# The -working-directory flag should not affect the placement of the link file.
# The following tests ensure that.
class WorkDirDoesntAffectLinkedFile(expect.ValidNamedObjectFile):
"""A base class for tests asserting that -working-directory has no impact
on the location of the output link file.
"""
environment = Directory('.', [
Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
# Try to fake glslc into putting the linked file here, though it
# shouldn't (because -working-directory doesn't impact -o).
Directory('bin', [])]),
File('shader.vert', "fake file, doesn't compile."),
Directory('bin', [])])
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileDefaultLocation(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the default link-file
location.
"""
glslc_args = ['-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('a.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileExplicit(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the named link-file
location.
"""
glslc_args = ['-o', 'b.spv', '-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('b.spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileInSubdir(WorkDirDoesntAffectLinkedFile):
"""Tests that -working-directory doesn't impact the link-file sent into an
existing subdirectory.
"""
glslc_args = ['-o', 'bin/spv', '-working-directory=subdir', 'shader.vert']
expected_object_filenames = ('bin/spv',)
# @inside_glslc_testsuite('WorkDir')
class TestWorkDirLinkFileInvalidPath(expect.ErrorMessage):
"""Tests that -working-directory doesn't impact the error generated for an
invalid -o path.
"""
environment = Directory('.', [
Directory('subdir', [
File('shader.vert', MINIMAL_SHADER),
Directory('missing', [])]), # Present here, but missing in parent.
File('shader.vert', "fake file, doesn't compile.")])
glslc_args = [
'-o', 'missing/spv', '-working-directory=subdir', 'shader.vert']
expected_error = ['glslc: error: cannot open output file: ',
"'missing/spv': No such file or directory\n"]