Setup dependent external sources
[platform/upstream/VK-GL-CTS.git] / external / spirv-tools / src / test / c_interface_test.cpp
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
17 #include "message.h"
18 #include "spirv-tools/libspirv.h"
19 #include "table.h"
20
21 namespace {
22
23 using namespace spvtools;
24
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";
32
33   spv_binary binary = nullptr;
34   EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
35                                          sizeof(input_text), &binary, nullptr));
36
37   {
38     // Sadly the compiler don't allow me to feed binary directly to
39     // spvValidate().
40     spv_const_binary_t b{binary->code, binary->wordCount};
41     EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
42   }
43
44   spv_text text = nullptr;
45   EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
46                                          binary->wordCount, 0, &text, nullptr));
47
48   spvTextDestroy(text);
49   spvBinaryDestroy(binary);
50   spvContextDestroy(context);
51 }
52
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";
57
58   spv_binary binary = nullptr;
59   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
60             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
61                             nullptr));
62   spvBinaryDestroy(binary);
63   spvContextDestroy(context);
64 }
65
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";
70
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;
76
77   spv_text text = nullptr;
78   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
79             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
80                             nullptr));
81
82   spvTextDestroy(text);
83   spvBinaryDestroy(binary);
84   spvContextDestroy(context);
85 }
86
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";
91
92   spv_binary binary = nullptr;
93   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
94                                          sizeof(input_text), &binary, nullptr));
95
96   spv_const_binary_t b{binary->code, binary->wordCount};
97   EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
98
99   spvBinaryDestroy(binary);
100   spvContextDestroy(context);
101 }
102
103 TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
104   const char input_text[] = "%1 = OpName\n";
105
106   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
107   int invocation = 0;
108   // TODO(antiagainst): Use public C API for setting the consumer once exists.
109   SetContextMessageConsumer(
110       context,
111       [&invocation](spv_message_level_t level, const char* source,
112                     const spv_position_t& position, const char* message) {
113         ++invocation;
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);
121       });
122
123   spv_binary binary = nullptr;
124   EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
125             spvTextToBinary(context, input_text, sizeof(input_text), &binary,
126                             nullptr));
127   EXPECT_EQ(1, invocation);
128   spvBinaryDestroy(binary);
129   spvContextDestroy(context);
130 }
131
132 TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
133   const char input_text[] = "OpNop";
134
135   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
136   int invocation = 0;
137   SetContextMessageConsumer(
138       context,
139       [&invocation](spv_message_level_t level, const char* source,
140                     const spv_position_t& position, const char* message) {
141         ++invocation;
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);
148       });
149
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;
155
156   spv_text text = nullptr;
157   EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
158             spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
159                             nullptr));
160   EXPECT_EQ(1, invocation);
161
162   spvTextDestroy(text);
163   spvBinaryDestroy(binary);
164   spvContextDestroy(context);
165 }
166
167 TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
168   const char input_text[] = "OpNop";
169
170   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
171   int invocation = 0;
172   SetContextMessageConsumer(
173       context,
174       [&invocation](spv_message_level_t level, const char* source,
175                     const spv_position_t& position, const char* message) {
176         ++invocation;
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",
185                      message);
186       });
187
188   spv_binary binary = nullptr;
189   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
190                                          sizeof(input_text), &binary, nullptr));
191
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);
195
196   spvBinaryDestroy(binary);
197   spvContextDestroy(context);
198 }
199
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";
204
205   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
206   int invocation = 0;
207   SetContextMessageConsumer(
208       context,
209       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
210                     const char*) { ++invocation; });
211
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,
216                             &diagnostic));
217   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
218   EXPECT_STREQ("Expected operand, found end of stream.", diagnostic->error);
219
220   spvDiagnosticDestroy(diagnostic);
221   spvBinaryDestroy(binary);
222   spvContextDestroy(context);
223 }
224
225 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
226   const char input_text[] = "OpNop";
227
228   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
229   int invocation = 0;
230   SetContextMessageConsumer(
231       context,
232       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
233                     const char*) { ++invocation; });
234
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;
240
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,
245                             &diagnostic));
246
247   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
248   EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
249
250   spvTextDestroy(text);
251   spvDiagnosticDestroy(diagnostic);
252   spvBinaryDestroy(binary);
253   spvContextDestroy(context);
254 }
255
256 TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
257   const char input_text[] = "OpNop";
258
259   auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
260   int invocation = 0;
261   SetContextMessageConsumer(
262       context,
263       [&invocation](spv_message_level_t, const char*, const spv_position_t&,
264                     const char*) { ++invocation; });
265
266   spv_binary binary = nullptr;
267   ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
268                                          sizeof(input_text), &binary, nullptr));
269
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));
273
274   EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
275   EXPECT_STREQ("Nop cannot appear before the memory model instruction",
276                diagnostic->error);
277
278   spvDiagnosticDestroy(diagnostic);
279   spvBinaryDestroy(binary);
280   spvContextDestroy(context);
281 }
282
283 }  // anonymous namespace