• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Google Inc.
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 
15 #include "gtest/gtest.h"
16 #include "source/table.h"
17 #include "spirv-tools/libspirv.h"
18 
19 namespace spvtools {
20 namespace {
21 
22 // TODO(antiagainst): Use public C API for setting the consumer once exists.
23 #ifndef SPIRV_TOOLS_SHAREDLIB
SetContextMessageConsumer(spv_context context,MessageConsumer consumer)24 void SetContextMessageConsumer(spv_context context, MessageConsumer consumer) {
25   spvtools::SetContextMessageConsumer(context, consumer);
26 }
27 #else
28 void SetContextMessageConsumer(spv_context, MessageConsumer) {}
29 #endif
30 
31 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForValidInput)32 TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
33   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
34   const char input_text[] =
35       "OpCapability Shader\n"
36       "OpCapability Linkage\n"
37       "OpMemoryModel Logical GLSL450";
38 
39   spv_binary binary = nullptr;
40   EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
41                                          sizeof(input_text), &binary, nullptr));
42 
43   {
44     // Sadly the compiler don't allow me to feed binary directly to
45     // spvValidate().
46     spv_const_binary_t b{binary->code, binary->wordCount};
47     EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
48   }
49 
50   spv_text text = nullptr;
51   EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
52                                          binary->wordCount, 0, &text, nullptr));
53 
54   spvTextDestroy(text);
55   spvBinaryDestroy(binary);
56   spvContextDestroy(context);
57 }
58 
59 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidAssembling)60 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidAssembling) {
61   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
62   const char input_text[] = "%1 = OpName";
63 
64   spv_binary binary = nullptr;
65   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
66             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
67                             nullptr));
68   spvBinaryDestroy(binary);
69   spvContextDestroy(context);
70 }
71 
72 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidDiassembling)73 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidDiassembling) {
74   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
75   const char input_text[] = "OpNop";
76 
77   spv_binary binary = nullptr;
78   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
79                                          sizeof(input_text), &binary, nullptr));
80   // Change OpNop to an invalid (wordcount|opcode) word.
81   binary->code[binary->wordCount - 1] = 0xffffffff;
82 
83   spv_text text = nullptr;
84   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
85             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
86                             nullptr));
87 
88   spvTextDestroy(text);
89   spvBinaryDestroy(binary);
90   spvContextDestroy(context);
91 }
92 
93 // The default consumer is a null std::function.
TEST(CInterface,DefaultConsumerNullDiagnosticForInvalidValidating)94 TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) {
95   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
96   const char input_text[] = "OpNop";
97 
98   spv_binary binary = nullptr;
99   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
100                                          sizeof(input_text), &binary, nullptr));
101 
102   spv_const_binary_t b{binary->code, binary->wordCount};
103   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
104 
105   spvBinaryDestroy(binary);
106   spvContextDestroy(context);
107 }
108 
TEST(CInterface,SpecifyConsumerNullDiagnosticForAssembling)109 TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
110   const char input_text[] = "     OpName\n";
111 
112   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
113   int invocation = 0;
114   SetContextMessageConsumer(
115       context,
116       [&invocation](spv_message_level_t level, const char* source,
117                     const spv_position_t& position, const char* message) {
118         ++invocation;
119         EXPECT_EQ(SPV_MSG_ERROR, level);
120         // The error happens at scanning the begining of second line.
121         EXPECT_STREQ("input", source);
122         EXPECT_EQ(1u, position.line);
123         EXPECT_EQ(0u, position.column);
124         EXPECT_EQ(12u, position.index);
125         EXPECT_STREQ("Expected operand, found end of stream.", message);
126       });
127 
128   spv_binary binary = nullptr;
129   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
130             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
131                             nullptr));
132 #ifndef SPIRV_TOOLS_SHAREDLIB
133   EXPECT_EQ(1, invocation);
134 #endif
135   spvBinaryDestroy(binary);
136   spvContextDestroy(context);
137 }
138 
TEST(CInterface,SpecifyConsumerNullDiagnosticForDisassembling)139 TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
140   const char input_text[] = "OpNop";
141 
142   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
143   int invocation = 0;
144   SetContextMessageConsumer(
145       context,
146       [&invocation](spv_message_level_t level, const char* source,
147                     const spv_position_t& position, const char* message) {
148         ++invocation;
149         EXPECT_EQ(SPV_MSG_ERROR, level);
150         EXPECT_STREQ("input", source);
151         EXPECT_EQ(0u, position.line);
152         EXPECT_EQ(0u, position.column);
153         EXPECT_EQ(1u, position.index);
154         EXPECT_STREQ("Invalid opcode: 65535", message);
155       });
156 
157   spv_binary binary = nullptr;
158   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
159                                          sizeof(input_text), &binary, nullptr));
160   // Change OpNop to an invalid (wordcount|opcode) word.
161   binary->code[binary->wordCount - 1] = 0xffffffff;
162 
163   spv_text text = nullptr;
164   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
165             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
166                             nullptr));
167 #ifndef SPIRV_TOOLS_SHAREDLIB
168   EXPECT_EQ(1, invocation);
169 #endif
170 
171   spvTextDestroy(text);
172   spvBinaryDestroy(binary);
173   spvContextDestroy(context);
174 }
175 
TEST(CInterface,SpecifyConsumerNullDiagnosticForValidating)176 TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
177   const char input_text[] = "OpNop";
178 
179   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
180   int invocation = 0;
181   SetContextMessageConsumer(
182       context,
183       [&invocation](spv_message_level_t level, const char* source,
184                     const spv_position_t& position, const char* message) {
185         ++invocation;
186         EXPECT_EQ(SPV_MSG_ERROR, level);
187         EXPECT_STREQ("input", source);
188         EXPECT_EQ(0u, position.line);
189         EXPECT_EQ(0u, position.column);
190         // TODO(antiagainst): what validation reports is not a word offset here.
191         // It is inconsistent with diassembler. Should be fixed.
192         EXPECT_EQ(1u, position.index);
193         EXPECT_STREQ(
194             "Nop cannot appear before the memory model instruction\n"
195             "  OpNop\n",
196             message);
197       });
198 
199   spv_binary binary = nullptr;
200   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
201                                          sizeof(input_text), &binary, nullptr));
202 
203   spv_const_binary_t b{binary->code, binary->wordCount};
204   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
205 #ifndef SPIRV_TOOLS_SHAREDLIB
206   EXPECT_EQ(1, invocation);
207 #endif
208 
209   spvBinaryDestroy(binary);
210   spvContextDestroy(context);
211 }
212 
213 // When having both a consumer and an diagnostic object, the diagnostic object
214 // should take priority.
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForAssembling)215 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
216   const char input_text[] = "     OpName";
217 
218   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
219   int invocation = 0;
220   SetContextMessageConsumer(
221       context,
222       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
223                     const char*) { ++invocation; });
224 
225   spv_binary binary = nullptr;
226   spv_diagnostic diagnostic = nullptr;
227   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
228             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
229                             &diagnostic));
230   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
231   EXPECT_STREQ("Expected operand, found end of stream.", diagnostic->error);
232 
233   spvDiagnosticDestroy(diagnostic);
234   spvBinaryDestroy(binary);
235   spvContextDestroy(context);
236 }
237 
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForDisassembling)238 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
239   const char input_text[] = "OpNop";
240 
241   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
242   int invocation = 0;
243   SetContextMessageConsumer(
244       context,
245       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
246                     const char*) { ++invocation; });
247 
248   spv_binary binary = nullptr;
249   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
250                                          sizeof(input_text), &binary, nullptr));
251   // Change OpNop to an invalid (wordcount|opcode) word.
252   binary->code[binary->wordCount - 1] = 0xffffffff;
253 
254   spv_diagnostic diagnostic = nullptr;
255   spv_text text = nullptr;
256   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
257             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
258                             &diagnostic));
259 
260   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
261   EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
262 
263   spvTextDestroy(text);
264   spvDiagnosticDestroy(diagnostic);
265   spvBinaryDestroy(binary);
266   spvContextDestroy(context);
267 }
268 
TEST(CInterface,SpecifyConsumerSpecifyDiagnosticForValidating)269 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
270   const char input_text[] = "OpNop";
271 
272   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
273   int invocation = 0;
274   SetContextMessageConsumer(
275       context,
276       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
277                     const char*) { ++invocation; });
278 
279   spv_binary binary = nullptr;
280   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
281                                          sizeof(input_text), &binary, nullptr));
282 
283   spv_diagnostic diagnostic = nullptr;
284   spv_const_binary_t b{binary->code, binary->wordCount};
285   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, &diagnostic));
286 
287   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
288   EXPECT_STREQ(
289       "Nop cannot appear before the memory model instruction\n"
290       "  OpNop\n",
291       diagnostic->error);
292 
293   spvDiagnosticDestroy(diagnostic);
294   spvBinaryDestroy(binary);
295   spvContextDestroy(context);
296 }
297 
298 }  // namespace
299 }  // namespace spvtools
300