/* * Copyright 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // Test program to exercise the Technique Antlr grammar using both files and // in-memory string buffers. #include "tests/common/win/testing_common.h" #include "compiler/technique/technique_parser.h" namespace o3d { // classes --------------------------------------------------------------------- class TechniqueParserTest : public testing::Test { protected: virtual void SetUp(); virtual void TearDown(); private: }; void TechniqueParserTest::SetUp() { } void TechniqueParserTest::TearDown() { } // globals --------------------------------------------------------------------- char simple_fx_source[] = "float4x4 worldViewProj : WORLDVIEWPROJECTION; \ void vs(in float4 pos, out float4 opos) { \ opos = mul(pos, worldViewProj); \ } \ float4 fs(): COLOR { \ return float3(0.33f, 0.57f, 0.10f); \ } \ technique t1 { \ pass p0 { \ VertexShader = compile vs_2_0 vs(); \ PixelShader = compile ps_2_0 fs(); \ } \ } \ "; char lambert_fx_source[] = "struct a2v { \ float4 pos : POSITION; \ float3 normal : NORMAL; \ }; \ \ struct v2f { \ float4 pos : POSITION; \ float3 n : TEXCOORD0; \ float3 l : TEXCOORD1; \ }; \ \ float4x4 worldViewProj : WorldViewProjection; \ float4x4 world : World; \ float4x4 worldIT : WorldInverseTranspose; \ float3 lightWorldPos; \ float4 lightColor; \ \ v2f vsMain(a2v IN) { \ v2f OUT; \ OUT.pos = mul(IN.pos, worldViewProj); \ OUT.n = mul(float4(IN.normal,0), worldIT).xyz; \ OUT.l = lightWorldPos-mul(IN.pos, world).xyz; \ return OUT; \ } \ \ float4 fsMain(v2f IN): COLOR { \ float3 l=normalize(IN.l); \ float3 n=normalize(IN.n); \ float4 litR=lit(dot(n,l),0,0); \ return emissive+lightColor*(ambient+diffuse*litR.y); \ } \ \ technique { \ pass p0 { \ VertexShader = compile vs_2_0 vsMain(); \ PixelShader = compile ps_2_0 fsMain(); \ } \ } \ "; // ----------------------------------------------------------------------------- TEST_F(TechniqueParserTest, ParseSimpleFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/simple.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_LT(0, static_cast(technique_list.size())); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ("t1", technique_list[0].name); ASSERT_EQ(0, technique_list[0].annotation.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("p0", technique_list[0].pass[0].name); ASSERT_EQ(0, technique_list[0].pass[0].annotation.size()); EXPECT_EQ("vs", technique_list[0].pass[0].vertex_shader_entry); EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments); EXPECT_EQ("fs", technique_list[0].pass[0].fragment_shader_entry); EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments); ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size()); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseSimpleFXFromString) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; EXPECT_TRUE(ParseFxString(simple_fx_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_LT(0, static_cast(technique_list.size())); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ("t1", technique_list[0].name); ASSERT_EQ(0, technique_list[0].annotation.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("p0", technique_list[0].pass[0].name); ASSERT_EQ(0, technique_list[0].pass[0].annotation.size()); EXPECT_EQ("vs", technique_list[0].pass[0].vertex_shader_entry); EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments); EXPECT_EQ("fs", technique_list[0].pass[0].fragment_shader_entry); EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments); ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size()); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseLambertFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/lambert.fx"; EXPECT_TRUE(ParseFxFile(filepath.c_str(), &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_LT(0, static_cast(technique_list.size())); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ("", technique_list[0].name); ASSERT_EQ(0, technique_list[0].annotation.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("p0", technique_list[0].pass[0].name); ASSERT_EQ(0, technique_list[0].pass[0].annotation.size()); EXPECT_EQ("vsMain", technique_list[0].pass[0].vertex_shader_entry); EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments); EXPECT_EQ("fsMain", technique_list[0].pass[0].fragment_shader_entry); EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments); ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size()); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseLambertFXFromString) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; EXPECT_TRUE(ParseFxString(lambert_fx_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_LT(0, static_cast(technique_list.size())); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ("", technique_list[0].name); ASSERT_EQ(0, technique_list[0].annotation.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("p0", technique_list[0].pass[0].name); ASSERT_EQ(0, technique_list[0].pass[0].annotation.size()); EXPECT_EQ("vsMain", technique_list[0].pass[0].vertex_shader_entry); EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments); EXPECT_EQ("fsMain", technique_list[0].pass[0].fragment_shader_entry); EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments); ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size()); ASSERT_EQ(0, sampler_list.size()); } // Test the longer shaders from files ------------------------------------------ TEST_F(TechniqueParserTest, ParseNoShaderFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/noshader.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_LT(0, static_cast(technique_list.size())); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ("t1", technique_list[0].name); ASSERT_EQ(0, technique_list[0].annotation.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("p0", technique_list[0].pass[0].name); ASSERT_EQ(0, technique_list[0].pass[0].annotation.size()); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_entry); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_entry); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_profile); EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments); ASSERT_EQ(4, technique_list[0].pass[0].state_assignment.size()); EXPECT_EQ("ZEnable", technique_list[0].pass[0].state_assignment[0].name); EXPECT_EQ("true", technique_list[0].pass[0].state_assignment[0].value); EXPECT_EQ("ZWriteEnable", technique_list[0].pass[0].state_assignment[1].name); EXPECT_EQ("true", technique_list[0].pass[0].state_assignment[1].value); EXPECT_EQ("ZFunc", technique_list[0].pass[0].state_assignment[2].name); EXPECT_EQ("LessEqual", technique_list[0].pass[0].state_assignment[2].value); EXPECT_EQ("CullMode", technique_list[0].pass[0].state_assignment[3].name); EXPECT_EQ("None", technique_list[0].pass[0].state_assignment[3].value); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseNoTechniqueFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/notechnique.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(0, technique_list.size()); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseFurFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/fur.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); ASSERT_EQ(1, technique_list.size()); EXPECT_EQ(1, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseShadowMapFXFromFile) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/shadow_map.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); ASSERT_EQ(2, technique_list.size()); EXPECT_EQ(2, sampler_list.size()); } // Tests of error cases -------------------------------------------------------- TEST_F(TechniqueParserTest, ParseEmptyString) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String empty_fx_source = ""; EXPECT_TRUE(ParseFxString(empty_fx_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(0, technique_list.size()); EXPECT_EQ(String(""), shader_source); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseInvalidString) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String invalid_fx_source = "$%^~ This is an invalid shader."; EXPECT_FALSE(ParseFxString(invalid_fx_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(0, technique_list.size()); EXPECT_EQ(0, sampler_list.size()); // TODO: make sure the string was rejected as an invalid HLSL // program and test the parser errors. } TEST_F(TechniqueParserTest, ParseInvalidFilename) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/invalid_filename.fx"; EXPECT_FALSE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(technique_list.size(), 0); EXPECT_EQ(shader_source, String("")); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseInvalidPassIdentifier) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String invalid_pass_identifier_source = "technique { pass pass { } };"; EXPECT_FALSE(ParseFxString(invalid_pass_identifier_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(1, technique_list.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("", technique_list[0].pass[0].name); EXPECT_EQ(shader_source, String("")); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseInvalidStateName) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; // NOTE: "FragmentShader" should read "FragmentProgram" or "PixelShader". String invalid_pass_identifier_source = "technique { pass { FragmentShader = compile ps_2_0 nothing(); } };"; EXPECT_FALSE(ParseFxString(invalid_pass_identifier_source, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(1, technique_list.size()); ASSERT_EQ(1, technique_list[0].pass.size()); EXPECT_EQ("", technique_list[0].pass[0].name); EXPECT_EQ(shader_source, String("")); EXPECT_EQ(0, sampler_list.size()); } TEST_F(TechniqueParserTest, ParseSampler) { String shader_source, error_string; TechniqueDeclarationList technique_list; SamplerStateList sampler_list; String filepath = *g_program_path + "/unittest_data/sampler_test.fx"; EXPECT_TRUE(ParseFxFile(filepath, &shader_source, &sampler_list, &technique_list, &error_string)); EXPECT_EQ(1, technique_list.size()); ASSERT_EQ(1, technique_list[0].pass.size()); ASSERT_EQ(1, sampler_list.size()); EXPECT_EQ("Tex0", sampler_list[0].texture); EXPECT_EQ("Linear", sampler_list[0].min_filter); EXPECT_EQ("Point", sampler_list[0].mag_filter); EXPECT_EQ("None", sampler_list[0].mip_filter); EXPECT_EQ("Mirror", sampler_list[0].address_u); EXPECT_EQ("Wrap", sampler_list[0].address_v); EXPECT_EQ("Clamp", sampler_list[0].address_w); EXPECT_EQ("16", sampler_list[0].max_anisotropy); EXPECT_EQ("float4(1.0, 0.0, 0.0, 1.0)", sampler_list[0].border_color); } } // namespace o3d