summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/glslang/src/gtests/TestFixture.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/glslang/src/gtests/TestFixture.h')
-rw-r--r--chromium/third_party/glslang/src/gtests/TestFixture.h341
1 files changed, 341 insertions, 0 deletions
diff --git a/chromium/third_party/glslang/src/gtests/TestFixture.h b/chromium/third_party/glslang/src/gtests/TestFixture.h
new file mode 100644
index 00000000000..e71bab1c4c2
--- /dev/null
+++ b/chromium/third_party/glslang/src/gtests/TestFixture.h
@@ -0,0 +1,341 @@
+//
+// Copyright (C) 2016 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GLSLANG_GTESTS_TEST_FIXTURE_H
+#define GLSLANG_GTESTS_TEST_FIXTURE_H
+
+#include <stdint.h>
+#include <fstream>
+#include <sstream>
+#include <streambuf>
+#include <tuple>
+
+#include <gtest/gtest.h>
+
+#include "SPIRV/GlslangToSpv.h"
+#include "SPIRV/disassemble.h"
+#include "SPIRV/doc.h"
+#include "StandAlone/ResourceLimits.h"
+#include "glslang/Public/ShaderLang.h"
+
+#include "Initializer.h"
+#include "Settings.h"
+
+// We need CMake to provide us the absolute path to the directory containing
+// test files, so we are certain to find those files no matter where the test
+// harness binary is generated. This provides out-of-source build capability.
+#ifndef GLSLANG_TEST_DIRECTORY
+#error \
+ "GLSLANG_TEST_DIRECTORY needs to be defined for gtest to locate test files."
+#endif
+
+namespace glslangtest {
+
+// This function is used to provide custom test name suffixes based on the
+// shader source file names. Otherwise, the test name suffixes will just be
+// numbers, which are not quite obvious.
+std::string FileNameAsCustomTestSuffix(
+ const ::testing::TestParamInfo<std::string>& info);
+
+enum class Source {
+ GLSL,
+ HLSL,
+};
+
+// Enum for shader compilation semantics.
+enum class Semantics {
+ OpenGL,
+ Vulkan,
+};
+
+// Enum for compilation target.
+enum class Target {
+ AST,
+ Spv,
+ BothASTAndSpv,
+};
+
+EShLanguage GetShaderStage(const std::string& stage);
+
+EShMessages DeriveOptions(Source, Semantics, Target);
+
+// Reads the content of the file at the given |path|. On success, returns true
+// and the contents; otherwise, returns false and an empty string.
+std::pair<bool, std::string> ReadFile(const std::string& path);
+
+// Writes the given |contents| into the file at the given |path|. Returns true
+// on successful output.
+bool WriteFile(const std::string& path, const std::string& contents);
+
+// Returns the suffix of the given |name|.
+std::string GetSuffix(const std::string& name);
+
+// Base class for glslang integration tests. It contains many handy utility-like
+// methods such as reading shader source files, compiling into AST/SPIR-V, and
+// comparing with expected outputs.
+//
+// To write value-Parameterized tests:
+// using ValueParamTest = GlslangTest<::testing::TestWithParam<std::string>>;
+// To use as normal fixture:
+// using FixtureTest = GlslangTest<::testing::Test>;
+template <typename GT>
+class GlslangTest : public GT {
+public:
+ GlslangTest()
+ : defaultVersion(100),
+ defaultProfile(ENoProfile),
+ forceVersionProfile(false),
+ isForwardCompatible(false) {}
+
+ // Tries to load the contents from the file at the given |path|. On success,
+ // writes the contents into |contents|. On failure, errors out.
+ void tryLoadFile(const std::string& path, const std::string& tag,
+ std::string* contents)
+ {
+ bool fileReadOk;
+ std::tie(fileReadOk, *contents) = ReadFile(path);
+ ASSERT_TRUE(fileReadOk) << "Cannot open " << tag << " file: " << path;
+ }
+
+ // Checks the equality of |expected| and |real|. If they are not equal,
+ // write |real| to the given file named as |fname| if update mode is on.
+ void checkEqAndUpdateIfRequested(const std::string& expected,
+ const std::string& real,
+ const std::string& fname)
+ {
+ // In order to output the message we want under proper circumstances,
+ // we need the following operator<< stuff.
+ EXPECT_EQ(expected, real)
+ << (GlobalTestSettings.updateMode
+ ? ("Mismatch found and update mode turned on - "
+ "flushing expected result output.")
+ : "");
+
+ // Update the expected output file if requested.
+ // It looks weird to duplicate the comparison between expected_output
+ // and stream.str(). However, if creating a variable for the comparison
+ // result, we cannot have pretty print of the string diff in the above.
+ if (GlobalTestSettings.updateMode && expected != real) {
+ EXPECT_TRUE(WriteFile(fname, real)) << "Flushing failed";
+ }
+ }
+
+ struct ShaderResult {
+ std::string shaderName;
+ std::string output;
+ std::string error;
+ };
+
+ // A struct for holding all the information returned by glslang compilation
+ // and linking.
+ struct GlslangResult {
+ std::vector<ShaderResult> shaderResults;
+ std::string linkingOutput;
+ std::string linkingError;
+ std::string spirvWarningsErrors;
+ std::string spirv; // Optional SPIR-V disassembly text.
+ };
+
+ // Compiles and the given source |code| of the given shader |stage| into
+ // the target under the semantics conveyed via |controls|. Returns true
+ // and modifies |shader| on success.
+ bool compile(glslang::TShader* shader, const std::string& code,
+ const std::string& entryPointName, EShMessages controls,
+ const TBuiltInResource* resources=nullptr)
+ {
+ const char* shaderStrings = code.data();
+ const int shaderLengths = static_cast<int>(code.size());
+
+ shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
+ if (!entryPointName.empty()) shader->setEntryPoint(entryPointName.c_str());
+ // Reinitialize glslang if the semantics change.
+ GlslangInitializer::InitializationToken token =
+ GlobalTestSettings.initializer->acquire(controls);
+ return shader->parse(
+ (resources ? resources : &glslang::DefaultTBuiltInResource),
+ defaultVersion, isForwardCompatible, controls);
+ }
+
+ // Compiles and links the given source |code| of the given shader
+ // |stage| into the target under the semantics specified via |controls|.
+ // Returns a GlslangResult instance containing all the information generated
+ // during the process. If the target includes SPIR-V, also disassembles
+ // the result and returns disassembly text.
+ GlslangResult compileAndLink(
+ const std::string shaderName, const std::string& code,
+ const std::string& entryPointName, EShMessages controls)
+ {
+ const EShLanguage kind = GetShaderStage(GetSuffix(shaderName));
+
+ glslang::TShader shader(kind);
+ bool success = compile(&shader, code, entryPointName, controls);
+
+ glslang::TProgram program;
+ program.addShader(&shader);
+ success &= program.link(controls);
+
+ spv::SpvBuildLogger logger;
+
+ if (success && (controls & EShMsgSpvRules)) {
+ std::vector<uint32_t> spirv_binary;
+ glslang::GlslangToSpv(*program.getIntermediate(kind),
+ spirv_binary, &logger);
+
+ std::ostringstream disassembly_stream;
+ spv::Parameterize();
+ spv::Disassemble(disassembly_stream, spirv_binary);
+ return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
+ program.getInfoLog(), program.getInfoDebugLog(),
+ logger.getAllMessages(), disassembly_stream.str()};
+ } else {
+ return {{{shaderName, shader.getInfoLog(), shader.getInfoDebugLog()},},
+ program.getInfoLog(), program.getInfoDebugLog(), "", ""};
+ }
+ }
+
+ void outputResultToStream(std::ostringstream* stream,
+ const GlslangResult& result,
+ EShMessages controls)
+ {
+ const auto outputIfNotEmpty = [&stream](const std::string& str) {
+ if (!str.empty()) *stream << str << "\n";
+ };
+
+ for (const auto& shaderResult : result.shaderResults) {
+ *stream << shaderResult.shaderName << "\n";
+ outputIfNotEmpty(shaderResult.output);
+ outputIfNotEmpty(shaderResult.error);
+ }
+ outputIfNotEmpty(result.linkingOutput);
+ outputIfNotEmpty(result.linkingError);
+ *stream << result.spirvWarningsErrors;
+
+ if (controls & EShMsgSpvRules) {
+ *stream
+ << (result.spirv.empty()
+ ? "SPIR-V is not generated for failed compile or link\n"
+ : result.spirv);
+ }
+ }
+
+ void loadFileCompileAndCheck(const std::string& testDir,
+ const std::string& testName,
+ Source source,
+ Semantics semantics,
+ Target target,
+ const std::string& entryPointName="")
+ {
+ const std::string inputFname = testDir + "/" + testName;
+ const std::string expectedOutputFname =
+ testDir + "/baseResults/" + testName + ".out";
+ std::string input, expectedOutput;
+
+ tryLoadFile(inputFname, "input", &input);
+ tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
+
+ const EShMessages controls = DeriveOptions(source, semantics, target);
+ GlslangResult result =
+ compileAndLink(testName, input, entryPointName, controls);
+
+ // Generate the hybrid output in the way of glslangValidator.
+ std::ostringstream stream;
+ outputResultToStream(&stream, result, controls);
+
+ checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
+ expectedOutputFname);
+ }
+
+ // Preprocesses the given |source| code. On success, returns true, the
+ // preprocessed shader, and warning messages. Otherwise, returns false, an
+ // empty string, and error messages.
+ std::tuple<bool, std::string, std::string> preprocess(
+ const std::string& source)
+ {
+ const char* shaderStrings = source.data();
+ const int shaderLengths = static_cast<int>(source.size());
+
+ glslang::TShader shader(EShLangVertex);
+ shader.setStringsWithLengths(&shaderStrings, &shaderLengths, 1);
+ std::string ppShader;
+ glslang::TShader::ForbidInclude includer;
+ const bool success = shader.preprocess(
+ &glslang::DefaultTBuiltInResource, defaultVersion, defaultProfile,
+ forceVersionProfile, isForwardCompatible, EShMsgOnlyPreprocessor,
+ &ppShader, includer);
+
+ std::string log = shader.getInfoLog();
+ log += shader.getInfoDebugLog();
+ if (success) {
+ return std::make_tuple(true, ppShader, log);
+ } else {
+ return std::make_tuple(false, "", log);
+ }
+ }
+
+ void loadFilePreprocessAndCheck(const std::string& testDir,
+ const std::string& testName)
+ {
+ const std::string inputFname = testDir + "/" + testName;
+ const std::string expectedOutputFname =
+ testDir + "/baseResults/" + testName + ".out";
+ const std::string expectedErrorFname =
+ testDir + "/baseResults/" + testName + ".err";
+ std::string input, expectedOutput, expectedError;
+
+ tryLoadFile(inputFname, "input", &input);
+ tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
+ tryLoadFile(expectedErrorFname, "expected error", &expectedError);
+
+ bool ppOk;
+ std::string output, error;
+ std::tie(ppOk, output, error) = preprocess(input);
+ if (!output.empty()) output += '\n';
+ if (!error.empty()) error += '\n';
+
+ checkEqAndUpdateIfRequested(expectedOutput, output,
+ expectedOutputFname);
+ checkEqAndUpdateIfRequested(expectedError, error,
+ expectedErrorFname);
+ }
+
+private:
+ const int defaultVersion;
+ const EProfile defaultProfile;
+ const bool forceVersionProfile;
+ const bool isForwardCompatible;
+};
+
+} // namespace glslangtest
+
+#endif // GLSLANG_GTESTS_TEST_FIXTURE_H