1 #include <msp/core/algorithm.h>
2 #include <msp/fs/dir.h>
3 #include <msp/fs/utils.h>
4 #include <msp/gl/glsl/compiler.h>
5 #include <msp/gl/glsl/glsl_error.h>
6 #include <msp/gl/glsl/tokenizer.h>
7 #include <msp/strings/utils.h>
8 #include <msp/test/test.h>
10 #include <msp/io/print.h>
12 class GlslCompilerTest: public Msp::Test::RegisteredTest<GlslCompilerTest>
19 std::map<Msp::GL::SL::Stage::Type, std::string> expected_output;
22 std::list<TestCase> test_cases;
27 static const char *get_name() { return "GLSL compiler"; }
30 const TestCase &load_test_case(const std::string &);
32 void run_test_case(const TestCase *);
38 GlslCompilerTest::GlslCompilerTest()
40 FS::Path tests_dir = "glsl";
41 list<string> test_files = FS::list_filtered(tests_dir, "\\.glsl$");
43 for(const auto &fn: test_files)
44 load_test_case((tests_dir/fn).str());
46 for(const auto &tc: test_cases)
47 add(&GlslCompilerTest::run_test_case, &tc, tc.name);
50 const GlslCompilerTest::TestCase &GlslCompilerTest::load_test_case(const string &fn)
52 IO::BufferedFile file(fn);
54 test_case.name = FS::basename(fn);
55 string *target = &test_case.source;
59 if(!file.getline(line))
65 string::size_type expected = line.find("Expected output:");
66 if(expected!=string::npos)
68 string stage = strip(line.substr(expected+16));
70 target = &test_case.expected_output[GL::SL::Stage::VERTEX];
71 else if(stage=="geometry")
72 target = &test_case.expected_output[GL::SL::Stage::GEOMETRY];
73 else if(stage=="fragment")
74 target = &test_case.expected_output[GL::SL::Stage::FRAGMENT];
76 throw runtime_error("Unknown stage "+stage);
83 test_cases.push_back(test_case);
85 return test_cases.back();
88 void GlslCompilerTest::run_test_case(const TestCase *test_case)
90 GL::SL::Compiler compiler(GL::SL::Features::all());
91 compiler.set_source(test_case->source, "<test>");
92 compiler.compile(GL::SL::Compiler::PROGRAM);
94 auto stages = compiler.get_stages();
97 auto i = test_case->expected_output.find(s);
98 if(i==test_case->expected_output.end())
99 fail(format("Compiler produced extra stage %s", GL::SL::Stage::get_stage_name(s)));
101 string output = compiler.get_stage_glsl(s);
102 debug(format("Output for stage %s:", GL::SL::Stage::get_stage_name(s)));
103 auto lines = split_fields(output, '\n');
104 for(unsigned j=0; j<lines.size(); ++j)
105 debug(format("%3d: %s", j+1, lines[j]));
107 GL::SL::Tokenizer tokenizer;
108 tokenizer.begin("<output>", output);
110 GL::SL::Tokenizer expected_tkn;
111 expected_tkn.begin("<expected>", i->second);
115 string token = expected_tkn.parse_token();
119 tokenizer.expect(token);
121 catch(const GL::SL::invalid_shader_source &exc)
131 for(const auto &s: test_case->expected_output)
132 if(find(stages, s.first)==stages.end())
133 fail(format("Compiler didn't produce stage %s", GL::SL::Stage::get_stage_name(s.first)));