| // Copyright 2018 The Amber Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "src/vkscript/section_parser.h" |
| |
| #include "gtest/gtest.h" |
| #include "src/shader_data.h" |
| |
| namespace amber { |
| namespace vkscript { |
| |
| using SectionParserTest = testing::Test; |
| |
| TEST_F(SectionParserTest, SectionParserCommentSection) { |
| std::string input = "[comment]\nThis is the comment body\n.Lots of Text."; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()); |
| |
| auto sections = p.Sections(); |
| EXPECT_TRUE(sections.empty()); |
| } |
| |
| TEST_F(SectionParserTest, ParseShaderGlslVertex) { |
| std::string shader = R"(#version 430 |
| void main() { |
| })"; |
| std::string input = "[vertex shader]\n" + shader; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()); |
| |
| auto sections = p.Sections(); |
| ASSERT_EQ(1U, sections.size()); |
| EXPECT_EQ(NodeType::kShader, sections[0].section_type); |
| EXPECT_EQ(kShaderTypeVertex, sections[0].shader_type); |
| EXPECT_EQ(kShaderFormatGlsl, sections[0].format); |
| EXPECT_EQ(shader, sections[0].contents); |
| } |
| |
| TEST_F(SectionParserTest, ParseShaderGlslVertexPassthrough) { |
| std::string input = "[vertex shader passthrough]"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()); |
| |
| auto sections = p.Sections(); |
| ASSERT_EQ(1U, sections.size()); |
| EXPECT_EQ(NodeType::kShader, sections[0].section_type); |
| EXPECT_EQ(kShaderTypeVertex, sections[0].shader_type); |
| EXPECT_EQ(kShaderFormatSpirvAsm, sections[0].format); |
| EXPECT_EQ(kPassThroughShader, sections[0].contents); |
| } |
| |
| TEST_F(SectionParserTest, SectionParserMultipleSections) { |
| std::string input = R"( |
| [comment] |
| This is a test. |
| |
| [vertex shader passthrough] |
| [fragment shader] |
| #version 430 |
| void main() {} |
| |
| [geometry shader] |
| float4 main() {} |
| |
| [comment] |
| Another comment section. |
| Multi line. |
| |
| [indices] |
| 1 2 3 4 |
| 5 6 7 8 |
| [test] |
| test body.)"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()) << r.Error(); |
| |
| auto sections = p.Sections(); |
| ASSERT_EQ(5U, sections.size()); |
| |
| // Passthrough vertext shader |
| EXPECT_EQ(NodeType::kShader, sections[0].section_type); |
| EXPECT_EQ(kShaderTypeVertex, sections[0].shader_type); |
| EXPECT_EQ(kShaderFormatSpirvAsm, sections[0].format); |
| EXPECT_EQ(kPassThroughShader, sections[0].contents); |
| |
| // fragment shader |
| EXPECT_EQ(NodeType::kShader, sections[1].section_type); |
| EXPECT_EQ(kShaderTypeFragment, sections[1].shader_type); |
| EXPECT_EQ(kShaderFormatGlsl, sections[1].format); |
| EXPECT_EQ("#version 430\nvoid main() {}", sections[1].contents); |
| |
| // geometry shader |
| EXPECT_EQ(NodeType::kShader, sections[2].section_type); |
| EXPECT_EQ(kShaderTypeGeometry, sections[2].shader_type); |
| EXPECT_EQ(kShaderFormatGlsl, sections[2].format); |
| EXPECT_EQ("float4 main() {}", sections[2].contents); |
| |
| // indices |
| EXPECT_EQ(NodeType::kIndices, sections[3].section_type); |
| EXPECT_EQ(kShaderFormatText, sections[3].format); |
| EXPECT_EQ("1 2 3 4\n5 6 7 8", sections[3].contents); |
| |
| // test |
| EXPECT_EQ(NodeType::kTest, sections[4].section_type); |
| EXPECT_EQ(kShaderFormatText, sections[4].format); |
| EXPECT_EQ("test body.", sections[4].contents); |
| } |
| |
| TEST_F(SectionParserTest, SkipCommentLinesOutsideSections) { |
| std::string input = "# comment 1\n#comment 2\r\n[vertex shader]"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()); |
| |
| auto sections = p.Sections(); |
| ASSERT_EQ(1U, sections.size()); |
| EXPECT_EQ(NodeType::kShader, sections[0].section_type); |
| EXPECT_EQ(kShaderTypeVertex, sections[0].shader_type); |
| EXPECT_EQ(kShaderFormatGlsl, sections[0].format); |
| EXPECT_EQ("", sections[0].contents); |
| } |
| |
| TEST_F(SectionParserTest, SkipBlankLinesOutsideSections) { |
| std::string input = "\n\r\n[vertex shader]"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| ASSERT_TRUE(r.IsSuccess()) << r.Error(); |
| |
| auto sections = p.Sections(); |
| ASSERT_EQ(1U, sections.size()); |
| EXPECT_EQ(NodeType::kShader, sections[0].section_type); |
| EXPECT_EQ(kShaderTypeVertex, sections[0].shader_type); |
| EXPECT_EQ(kShaderFormatGlsl, sections[0].format); |
| EXPECT_EQ("", sections[0].contents); |
| } |
| |
| TEST_F(SectionParserTest, UnknownTextOutsideSection) { |
| std::string input = "Invalid Text"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| EXPECT_FALSE(r.IsSuccess()); |
| EXPECT_EQ("1: Invalid character", r.Error()); |
| } |
| |
| TEST_F(SectionParserTest, UnknownSectionName) { |
| std::string input = "[Invalid Section]"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| EXPECT_FALSE(r.IsSuccess()); |
| EXPECT_EQ("1: Invalid name: Invalid Section", r.Error()); |
| } |
| |
| TEST_F(SectionParserTest, MissingSectionClose) { |
| std::string input = "[vertex shader\nMore Content"; |
| |
| SectionParser p; |
| Result r = p.SplitSectionsForTesting(input); |
| EXPECT_FALSE(r.IsSuccess()); |
| EXPECT_EQ("1: Missing section close", r.Error()); |
| } |
| |
| TEST_F(SectionParserTest, NameToNodeType) { |
| struct { |
| const char* name; |
| NodeType section_type; |
| ShaderType shader_type; |
| ShaderFormat fmt; |
| } name_cases[] = { |
| {"comment", NodeType::kComment, kShaderTypeVertex, kShaderFormatText}, |
| {"indices", NodeType::kIndices, kShaderTypeVertex, kShaderFormatText}, |
| {"require", NodeType::kRequire, kShaderTypeVertex, kShaderFormatText}, |
| {"test", NodeType::kTest, kShaderTypeVertex, kShaderFormatText}, |
| {"vertex data", NodeType::kVertexData, kShaderTypeVertex, |
| kShaderFormatText}, |
| |
| {"compute shader", NodeType::kShader, kShaderTypeCompute, |
| kShaderFormatGlsl}, |
| {"fragment shader", NodeType::kShader, kShaderTypeFragment, |
| kShaderFormatGlsl}, |
| {"geometry shader", NodeType::kShader, kShaderTypeGeometry, |
| kShaderFormatGlsl}, |
| {"tessellation control shader", NodeType::kShader, |
| kShaderTypeTessellationControl, kShaderFormatGlsl}, |
| {"tessellation evaluation shader", NodeType::kShader, |
| kShaderTypeTessellationEvaluation, kShaderFormatGlsl}, |
| {"vertex shader", NodeType::kShader, kShaderTypeVertex, |
| kShaderFormatGlsl}, |
| {"compute shader spirv", NodeType::kShader, kShaderTypeCompute, |
| kShaderFormatSpirvAsm}, |
| {"fragment shader spirv", NodeType::kShader, kShaderTypeFragment, |
| kShaderFormatSpirvAsm}, |
| {"geometry shader spirv", NodeType::kShader, kShaderTypeGeometry, |
| kShaderFormatSpirvAsm}, |
| {"tessellation control shader spirv", NodeType::kShader, |
| kShaderTypeTessellationControl, kShaderFormatSpirvAsm}, |
| {"tessellation evaluation shader spirv", NodeType::kShader, |
| kShaderTypeTessellationEvaluation, kShaderFormatSpirvAsm}, |
| {"vertex shader spirv", NodeType::kShader, kShaderTypeVertex, |
| kShaderFormatSpirvAsm}, |
| {"compute shader spirv hex", NodeType::kShader, kShaderTypeCompute, |
| kShaderFormatSpirvHex}, |
| {"fragment shader spirv hex", NodeType::kShader, kShaderTypeFragment, |
| kShaderFormatSpirvHex}, |
| {"geometry shader spirv hex", NodeType::kShader, kShaderTypeGeometry, |
| kShaderFormatSpirvHex}, |
| {"tessellation control shader spirv hex", NodeType::kShader, |
| kShaderTypeTessellationControl, kShaderFormatSpirvHex}, |
| {"tessellation evaluation shader spirv hex", NodeType::kShader, |
| kShaderTypeTessellationEvaluation, kShaderFormatSpirvHex}, |
| {"vertex shader spirv hex", NodeType::kShader, kShaderTypeVertex, |
| kShaderFormatSpirvHex}, |
| {"vertex shader passthrough", NodeType::kShader, kShaderTypeVertex, |
| kShaderFormatDefault}}; |
| |
| for (auto name_case : name_cases) { |
| NodeType section_type = NodeType::kTest; |
| ShaderType shader_type = kShaderTypeVertex; |
| ShaderFormat fmt = kShaderFormatText; |
| SectionParser p; |
| Result r = p.NameToNodeTypeForTesting(name_case.name, §ion_type, |
| &shader_type, &fmt); |
| |
| ASSERT_TRUE(r.IsSuccess()) << r.Error(); |
| EXPECT_EQ(name_case.section_type, section_type) << name_case.name; |
| EXPECT_EQ(name_case.shader_type, shader_type) << name_case.name; |
| EXPECT_EQ(name_case.fmt, fmt) << name_case.name; |
| } |
| } |
| |
| TEST_F(SectionParserTest, NameToNodeTypeInvalidName) { |
| NodeType section_type = NodeType::kTest; |
| ShaderType shader_type = kShaderTypeVertex; |
| ShaderFormat fmt = kShaderFormatText; |
| SectionParser p; |
| Result r = p.NameToNodeTypeForTesting("InvalidName", §ion_type, |
| &shader_type, &fmt); |
| ASSERT_FALSE(r.IsSuccess()); |
| EXPECT_EQ("Invalid name: InvalidName", r.Error()); |
| } |
| |
| TEST_F(SectionParserTest, NameToSectionInvalidSuffix) { |
| struct { |
| const char* name; |
| } cases[] = {{"comment spirv"}, {"indices spirv"}, |
| {"require spirv"}, {"test spirv"}, |
| {"vertex data spirv"}, {"comment spirv hex"}, |
| {"indices spirv hex"}, {"require spirv hex"}, |
| {"test spirv hex"}, {"vertex data spirv hex"}}; |
| |
| for (auto name_case : cases) { |
| NodeType section_type = NodeType::kTest; |
| ShaderType shader_type = kShaderTypeVertex; |
| ShaderFormat fmt = kShaderFormatText; |
| SectionParser p; |
| |
| Result r = p.NameToNodeTypeForTesting(name_case.name, §ion_type, |
| &shader_type, &fmt); |
| ASSERT_FALSE(r.IsSuccess()) << name_case.name; |
| EXPECT_EQ("Invalid source format: " + std::string(name_case.name), |
| r.Error()); |
| } |
| } |
| |
| TEST_F(SectionParserTest, HasShader) { |
| EXPECT_TRUE(SectionParser::HasShader(NodeType::kShader)); |
| } |
| |
| TEST_F(SectionParserTest, HasNoShader) { |
| const NodeType false_types[] = {NodeType::kComment, NodeType::kTest, |
| NodeType::kIndices, NodeType::kVertexData, |
| NodeType::kRequire}; |
| for (auto type : false_types) { |
| EXPECT_FALSE(SectionParser::HasShader(type)); |
| } |
| } |
| |
| } // namespace vkscript |
| } // namespace amber |