// Copyright (c) 2024 Google LLC. // // 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. #include #include "gmock/gmock.h" #include "test/test_fixture.h" #include "tools/io.h" namespace spvtools { namespace { using spvtest::ScopedContext; class HexToText : public ::testing::Test { public: void VerifyDisassembly(const char* hex_stream, const char* expected_disassembly) { std::vector stream(hex_stream, hex_stream + strlen(hex_stream)); std::vector binary; // Convert hext to binary first. EXPECT_TRUE(ConvertHexToBinary(stream, &binary)); // Then disassemble it. spv_diagnostic diagnostic = nullptr; spv_text disassembly = nullptr; EXPECT_EQ(spvBinaryToText(ScopedContext().context, binary.data(), binary.size(), SPV_BINARY_TO_TEXT_OPTION_NONE, &disassembly, &diagnostic), SPV_SUCCESS); EXPECT_EQ(diagnostic, nullptr); // Verify disassembly is as expected and clean up. EXPECT_STREQ(disassembly->str, expected_disassembly); spvDiagnosticDestroy(diagnostic); spvTextDestroy(disassembly); } void EnsureError(const char* hex_stream) { std::vector stream(hex_stream, hex_stream + strlen(hex_stream)); std::vector binary; // Make sure there is a parse error EXPECT_FALSE(ConvertHexToBinary(stream, &binary)); } }; // The actual assembly doesn't matter, just the hex parsing. All the tests use // the following SPIR-V. constexpr char kDisassembly[] = R"(; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 ; Bound: 11 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %1 "main" %2 %3 OpName %2 "fancy_attribute" OpName %3 "useful_output" OpDecorate %2 Location 4 OpDecorate %3 Location 2 %4 = OpTypeFloat 32 %5 = OpTypePointer Input %4 %2 = OpVariable %5 Input %6 = OpTypePointer Output %4 %3 = OpVariable %6 Output %7 = OpTypeVoid %8 = OpTypeFunction %7 %1 = OpFunction %7 None %8 %9 = OpLabel %10 = OpLoad %4 %2 OpStore %3 %10 OpReturn OpFunctionEnd )"; TEST_F(HexToText, Words) { constexpr char kHex[] = R"(0x07230203, 0x00010600, 0x00070000, 0x0000000b 0x00000000, 0x00020011, 0x00000001, 0x0003000e 0x00000000, 0x00000001, 0x0007000f, 0x00000000 0x00000001, 0x6e69616d, 0x00000000, 0x00000002 0x00000003, 0x00060005, 0x00000002, 0x636e6166 0x74615f79, 0x62697274, 0x00657475, 0x00060005 0x00000003, 0x66657375, 0x6f5f6c75, 0x75707475 0x00000074, 0x00040047, 0x00000002, 0x0000001e 0x00000004, 0x00040047, 0x00000003, 0x0000001e 0x00000002, 0x00030016, 0x00000004, 0x00000020 0x00040020, 0x00000005, 0x00000001, 0x00000004 0x0004003b, 0x00000005, 0x00000002, 0x00000001 0x00040020, 0x00000006, 0x00000003, 0x00000004 0x0004003b, 0x00000006, 0x00000003, 0x00000003 0x00020013, 0x00000007, 0x00030021, 0x00000008 0x00000007, 0x00050036, 0x00000007, 0x00000001 0x00000000, 0x00000008, 0x000200f8, 0x00000009 0x0004003d, 0x00000004, 0x0000000a, 0x00000002 0x0003003e, 0x00000003, 0x0000000a, 0x000100fd 0x00010038)"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, WordsLeadingSpace) { constexpr char kHex[] = R"( x07230203, x00010600, x00070000, x0000000b x00000000, x00020011, x00000001, x0003000e x00000000, x00000001, x0007000f, x00000000 x00000001, x6e69616d, x00000000, x00000002 x00000003, x00060005, x00000002, x636e6166 x74615f79, x62697274, x00657475, x00060005 x00000003, x66657375, x6f5f6c75, x75707475 x00000074, x00040047, x00000002, x0000001e x00000004, x00040047, x00000003, x0000001e x00000002, x00030016, x00000004, x00000020 x00040020, x00000005, x00000001, x00000004 x0004003b, x00000005, x00000002, x00000001 x00040020, x00000006, x00000003, x00000004 x0004003b, x00000006, x00000003, x00000003 x00020013, x00000007, x00030021, x00000008 x00000007, x00050036, x00000007, x00000001 x00000000, x00000008, x000200f8, x00000009 x0004003d, x00000004, x0000000a, x00000002 x0003003e, x00000003, x0000000a, x000100fd x00010038)"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, WordsTrailingSpace) { constexpr char kHex[] = R"(0X7230203, 0X10600, 0X70000, 0XB 0X0, 0X20011, 0X1, 0X3000E 0X0, 0X1, 0X7000F, 0X0 0X1, X6E69616D, 0X0, 0X2 0X3, 0X60005, 0X2, X636E6166 X74615F79, X62697274, 0X657475, 0X60005 0X3, X66657375, X6F5F6C75, X75707475 0X74, 0X40047, 0X2, 0X1E 0X4, 0X40047, 0X3, 0X1E 0X2, 0X30016, 0X4, 0X20 0X40020, 0X5, 0X1, 0X4 0X4003B, 0X5, 0X2, 0X1 0X40020, 0X6, 0X3, 0X4 0X4003B, 0X6, 0X3, 0X3 0X20013, 0X7, 0X30021, 0X8 0X7, 0X50036, 0X7, 0X1 0X0, 0X8, 0X200F8, 0X9 0X4003D, 0X4, 0XA, 0X2 0X3003E, 0X3, 0XA, 0X100FD 0X10038 )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, BytesLittleEndian) { constexpr char kHex[] = R"( 0x03 0x02 0x23 0x07 0x00 0x06 0x01 0x00 0x00 0x00 0x07 0x00 0x0b 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x11 0x00 0x02 0x00 0x01 0x00 0x00 0x00 0x0e 0x00 0x03 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x0f 0x00 0x07 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x6d 0x61 0x69 0x6e 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x05 0x00 0x06 0x00 0x02 0x00 0x00 0x00 0x66 0x61 0x6e 0x63 0x79 0x5f 0x61 0x74 0x74 0x72 0x69 0x62 0x75 0x74 0x65 0x00 0x05 0x00 0x06 0x00 0x03 0x00 0x00 0x00 0x75 0x73 0x65 0x66 0x75 0x6c 0x5f 0x6f 0x75 0x74 0x70 0x75 0x74 0x00 0x00 0x00 0x47 0x00 0x04 0x00 0x02 0x00 0x00 0x00 0x1e 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x47 0x00 0x04 0x00 0x03 0x00 0x00 0x00 0x1e 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x16 0x00 0x03 0x00 0x04 0x00 0x00 0x00 0x20 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x05 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x3b 0x00 0x04 0x00 0x05 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x20 0x00 0x04 0x00 0x06 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x3b 0x00 0x04 0x00 0x06 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x13 0x00 0x02 0x00 0x07 0x00 0x00 0x00 0x21 0x00 0x03 0x00 0x08 0x00 0x00 0x00 0x07 0x00 0x00 0x00 0x36 0x00 0x05 0x00 0x07 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x00 0x00 0x00 0xf8 0x00 0x02 0x00 0x09 0x00 0x00 0x00 0x3d 0x00 0x04 0x00 0x04 0x00 0x00 0x00 0x0a 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x3e 0x00 0x03 0x00 0x03 0x00 0x00 0x00 0x0a 0x00 0x00 0x00 0xfd 0x00 0x01 0x00 0x38 0x00 0x01 0x00 )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, BytesBigEndian) { constexpr char kHex[] = R"( X07,X23,X02,X03, X00,X01,X06,X00, X00,X07,X00,X00, X00,X00,X00,X0B X00,X00,X00,X00, X00,X02,X00,X11, X00,X00,X00,X01, X00,X03,X00,X0E X00,X00,X00,X00, X00,X00,X00,X01, X00,X07,X00,X0F, X00,X00,X00,X00 X00,X00,X00,X01, X6E,X69,X61,X6D, X00,X00,X00,X00, X00,X00,X00,X02 X00,X00,X00,X03, X00,X06,X00,X05, X00,X00,X00,X02, X63,X6E,X61,X66 X74,X61,X5F,X79, X62,X69,X72,X74, X00,X65,X74,X75, X00,X06,X00,X05 X00,X00,X00,X03, X66,X65,X73,X75, X6F,X5F,X6C,X75, X75,X70,X74,X75 X00,X00,X00,X74, X00,X04,X00,X47, X00,X00,X00,X02, X00,X00,X00,X1E X00,X00,X00,X04, X00,X04,X00,X47, X00,X00,X00,X03, X00,X00,X00,X1E X00,X00,X00,X02, X00,X03,X00,X16, X00,X00,X00,X04, X00,X00,X00,X20 X00,X04,X00,X20, X00,X00,X00,X05, X00,X00,X00,X01, X00,X00,X00,X04 X00,X04,X00,X3B, X00,X00,X00,X05, X00,X00,X00,X02, X00,X00,X00,X01 X00,X04,X00,X20, X00,X00,X00,X06, X00,X00,X00,X03, X00,X00,X00,X04 X00,X04,X00,X3B, X00,X00,X00,X06, X00,X00,X00,X03, X00,X00,X00,X03 X00,X02,X00,X13, X00,X00,X00,X07, X00,X03,X00,X21, X00,X00,X00,X08 X00,X00,X00,X07, X00,X05,X00,X36, X00,X00,X00,X07, X00,X00,X00,X01 X00,X00,X00,X00, X00,X00,X00,X08, X00,X02,X00,XF8, X00,X00,X00,X09 X00,X04,X00,X3D, X00,X00,X00,X04, X00,X00,X00,X0A, X00,X00,X00,X02 X00,X03,X00,X3E, X00,X00,X00,X03, X00,X00,X00,X0A, X00,X01,X00,XFD X00,X01,X00,X38, )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, StreamLittleEndian) { constexpr char kHex[] = R"( 03 02 23 07 00 06 01 00 00 00 07 00 0b 00 00 00 00 00 00 00 11 00 02 00 01 00 00 00 0e 00 03 00 00 00 00 00 01 00 00 00 0f 00 07 00 00 00 00 00 01 00 00 00 6d 61 69 6e 00 00 00 00 02 00 00 00 03 00 00 00 05 00 06 00 02 00 00 00 66 61 6e 63 79 5f 61 74 74 72 69 62 75 74 65 00 05 00 06 00 03 00 00 00 75 73 65 66 75 6c 5f 6f 75 74 70 75 74 00 00 00 47 00 04 00 02 00 00 00 1e 00 00 00 04 00 00 00 47 00 04 00 03 00 00 00 1e 00 00 00 02 00 00 00 16 00 03 00 04 00 00 00 20 00 00 00 20 00 04 00 05 00 00 00 01 00 00 00 04 00 00 00 3b 00 04 00 05 00 00 00 02 00 00 00 01 00 00 00 20 00 04 00 06 00 00 00 03 00 00 00 04 00 00 00 3b 00 04 00 06 00 00 00 03 00 00 00 03 00 00 00 13 00 02 00 07 00 00 00 21 00 03 00 08 00 00 00 07 00 00 00 36 00 05 00 07 00 00 00 01 00 00 00 00 00 00 00 08 00 00 00 f8 00 02 00 09 00 00 00 3d 00 04 00 04 00 00 00 0a 00 00 00 02 00 00 00 3e 00 03 00 03 00 00 00 0a 00 00 00 fd 00 01 00 38 00 01 00 )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, StreamLittleEndianNoDelim) { constexpr char kHex[] = R"( 0302230700060100000007000B000000 0000000011000200010000000E000300 00000000010000000F00070000000000 010000006D61696E0000000002000000 03000000050006000200000066616E63 795F6174747269627574650005000600 0300000075736566756C5F6F75747075 7400000047000400020000001E000000 0400000047000400030000001E000000 02000000160003000400000020000000 20000400050000000100000004000000 3B000400050000000200000001000000 20000400060000000300000004000000 3B000400060000000300000003000000 13000200070000002100030008000000 07000000360005000700000001000000 0000000008000000F800020009000000 3D000400040000000A00000002000000 3E000300030000000A000000FD000100 38000100 )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, StreamBigEndian) { constexpr char kHex[] = R"( 07230203, 00010600, 00070000, 0000000b 00000000, 00020011, 00000001, 0003000e 00000000, 00000001, 0007000f, 00000000 00000001, 6e69616d, 00000000, 00000002 00000003, 00060005, 00000002, 636e6166 74615f79, 62697274, 00657475, 00060005 00000003, 66657375, 6f5f6c75, 75707475 00000074, 00040047, 00000002, 0000001e 00000004, 00040047, 00000003, 0000001e 00000002, 00030016, 00000004, 00000020 00040020, 00000005, 00000001, 00000004 0004003b, 00000005, 00000002, 00000001 00040020, 00000006, 00000003, 00000004 0004003b, 00000006, 00000003, 00000003 00020013, 00000007, 00030021, 00000008 00000007, 00050036, 00000007, 00000001 00000000, 00000008, 000200f8, 00000009 0004003d, 00000004, 0000000a, 00000002 0003003e, 00000003, 0000000a, 000100fd 00010038, )"; VerifyDisassembly(kHex, kDisassembly); } TEST_F(HexToText, WordsNoDelimieter) { constexpr char kHex[] = R"(0x07230203 0x00010600 0x00070000 0x0000000b 0x00000000 0x00020011 0x00000001 0x0003000e 0x00000000 0x00000001 0x0007000f 0x00000000 0x00000001 0x6e69616d 0x00000000 0x00000002 0x00000003 0x00060005 0x00000002 0x636e6166 0x74615f79 0x62697274 0x00657475 0x00060005 0x00000003 0x666573750x6f5f6c75 0x75707475 0x00000074 0x00040047 0x00000002 0x0000001e 0x00000004 0x00040047 0x00000003 0x0000001e 0x00000002 0x00030016 0x00000004 0x00000020 0x00040020 0x00000005 0x00000001 0x00000004 0x0004003b 0x00000005 0x00000002 0x00000001 0x00040020 0x00000006 0x00000003 0x00000004 0x0004003b 0x00000006 0x00000003 0x00000003 0x00020013 0x00000007 0x00030021 0x00000008 0x00000007 0x00050036 0x00000007 0x00000001 0x00000000 0x00000008 0x000200f8 0x00000009 0x0004003d 0x00000004 0x0000000a 0x00000002 0x0003003e 0x00000003 0x0000000a 0x000100fd 0x00010038)"; EnsureError(kHex); } TEST_F(HexToText, InvalidFirstToken) { constexpr char kHex[] = R"(0x17230203, 0x00010600, 0x00070000, 0x0000000b 0x00000000, 0x00020011, 0x00000001, 0x0003000e 0x00000000, 0x00000001, 0x0007000f, 0x00000000 0x00000001, 0x6e69616d, 0x00000000, 0x00000002 0x00000003, 0x00060005, 0x00000002, 0x636e6166 0x74615f79, 0x62697274, 0x00657475, 0x00060005 0x00000003, 0x66657375, 0x6f5f6c75, 0x75707475 0x00000074, 0x00040047, 0x00000002, 0x0000001e 0x00000004, 0x00040047, 0x00000003, 0x0000001e 0x00000002, 0x00030016, 0x00000004, 0x00000020 0x00040020, 0x00000005, 0x00000001, 0x00000004 0x0004003b, 0x00000005, 0x00000002, 0x00000001 0x00040020, 0x00000006, 0x00000003, 0x00000004 0x0004003b, 0x00000006, 0x00000003, 0x00000003 0x00020013, 0x00000007, 0x00030021, 0x00000008 0x00000007, 0x00050036, 0x00000007, 0x00000001 0x00000000, 0x00000008, 0x000200f8, 0x00000009 0x0004003d, 0x00000004, 0x0000000a, 0x00000002 0x0003003e, 0x00000003, 0x0000000a, 0x000100fd 0x00010038)"; EnsureError(kHex); } TEST_F(HexToText, NonHexCharacter) { // Note: a 6 is replaced with G in this stream constexpr char kHex[] = R"(0x07230203, 0x00010600, 0x00070000, 0x0000000b 0x00000000, 0x00020011, 0x00000001, 0x0003000e 0x00000000, 0x00000001, 0x0007000f, 0x00000000 0x00000001, 0x6e69616d, 0x00000000, 0x00000002 0x00000003, 0x00060005, 0x00000002, 0x636e6166 0x74615f79, 0x62697274, 0x00657475, 0x00060005 0x00000003, 0x66657375, 0x6f5f6c75, 0x75707475 0x00000074, 0x00040047, 0x00000002, 0x0000001e 0x00000004, 0x00040047, 0x00000003, 0x0000001e 0x00000002, 0x0003001G, 0x00000004, 0x00000020 0x00040020, 0x00000005, 0x00000001, 0x00000004 0x0004003b, 0x00000005, 0x00000002, 0x00000001 0x00040020, 0x00000006, 0x00000003, 0x00000004 0x0004003b, 0x00000006, 0x00000003, 0x00000003 0x00020013, 0x00000007, 0x00030021, 0x00000008 0x00000007, 0x00050036, 0x00000007, 0x00000001 0x00000000, 0x00000008, 0x000200f8, 0x00000009 0x0004003d, 0x00000004, 0x0000000a, 0x00000002 0x0003003e, 0x00000003, 0x0000000a, 0x000100fd 0x00010038)"; EnsureError(kHex); } TEST_F(HexToText, MissingExpectedPrefix) { constexpr char kHex[] = R"(0x07230203, 0x00010600, 0x00070000, 0x0000000b 0x00000000, 0x00020011, 0x00000001, 0x0003000e 0x00000000, 0x00000001, 0x0007000f, 0x00000000 0x00000001, 0x6e69616d, 0x00000000, 0x00000002 0x00000003, 0x00060005, 0x00000002, 0x636e6166 0x74615f79, 0x62697274, 0x00657475, 0x00060005 0x00000003, 0x66657375, 0x6f5f6c75, 0x75707475 0x00000074, 0x00040047, 0x00000002, 0x0000001e 0x00000004, 0x00040047, 0x00000003, 0x0000001e 0x00000002, 0x00030016, 0x00000004, 0x00000020 0x00040020, 0x00000005, 00000001, 0x00000004 0x0004003b, 0x00000005, 0x00000002, 0x00000001 0x00040020, 0x00000006, 0x00000003, 0x00000004 0x0004003b, 0x00000006, 0x00000003, 0x00000003 0x00020013, 0x00000007, 0x00030021, 0x00000008 0x00000007, 0x00050036, 0x00000007, 0x00000001 0x00000000, 0x00000008, 0x000200f8, 0x00000009 0x0004003d, 0x00000004, 0x0000000a, 0x00000002 0x0003003e, 0x00000003, 0x0000000a, 0x000100fd 0x00010038)"; EnsureError(kHex); } TEST_F(HexToText, UnexpectedPrefix) { constexpr char kHex[] = R"(07230203, 00010600, 00070000, 0000000b 00000000, 00020011, 00000001, 0003000e 00000000, 00000001, 0007000f, 00000000 00000001, 6e69616d, 00000000, 00000002 00000003, 00060005, 00000002, 636e6166 74615f79, 62697274, 00657475, 00060005 00000003, 66657375, 6f5f6c75, 75707475 00000074, 00040047, 00000002, 0000001e 00000004, 00040047, 00000003, 0000001e 00000002, 00030016, 00000004, 00000020 00040020, 00000005, 0x00000001, 00000004 0004003b, 00000005, 00000002, 00000001 00040020, 00000006, 00000003, 00000004 0004003b, 00000006, 00000003, 00000003 00020013, 00000007, 00030021, 00000008 00000007, 00050036, 00000007, 00000001 00000000, 00000008, 000200f8, 00000009 0004003d, 00000004, 0000000a, 00000002 0003003e, 00000003, 0000000a, 000100fd 00010038)"; EnsureError(kHex); } } // namespace } // namespace spvtools