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", 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", r.Error());
236 }
237
238 struct ShaderTypeData {
239 const char* name;
240 ShaderType type;
241 };
242
243 using AmberScriptParserShaderTypeTest = testing::TestWithParam<ShaderTypeData>;
TEST_P(AmberScriptParserShaderTypeTest,ShaderFormats)244 TEST_P(AmberScriptParserShaderTypeTest, ShaderFormats) {
245 auto test_data = GetParam();
246
247 std::string shader_result = R"(
248 void main() {
249 gl_FragColor = vec3(2, 3, 4);
250 }
251 )";
252
253 std::string in = "SHADER " + std::string(test_data.name) +
254 R"( my_shader GLSL
255 )" + shader_result +
256 "END";
257
258 Parser parser;
259 Result r = parser.Parse(in);
260 ASSERT_TRUE(r.IsSuccess()) << r.Error();
261
262 auto script = parser.GetScript();
263 const auto& shaders = script->GetShaders();
264 ASSERT_EQ(1U, shaders.size());
265
266 const auto* shader = shaders[0].get();
267 EXPECT_EQ("my_shader", shader->GetName());
268 EXPECT_EQ(test_data.type, shader->GetType());
269 EXPECT_EQ(kShaderFormatGlsl, shader->GetFormat());
270 EXPECT_EQ(shader_result, shader->GetData());
271 }
272 INSTANTIATE_TEST_SUITE_P(
273 AmberScriptParserTestsShaderType,
274 AmberScriptParserShaderTypeTest,
275 testing::Values(
276 ShaderTypeData{"vertex", kShaderTypeVertex},
277 ShaderTypeData{"fragment", kShaderTypeFragment},
278 ShaderTypeData{"geometry", kShaderTypeGeometry},
279 ShaderTypeData{"tessellation_evaluation",
280 kShaderTypeTessellationEvaluation},
281 ShaderTypeData{"tessellation_control", kShaderTypeTessellationControl},
282 ShaderTypeData{"compute", kShaderTypeCompute},
283 ShaderTypeData{"multi",
284 kShaderTypeMulti})); // NOLINT(whitespace/parens)
285
286 struct ShaderFormatData {
287 const char* name;
288 ShaderFormat format;
289 };
290
291 using AmberScriptParserShaderFormatTest =
292 testing::TestWithParam<ShaderFormatData>;
TEST_P(AmberScriptParserShaderFormatTest,ShaderFormats)293 TEST_P(AmberScriptParserShaderFormatTest, ShaderFormats) {
294 auto test_data = GetParam();
295
296 std::string shader_result = R"(void main() {
297 gl_FragColor = vec3(2, 3, 4);
298 }
299 )";
300
301 std::string in = "SHADER vertex my_shader " + std::string(test_data.name) +
302 "\n" + shader_result + "END";
303
304 Parser parser;
305 Result r = parser.Parse(in);
306 ASSERT_TRUE(r.IsSuccess()) << r.Error();
307
308 auto script = parser.GetScript();
309 const auto& shaders = script->GetShaders();
310 ASSERT_EQ(1U, shaders.size());
311
312 const auto* shader = shaders[0].get();
313 EXPECT_EQ("my_shader", shader->GetName());
314 EXPECT_EQ(kShaderTypeVertex, shader->GetType());
315 EXPECT_EQ(test_data.format, shader->GetFormat());
316 EXPECT_EQ(shader_result, shader->GetData());
317 }
318 INSTANTIATE_TEST_SUITE_P(
319 AmberScriptParserTestsShaderFormat,
320 AmberScriptParserShaderFormatTest,
321 testing::Values(ShaderFormatData{"GLSL", kShaderFormatGlsl},
322 ShaderFormatData{"SPIRV-ASM", kShaderFormatSpirvAsm},
323 ShaderFormatData{
324 "SPIRV-HEX",
325 kShaderFormatSpirvHex})); // NOLINT(whitespace/parens)
326
TEST_F(AmberScriptParserTest,DuplicateShaderName)327 TEST_F(AmberScriptParserTest, DuplicateShaderName) {
328 std::string in = R"(
329 SHADER vertex my_shader GLSL
330 # shader
331 END
332 SHADER fragment my_shader GLSL
333 # another shader
334 END)";
335
336 Parser parser;
337 Result r = parser.Parse(in);
338 ASSERT_FALSE(r.IsSuccess());
339 EXPECT_EQ("7: duplicate shader name provided", r.Error());
340 }
341
TEST_F(AmberScriptParserTest,OpenCLCKernel)342 TEST_F(AmberScriptParserTest, OpenCLCKernel) {
343 std::string in = R"(
344 SHADER compute my_shader OPENCL-C
345 # shader
346 END
347 )";
348
349 Parser parser;
350 Result r = parser.Parse(in);
351 ASSERT_TRUE(r.IsSuccess());
352 }
353
TEST_F(AmberScriptParserTest,OpenCLCMultiKernel)354 TEST_F(AmberScriptParserTest, OpenCLCMultiKernel) {
355 std::string in = R"(
356 SHADER multi my_shader OPENCL-C
357 # shader
358 END
359 )";
360
361 Parser parser;
362 Result r = parser.Parse(in);
363 ASSERT_TRUE(r.IsSuccess());
364 }
365
366 } // namespace amberscript
367 } // namespace amber
368