1 // Copyright (c) 2016 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include <gtest/gtest.h>
18 #include "spirv-tools/libspirv.h"
23 using namespace spvtools;
25 // The default consumer is a null std::function.
26 TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
27 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
28 const char input_text[] =
29 "OpCapability Shader\n"
30 "OpCapability Linkage\n"
31 "OpMemoryModel Logical GLSL450";
33 spv_binary binary = nullptr;
34 EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
35 sizeof(input_text), &binary, nullptr));
38 // Sadly the compiler don't allow me to feed binary directly to
40 spv_const_binary_t b{binary->code, binary->wordCount};
41 EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
44 spv_text text = nullptr;
45 EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
46 binary->wordCount, 0, &text, nullptr));
49 spvBinaryDestroy(binary);
50 spvContextDestroy(context);
53 // The default consumer is a null std::function.
54 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidAssembling) {
55 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
56 const char input_text[] = "%1 = OpName";
58 spv_binary binary = nullptr;
59 EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
60 spvTextToBinary(context, input_text, sizeof(input_text), &binary,
62 spvBinaryDestroy(binary);
63 spvContextDestroy(context);
66 // The default consumer is a null std::function.
67 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidDiassembling) {
68 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
69 const char input_text[] = "OpNop";
71 spv_binary binary = nullptr;
72 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
73 sizeof(input_text), &binary, nullptr));
74 // Change OpNop to an invalid (wordcount|opcode) word.
75 binary->code[binary->wordCount - 1] = 0xffffffff;
77 spv_text text = nullptr;
78 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
79 spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
83 spvBinaryDestroy(binary);
84 spvContextDestroy(context);
87 // The default consumer is a null std::function.
88 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) {
89 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
90 const char input_text[] = "OpNop";
92 spv_binary binary = nullptr;
93 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
94 sizeof(input_text), &binary, nullptr));
96 spv_const_binary_t b{binary->code, binary->wordCount};
97 EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
99 spvBinaryDestroy(binary);
100 spvContextDestroy(context);
103 TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
104 const char input_text[] = "%1 = OpName\n";
106 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
108 // TODO(antiagainst): Use public C API for setting the consumer once exists.
109 SetContextMessageConsumer(
111 [&invocation](spv_message_level_t level, const char* source,
112 const spv_position_t& position, const char* message) {
114 EXPECT_EQ(SPV_MSG_ERROR, level);
115 // The error happens at scanning the begining of second line.
116 EXPECT_STREQ("input", source);
117 EXPECT_EQ(1u, position.line);
118 EXPECT_EQ(0u, position.column);
119 EXPECT_EQ(12u, position.index);
120 EXPECT_STREQ("Expected operand, found end of stream.", message);
123 spv_binary binary = nullptr;
124 EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
125 spvTextToBinary(context, input_text, sizeof(input_text), &binary,
127 EXPECT_EQ(1, invocation);
128 spvBinaryDestroy(binary);
129 spvContextDestroy(context);
132 TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
133 const char input_text[] = "OpNop";
135 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
137 SetContextMessageConsumer(
139 [&invocation](spv_message_level_t level, const char* source,
140 const spv_position_t& position, const char* message) {
142 EXPECT_EQ(SPV_MSG_ERROR, level);
143 EXPECT_STREQ("input", source);
144 EXPECT_EQ(0u, position.line);
145 EXPECT_EQ(0u, position.column);
146 EXPECT_EQ(5u, position.index);
147 EXPECT_STREQ("Invalid opcode: 65535", message);
150 spv_binary binary = nullptr;
151 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
152 sizeof(input_text), &binary, nullptr));
153 // Change OpNop to an invalid (wordcount|opcode) word.
154 binary->code[binary->wordCount - 1] = 0xffffffff;
156 spv_text text = nullptr;
157 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
158 spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
160 EXPECT_EQ(1, invocation);
162 spvTextDestroy(text);
163 spvBinaryDestroy(binary);
164 spvContextDestroy(context);
167 TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
168 const char input_text[] = "OpNop";
170 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
172 SetContextMessageConsumer(
174 [&invocation](spv_message_level_t level, const char* source,
175 const spv_position_t& position, const char* message) {
177 EXPECT_EQ(SPV_MSG_ERROR, level);
178 EXPECT_STREQ("input", source);
179 EXPECT_EQ(0u, position.line);
180 EXPECT_EQ(0u, position.column);
181 // TODO(antiagainst): what validation reports is not a word offset here.
182 // It is inconsistent with diassembler. Should be fixed.
183 EXPECT_EQ(1u, position.index);
184 EXPECT_STREQ("Nop cannot appear before the memory model instruction",
188 spv_binary binary = nullptr;
189 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
190 sizeof(input_text), &binary, nullptr));
192 spv_const_binary_t b{binary->code, binary->wordCount};
193 EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
194 EXPECT_EQ(1, invocation);
196 spvBinaryDestroy(binary);
197 spvContextDestroy(context);
200 // When having both a consumer and an diagnostic object, the diagnostic object
201 // should take priority.
202 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
203 const char input_text[] = "%1 = OpName";
205 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
207 SetContextMessageConsumer(
209 [&invocation](spv_message_level_t, const char*, const spv_position_t&,
210 const char*) { ++invocation; });
212 spv_binary binary = nullptr;
213 spv_diagnostic diagnostic = nullptr;
214 EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
215 spvTextToBinary(context, input_text, sizeof(input_text), &binary,
217 EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
218 EXPECT_STREQ("Expected operand, found end of stream.", diagnostic->error);
220 spvDiagnosticDestroy(diagnostic);
221 spvBinaryDestroy(binary);
222 spvContextDestroy(context);
225 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
226 const char input_text[] = "OpNop";
228 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
230 SetContextMessageConsumer(
232 [&invocation](spv_message_level_t, const char*, const spv_position_t&,
233 const char*) { ++invocation; });
235 spv_binary binary = nullptr;
236 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
237 sizeof(input_text), &binary, nullptr));
238 // Change OpNop to an invalid (wordcount|opcode) word.
239 binary->code[binary->wordCount - 1] = 0xffffffff;
241 spv_diagnostic diagnostic = nullptr;
242 spv_text text = nullptr;
243 EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
244 spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
247 EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
248 EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
250 spvTextDestroy(text);
251 spvDiagnosticDestroy(diagnostic);
252 spvBinaryDestroy(binary);
253 spvContextDestroy(context);
256 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
257 const char input_text[] = "OpNop";
259 auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
261 SetContextMessageConsumer(
263 [&invocation](spv_message_level_t, const char*, const spv_position_t&,
264 const char*) { ++invocation; });
266 spv_binary binary = nullptr;
267 ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
268 sizeof(input_text), &binary, nullptr));
270 spv_diagnostic diagnostic = nullptr;
271 spv_const_binary_t b{binary->code, binary->wordCount};
272 EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, &diagnostic));
274 EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
275 EXPECT_STREQ("Nop cannot appear before the memory model instruction",
278 spvDiagnosticDestroy(diagnostic);
279 spvBinaryDestroy(binary);
280 spvContextDestroy(context);
283 } // anonymous namespace