diff --git a/CMakeLists.txt b/CMakeLists.txt index 813c57d60..1dea1c828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,6 +187,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Debug.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextToBinary.Miscellaneous.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/TextWordGet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/UnitSPIRV.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/Validate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/ValidateID.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp) diff --git a/test/TextToBinary.Debug.cpp b/test/TextToBinary.Debug.cpp index 688c966fd..3a1aad40a 100644 --- a/test/TextToBinary.Debug.cpp +++ b/test/TextToBinary.Debug.cpp @@ -37,8 +37,11 @@ namespace { using spvtest::MakeInstruction; +using spvtest::MakeVector; using ::testing::Eq; +// Test OpSource + // A single test case for OpSource struct LanguageCase { const char* language_name; @@ -74,7 +77,28 @@ TEST_P(OpSourceTest, AnyLanguage) { INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpSourceTest, ::testing::ValuesIn(kLanguageCases)); -// TODO(dneto): OpSourceExtension +// Test OpSourceExtension + +using OpSourceExtensionTest = + test_fixture::TextToBinaryTestBase<::testing::TestWithParam>; + +TEST_P(OpSourceExtensionTest, AnyExtension) { + // TODO(dneto): utf-8, quoting, escaping + std::string input = std::string("OpSourceExtension \"") + GetParam() + "\""; + + const std::vector encoded_string = MakeVector(GetParam()); + std::vector expected_instruction{ + spvOpcodeMake(encoded_string.size() + 1, spv::OpSourceExtension)}; + expected_instruction.insert(expected_instruction.end(), + encoded_string.begin(), encoded_string.end()); + EXPECT_THAT(CompiledInstructions(input), Eq(expected_instruction)); +} + +// TODO(dneto): utf-8, quoting, escaping +INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpSourceExtensionTest, + ::testing::ValuesIn(std::vector{ + "", "foo bar this and that"})); + // TODO(dneto): OpName // TODO(dneto): OpMemberName // TODO(dneto): OpString diff --git a/test/UnitSPIRV.cpp b/test/UnitSPIRV.cpp new file mode 100644 index 000000000..fed239dbd --- /dev/null +++ b/test/UnitSPIRV.cpp @@ -0,0 +1,46 @@ +// 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. + +#include "UnitSPIRV.h" + +#include "gmock/gmock.h" + +namespace { + +using spvtest::MakeVector; +using ::testing::Eq; +using Words = std::vector; + +TEST(MakeVector, Samples) { + EXPECT_THAT(MakeVector(""), Eq(Words{0})); + EXPECT_THAT(MakeVector("a"), Eq(Words{0x0061})); + EXPECT_THAT(MakeVector("ab"), Eq(Words{0x006261})); + EXPECT_THAT(MakeVector("abc"), Eq(Words{0x00636261})); + EXPECT_THAT(MakeVector("abcd"), Eq(Words{0x64636261, 0x00})); + EXPECT_THAT(MakeVector("abcde"), Eq(Words{0x64636261, 0x0065})); +} + +} // anonymous namespace diff --git a/test/UnitSPIRV.h b/test/UnitSPIRV.h index 7b8a39991..370cce9c9 100644 --- a/test/UnitSPIRV.h +++ b/test/UnitSPIRV.h @@ -107,15 +107,38 @@ inline void PrintTo(const WordVector& words, ::std::ostream* os) { } // Returns a vector of words representing a single instruction with the -// given opcode and number of operand words. +// given opcode and operand words as a vector. inline std::vector MakeInstruction( - spv::Op opcode, std::initializer_list args) { + spv::Op opcode, std::vector args) { std::vector result{ spvOpcodeMake(uint16_t(args.size() + 1), opcode)}; result.insert(result.end(), args.begin(), args.end()); return result; } +// Encodes a string as a sequence of words, using the SPIR-V encoding. +inline std::vector MakeVector(std::string input) { + std::vector result; + uint32_t word = 0; + size_t num_bytes = input.size(); + // SPIR-V strings are null-terminated. The byte_index == num_bytes + // case is used to push the terminating null byte. + for (size_t byte_index = 0; byte_index <= num_bytes; byte_index++) { + const auto new_byte = + (byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0)); + word |= (new_byte << (8 * (byte_index % sizeof(uint32_t)))); + if (3 == (byte_index % sizeof(uint32_t))) { + result.push_back(word); + word = 0; + } + } + // Emit a trailing partial word. + if ((num_bytes+1) % sizeof(uint32_t)) { + result.push_back(word); + } + return result; +} + } // namespace spvtest // A type for easily creating spv_text_t values, with an implicit conversion to