SPIRV-Tools/test/TestFixture.h
Lei Zhang 972788bf23 Use opaque context object to hold SPIR-V info tables.
Previously the opcode table is declared as an global array and we
have spvOpcodeTableInitialize() modifying it. That can result in
race condition. Now spvOpcodeTabelGet() copies the whole underlying
array.
2015-11-12 16:27:51 -05:00

190 lines
6.8 KiB
C++

// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
// https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
#ifndef LIBSPIRV_TEST_TEST_FIXTURE_H_
#define LIBSPIRV_TEST_TEST_FIXTURE_H_
#include "UnitSPIRV.h"
namespace spvtest {
// Common setup for TextToBinary tests. SetText() should be called to populate
// the actual test text.
template <typename T>
class TextToBinaryTestBase : public T {
public:
// Shorthand for SPIR-V compilation result.
using SpirvVector = std::vector<uint32_t>;
// Offset into a SpirvVector at which the first instruction starts.
const SpirvVector::size_type kFirstInstruction = 5;
TextToBinaryTestBase()
: context(spvContextCreate()),
diagnostic(nullptr),
text(),
binary(nullptr) {
char textStr[] = "substitute the text member variable with your test";
text = {textStr, strlen(textStr)};
}
virtual ~TextToBinaryTestBase() {
DestroyBinary();
if (diagnostic) spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
// Returns subvector v[from:end).
SpirvVector Subvector(const SpirvVector& v, SpirvVector::size_type from) {
assert(from <= v.size());
return SpirvVector(v.begin() + from, v.end());
}
// Compiles SPIR-V text in the given assembly syntax format, asserting
// compilation success. Returns the compiled code.
SpirvVector CompileSuccessfully(const std::string& text) {
spv_result_t status = spvTextToBinary(context, text.c_str(), text.size(),
&binary, &diagnostic);
EXPECT_EQ(SPV_SUCCESS, status) << text;
SpirvVector code_copy;
if (status == SPV_SUCCESS) {
code_copy = SpirvVector(binary->code, binary->code + binary->wordCount);
DestroyBinary();
} else {
spvDiagnosticPrint(diagnostic);
}
return code_copy;
}
// Compiles SPIR-V text with the given format, asserting compilation failure.
// Returns the error message(s).
std::string CompileFailure(const std::string& text) {
EXPECT_NE(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
&binary, &diagnostic))
<< text;
DestroyBinary();
return diagnostic->error;
}
// Encodes SPIR-V text into binary and then decodes the binary using
// default options. Returns the decoded text.
std::string EncodeAndDecodeSuccessfully(const std::string& text) {
return EncodeAndDecodeSuccessfully(text, SPV_BINARY_TO_TEXT_OPTION_NONE);
}
// Encodes SPIR-V text into binary and then decodes the binary using
// given options. Returns the decoded text.
std::string EncodeAndDecodeSuccessfully(const std::string& text,
uint32_t disassemble_options) {
DestroyBinary();
spv_result_t error = spvTextToBinary(context, text.c_str(), text.size(),
&binary, &diagnostic);
if (error) {
spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic);
}
EXPECT_EQ(SPV_SUCCESS, error);
if (!binary) return "";
spv_text decoded_text;
error = spvBinaryToText(context, binary->code, binary->wordCount,
disassemble_options, &decoded_text, &diagnostic);
if (error) {
spvDiagnosticPrint(diagnostic);
spvDiagnosticDestroy(diagnostic);
}
EXPECT_EQ(SPV_SUCCESS, error) << text;
const std::string decoded_string = decoded_text->str;
spvTextDestroy(decoded_text);
// Remove the preamble comments generated by disassembler.
const std::string schema0 = "Schema: 0\n";
std::string::size_type preamble_end = decoded_string.find(schema0);
return decoded_string.substr(preamble_end + schema0.size());
}
// Encodes SPIR-V text into binary. This is expected to succeed.
// The given words are then appended to the binary, and the result
// is then decoded. This is expected to fail.
// Returns the error message.
std::string EncodeSuccessfullyDecodeFailed(
const std::string& text, const SpirvVector& words_to_append) {
SpirvVector code =
spvtest::Concatenate({CompileSuccessfully(text), words_to_append});
spv_text decoded_text;
EXPECT_NE(SPV_SUCCESS, spvBinaryToText(context, code.data(), code.size(),
SPV_BINARY_TO_TEXT_OPTION_NONE,
&decoded_text, &diagnostic));
if (diagnostic) {
std::string error_message = diagnostic->error;
spvDiagnosticDestroy(diagnostic);
diagnostic = nullptr;
return error_message;
}
return "";
}
// Compiles SPIR-V text, asserts success, and returns the words representing
// the instructions. In particular, skip the words in the SPIR-V header.
SpirvVector CompiledInstructions(const std::string& text) {
const SpirvVector code = CompileSuccessfully(text);
SpirvVector result;
// Extract just the instructions.
// If the code fails to compile, then return the empty vector.
// In any case, don't crash or invoke undefined behaviour.
if (code.size() >= kFirstInstruction)
result = Subvector(code, kFirstInstruction);
return result;
}
void SetText(const std::string& code) {
textString = code;
text.str = textString.c_str();
text.length = textString.size();
}
// Destroys the binary, if it exists.
void DestroyBinary() {
spvBinaryDestroy(binary);
binary = nullptr;
}
spv_context context;
spv_diagnostic diagnostic;
std::string textString;
spv_text_t text;
spv_binary binary;
};
using TextToBinaryTest = TextToBinaryTestBase<::testing::Test>;
} // namespace spvtest
#endif // LIBSPIRV_TEST_TEST_FIXTURE_H_