1 // Copyright 2019 The Amber Authors.
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 parseried.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "gtest/gtest.h"
16 #include "src/amberscript/parser.h"
17 #include "src/shader_data.h"
18
19 namespace amber {
20 namespace amberscript {
21
22 using AmberScriptParserTest = testing::Test;
23
TEST_F(AmberScriptParserTest,ShaderPassThrough)24 TEST_F(AmberScriptParserTest, ShaderPassThrough) {
25 std::string in = "SHADER vertex my_shader1 PASSTHROUGH";
26
27 Parser parser;
28 Result r = parser.Parse(in);
29 ASSERT_TRUE(r.IsSuccess()) << r.Error();
30
31 auto script = parser.GetScript();
32 const auto& shaders = script->GetShaders();
33 ASSERT_EQ(1U, shaders.size());
34
35 const auto* shader = shaders[0].get();
36 EXPECT_EQ("my_shader1", shader->GetName());
37 EXPECT_EQ(kShaderTypeVertex, shader->GetType());
38 EXPECT_EQ(kShaderFormatSpirvAsm, shader->GetFormat());
39 EXPECT_EQ(kPassThroughShader, shader->GetData());
40 }
41
TEST_F(AmberScriptParserTest,ShaderInvalidShaderTypeToken)42 TEST_F(AmberScriptParserTest, ShaderInvalidShaderTypeToken) {
43 std::string in = "SHADER 1234 my_shader PASSTHROUGH";
44
45 Parser parser;
46 Result r = parser.Parse(in);
47 ASSERT_FALSE(r.IsSuccess());
48 EXPECT_EQ("1: invalid token when looking for shader type", r.Error());
49 }
50
TEST_F(AmberScriptParserTest,ShaderInvalidShaderNameToken)51 TEST_F(AmberScriptParserTest, ShaderInvalidShaderNameToken) {
52 std::string in = "SHADER vertex 12345 PASSTHROUGH";
53
54 Parser parser;
55 Result r = parser.Parse(in);
56 ASSERT_FALSE(r.IsSuccess());
57 EXPECT_EQ("1: invalid token when looking for shader name", r.Error());
58 }
59
TEST_F(AmberScriptParserTest,ShaderInvalidShaderFormatToken)60 TEST_F(AmberScriptParserTest, ShaderInvalidShaderFormatToken) {
61 std::string in = "SHADER vertex my_shader 1234";
62
63 Parser parser;
64 Result r = parser.Parse(in);
65 ASSERT_FALSE(r.IsSuccess());
66 EXPECT_EQ("1: invalid token when looking for shader format", r.Error());
67 }
68
69 struct NameData {
70 const char* name;
71 };
72
73 using AmberScriptParserShaderPassThroughTest = testing::TestWithParam<NameData>;
TEST_P(AmberScriptParserShaderPassThroughTest,ShaderPassThroughWithoutVertex)74 TEST_P(AmberScriptParserShaderPassThroughTest, ShaderPassThroughWithoutVertex) {
75 auto test_data = GetParam();
76
77 std::string in =
78 "SHADER " + std::string(test_data.name) + " my_shader PASSTHROUGH";
79
80 Parser parser;
81 Result r = parser.Parse(in);
82 ASSERT_FALSE(r.IsSuccess());
83 EXPECT_EQ(
84 "1: invalid shader type for PASSTHROUGH. Only vertex PASSTHROUGH "
85 "allowed",
86 r.Error());
87 }
88 INSTANTIATE_TEST_SUITE_P(
89 AmberScriptParserShaderPassThroughTests,
90 AmberScriptParserShaderPassThroughTest,
91 testing::Values(NameData{"fragment"},
92 NameData{"geometry"},
93 NameData{"tessellation_evaluation"},
94 NameData{"tessellation_control"},
95 NameData{"compute"},
96 NameData{"multi"})); // NOLINT(whitespace/parens)
97
TEST_F(AmberScriptParserTest,ShaderPassThroughUnknownShaderType)98 TEST_F(AmberScriptParserTest, ShaderPassThroughUnknownShaderType) {
99 std::string in = "SHADER UNKNOWN my_shader PASSTHROUGH";
100
101 Parser parser;
102 Result r = parser.Parse(in);
103 ASSERT_FALSE(r.IsSuccess());
104 EXPECT_EQ("1: unknown shader type: UNKNOWN", r.Error());
105 }
106
TEST_F(AmberScriptParserTest,ShaderPassThroughMissingName)107 TEST_F(AmberScriptParserTest, ShaderPassThroughMissingName) {
108 std::string in = "SHADER vertex PASSTHROUGH";
109
110 Parser parser;
111 Result r = parser.Parse(in);
112 ASSERT_FALSE(r.IsSuccess());
113 EXPECT_EQ("1: invalid token when looking for shader format", r.Error());
114 }
115
TEST_F(AmberScriptParserTest,ShaderPassThroughExtraParameters)116 TEST_F(AmberScriptParserTest, ShaderPassThroughExtraParameters) {
117 std::string in = "SHADER vertex my_shader PASSTHROUGH INVALID";
118
119 Parser parser;
120 Result r = parser.Parse(in);
121 ASSERT_FALSE(r.IsSuccess());
122 EXPECT_EQ("1: extra parameters after SHADER PASSTHROUGH: INVALID", r.Error());
123 }
124
TEST_F(AmberScriptParserTest,Shader)125 TEST_F(AmberScriptParserTest, Shader) {
126 std::string shader_result = R"(
127 # Shader has a comment in it.
128 void main() {
129 gl_FragColor = vec3(2, 3, 4);
130 }
131 )";
132
133 std::string in = R"(#!amber
134 SHADER geometry shader_name GLSL
135 )" + shader_result +
136 "END";
137
138 Parser parser;
139 Result r = parser.Parse(in);
140 ASSERT_TRUE(r.IsSuccess()) << r.Error();
141
142 auto script = parser.GetScript();
143 const auto& shaders = script->GetShaders();
144 ASSERT_EQ(1U, shaders.size());
145
146 const auto* shader = shaders[0].get();
147 EXPECT_EQ("shader_name", shader->GetName());
148 EXPECT_EQ(kShaderTypeGeometry, shader->GetType());
149 EXPECT_EQ(kShaderFormatGlsl, shader->GetFormat());
150 EXPECT_EQ(shader_result, shader->GetData());
151 }
152
TEST_F(AmberScriptParserTest,ShaderInvalidFormat)153 TEST_F(AmberScriptParserTest, ShaderInvalidFormat) {
154 std::string in = R"(#!amber
155 SHADER geometry shader_name INVALID
156 # Shader has a comment in it.
157 void main() {
158 gl_FragColor = vec3(2, 3, 4);
159 }
160 END)";
161
162 Parser parser;
163 Result r = parser.Parse(in);
164 ASSERT_FALSE(r.IsSuccess());
165 EXPECT_EQ("2: unknown shader format: INVALID", r.Error());
166 }
167
TEST_F(AmberScriptParserTest,ShaderMissingFormat)168 TEST_F(AmberScriptParserTest, ShaderMissingFormat) {
169 std::string in = R"(#!amber
170 SHADER geometry shader_name
171 # Shader has a comment in it.
172 void main() {
173 gl_FragColor = vec3(2, 3, 4);
174 }
175 END)";
176
177 Parser parser;
178 Result r = parser.Parse(in);
179 ASSERT_FALSE(r.IsSuccess());
180 EXPECT_EQ("3: invalid token when looking for shader format", r.Error());
181 }
182
TEST_F(AmberScriptParserTest,ShaderEmpty)183 TEST_F(AmberScriptParserTest, ShaderEmpty) {
184 std::string in = R"(#!amber
185 SHADER geometry shader_name GLSL
186 END)";
187
188 Parser parser;
189 Result r = parser.Parse(in);
190 ASSERT_FALSE(r.IsSuccess());
191 EXPECT_EQ("3: SHADER must not be empty", r.Error());
192 }
193
TEST_F(AmberScriptParserTest,ShaderMissingName)194 TEST_F(AmberScriptParserTest, ShaderMissingName) {
195 std::string in = R"(#!amber
196 SHADER geometry GLSL
197 # Shader has a comment in it.
198 void main() {
199 gl_FragColor = vec3(2, 3, 4);
200 }
201 END)";
202
203 Parser parser;
204 Result r = parser.Parse(in);
205 ASSERT_FALSE(r.IsSuccess());
206 EXPECT_EQ("3: invalid token when looking for shader format", r.Error());
207 }
208
TEST_F(AmberScriptParserTest,ShaderMissingEnd)209 TEST_F(AmberScriptParserTest, ShaderMissingEnd) {
210 std::string in = R"(#!amber
211 SHADER geometry shader_name GLSL
212 # Shader has a comment in it.
213 void main() {
214 gl_FragColor = vec3(2, 3, 4);
215 })";
216
217 Parser parser;
218 Result r = parser.Parse(in);
219 ASSERT_FALSE(r.IsSuccess());
220 EXPECT_EQ("6: SHADER missing END command", r.Error());
221 }
222
TEST_F(AmberScriptParserTest,ShaderExtraParameter)223 TEST_F(AmberScriptParserTest, ShaderExtraParameter) {
224 std::string in = R"(#!amber
225 SHADER geometry shader_name GLSL INVALID
226 # Shader has a comment in it.
227 void main() {
228 gl_FragColor = vec3(2, 3, 4);
229 }
230 END)";
231
232 Parser parser;
233 Result r = parser.Parse(in);
234 ASSERT_FALSE(r.IsSuccess());
235 EXPECT_EQ("2: extra parameters after SHADER command: INVALID", r.Error());
236 }
237
TEST_F(AmberScriptParserTest,ShaderTargetEnv)238 TEST_F(AmberScriptParserTest, ShaderTargetEnv) {
239 std::string in = R"(#!amber
240 SHADER geometry shader_name GLSL TARGET_ENV spv1.4
241 void main() {
242 gl_FragColor = vec3(2, 3, 4);
243 }
244 END)";
245
246 Parser parser;
247 Result r = parser.Parse(in);
248
249 ASSERT_TRUE(r.IsSuccess()) << r.Error();
250
251 auto script = parser.GetScript();
252 const auto& shaders = script->GetShaders();
253 ASSERT_EQ(1U, shaders.size());
254
255 const auto* shader = shaders[0].get();
256 EXPECT_EQ("spv1.4", shader->GetTargetEnv());
257 }
258
TEST_F(AmberScriptParserTest,ShaderTargetEnvMissingEnv)259 TEST_F(AmberScriptParserTest, ShaderTargetEnvMissingEnv) {
260 std::string in = R"(#!amber
261 SHADER geometry shader_name GLSL TARGET_ENV
262 void main() {
263 gl_FragColor = vec3(2, 3, 4);
264 }
265 END)";
266
267 Parser parser;
268 Result r = parser.Parse(in);
269 ASSERT_FALSE(r.IsSuccess());
270 EXPECT_EQ("3: expected target environment after TARGET_ENV", r.Error());
271 }
272
TEST_F(AmberScriptParserTest,ShaderTargetEnvInvalidEnv)273 TEST_F(AmberScriptParserTest, ShaderTargetEnvInvalidEnv) {
274 std::string in = R"(#!amber
275 SHADER geometry shader_name GLSL TARGET_ENV 12345
276 void main() {
277 gl_FragColor = vec3(2, 3, 4);
278 }
279 END)";
280
281 Parser parser;
282 Result r = parser.Parse(in);
283 ASSERT_FALSE(r.IsSuccess());
284 EXPECT_EQ("2: expected target environment after TARGET_ENV", r.Error());
285 }
286
TEST_F(AmberScriptParserTest,ShaderVirtualFile)287 TEST_F(AmberScriptParserTest, ShaderVirtualFile) {
288 std::string in = R"(#!amber
289 VIRTUAL_FILE my_shader.hlsl
290 My shader source
291 END
292
293 SHADER vertex my_shader HLSL VIRTUAL_FILE my_shader.hlsl
294 )";
295
296 Parser parser;
297 Result r = parser.Parse(in);
298 ASSERT_EQ(r.Error(), "");
299
300 auto script = parser.GetScript();
301 auto shader = script->GetShader("my_shader");
302 ASSERT_TRUE(shader != nullptr);
303 auto source = shader->GetData();
304 ASSERT_EQ("My shader source\n", shader->GetData());
305 }
306
TEST_F(AmberScriptParserTest,VirtualFileDuplicatePath)307 TEST_F(AmberScriptParserTest, VirtualFileDuplicatePath) {
308 std::string in = R"(#!amber
309 VIRTUAL_FILE my.file
310 Blah
311 END
312
313 VIRTUAL_FILE my.file
314 Blah
315 END
316 )";
317
318 Parser parser;
319 Result r = parser.Parse(in);
320 ASSERT_EQ(r.Error(), "8: Virtual file 'my.file' already declared");
321 }
322
TEST_F(AmberScriptParserTest,VirtualFileEmptyPath)323 TEST_F(AmberScriptParserTest, VirtualFileEmptyPath) {
324 std::string in = R"(#!amber
325 VIRTUAL_FILE ""
326 Blah
327 END
328 )";
329
330 Parser parser;
331 Result r = parser.Parse(in);
332 ASSERT_EQ(r.Error(), "4: Virtual file path was empty");
333 }
334
335 struct ShaderTypeData {
336 const char* name;
337 ShaderType type;
338 };
339
340 using AmberScriptParserShaderTypeTest = testing::TestWithParam<ShaderTypeData>;
TEST_P(AmberScriptParserShaderTypeTest,ShaderFormats)341 TEST_P(AmberScriptParserShaderTypeTest, ShaderFormats) {
342 auto test_data = GetParam();
343
344 std::string shader_result = R"(
345 void main() {
346 gl_FragColor = vec3(2, 3, 4);
347 }
348 )";
349
350 std::string in = "SHADER " + std::string(test_data.name) +
351 R"( my_shader GLSL
352 )" + shader_result +
353 "END";
354
355 Parser parser;
356 Result r = parser.Parse(in);
357 ASSERT_TRUE(r.IsSuccess()) << r.Error();
358
359 auto script = parser.GetScript();
360 const auto& shaders = script->GetShaders();
361 ASSERT_EQ(1U, shaders.size());
362
363 const auto* shader = shaders[0].get();
364 EXPECT_EQ("my_shader", shader->GetName());
365 EXPECT_EQ(test_data.type, shader->GetType());
366 EXPECT_EQ(kShaderFormatGlsl, shader->GetFormat());
367 EXPECT_EQ(shader_result, shader->GetData());
368 }
369 INSTANTIATE_TEST_SUITE_P(
370 AmberScriptParserTestsShaderType,
371 AmberScriptParserShaderTypeTest,
372 testing::Values(
373 ShaderTypeData{"vertex", kShaderTypeVertex},
374 ShaderTypeData{"fragment", kShaderTypeFragment},
375 ShaderTypeData{"geometry", kShaderTypeGeometry},
376 ShaderTypeData{"tessellation_evaluation",
377 kShaderTypeTessellationEvaluation},
378 ShaderTypeData{"tessellation_control", kShaderTypeTessellationControl},
379 ShaderTypeData{"compute", kShaderTypeCompute},
380 ShaderTypeData{"multi",
381 kShaderTypeMulti})); // NOLINT(whitespace/parens)
382
383 struct ShaderFormatData {
384 const char* name;
385 ShaderFormat format;
386 };
387
388 using AmberScriptParserShaderFormatTest =
389 testing::TestWithParam<ShaderFormatData>;
TEST_P(AmberScriptParserShaderFormatTest,ShaderFormats)390 TEST_P(AmberScriptParserShaderFormatTest, ShaderFormats) {
391 auto test_data = GetParam();
392
393 std::string shader_result = R"(void main() {
394 gl_FragColor = vec3(2, 3, 4);
395 }
396 )";
397
398 std::string in = "SHADER vertex my_shader " + std::string(test_data.name) +
399 "\n" + shader_result + "END";
400
401 Parser parser;
402 Result r = parser.Parse(in);
403 ASSERT_TRUE(r.IsSuccess()) << r.Error();
404
405 auto script = parser.GetScript();
406 const auto& shaders = script->GetShaders();
407 ASSERT_EQ(1U, shaders.size());
408
409 const auto* shader = shaders[0].get();
410 EXPECT_EQ("my_shader", shader->GetName());
411 EXPECT_EQ(kShaderTypeVertex, shader->GetType());
412 EXPECT_EQ(test_data.format, shader->GetFormat());
413 EXPECT_EQ(shader_result, shader->GetData());
414 }
415
416 INSTANTIATE_TEST_SUITE_P(
417 AmberScriptParserTestsShaderFormat,
418 AmberScriptParserShaderFormatTest,
419 testing::Values(ShaderFormatData{"GLSL", kShaderFormatGlsl},
420 ShaderFormatData{"SPIRV-ASM", kShaderFormatSpirvAsm},
421 ShaderFormatData{
422 "SPIRV-HEX",
423 kShaderFormatSpirvHex})); // NOLINT(whitespace/parens)
424
TEST_F(AmberScriptParserTest,DuplicateShaderName)425 TEST_F(AmberScriptParserTest, DuplicateShaderName) {
426 std::string in = R"(
427 SHADER vertex my_shader GLSL
428 # shader
429 END
430 SHADER fragment my_shader GLSL
431 # another shader
432 END)";
433
434 Parser parser;
435 Result r = parser.Parse(in);
436 ASSERT_FALSE(r.IsSuccess());
437 EXPECT_EQ("7: duplicate shader name provided", r.Error());
438 }
439
TEST_F(AmberScriptParserTest,OpenCLCKernel)440 TEST_F(AmberScriptParserTest, OpenCLCKernel) {
441 std::string in = R"(
442 SHADER compute my_shader OPENCL-C
443 # shader
444 END
445 )";
446
447 Parser parser;
448 Result r = parser.Parse(in);
449 ASSERT_TRUE(r.IsSuccess());
450 }
451
TEST_F(AmberScriptParserTest,OpenCLCMultiKernel)452 TEST_F(AmberScriptParserTest, OpenCLCMultiKernel) {
453 std::string in = R"(
454 SHADER multi my_shader OPENCL-C
455 # shader
456 END
457 )";
458
459 Parser parser;
460 Result r = parser.Parse(in);
461 ASSERT_TRUE(r.IsSuccess());
462 }
463
TEST_F(AmberScriptParserTest,ShaderDefaultFilePath)464 TEST_F(AmberScriptParserTest, ShaderDefaultFilePath) {
465 std::string in = R"(#!amber
466 SHADER fragment shader_name GLSL
467 void main() {
468 gl_FragColor = vec3(2, 3, 4);
469 }
470 END)";
471
472 Parser parser;
473 Result r = parser.Parse(in);
474 ASSERT_TRUE(r.IsSuccess()) << r.Error();
475
476 auto script = parser.GetScript();
477 auto shader = script->GetShader("shader_name");
478 EXPECT_EQ("embedded-shaders/shader_name", shader->GetFilePath());
479 }
480
TEST_F(AmberScriptParserTest,ShaderVirtualFilePath)481 TEST_F(AmberScriptParserTest, ShaderVirtualFilePath) {
482 std::string in = R"(#!amber
483 VIRTUAL_FILE my_fragment_shader
484 void main() {
485 gl_FragColor = vec3(2, 3, 4);
486 }
487 END
488
489 SHADER fragment shader_name GLSL VIRTUAL_FILE my_fragment_shader
490 )";
491
492 Parser parser;
493 Result r = parser.Parse(in);
494 ASSERT_TRUE(r.IsSuccess()) << r.Error();
495
496 auto script = parser.GetScript();
497 auto shader = script->GetShader("shader_name");
498 EXPECT_EQ("my_fragment_shader", shader->GetFilePath());
499 }
500
501 } // namespace amberscript
502 } // namespace amber
503