X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=tests%2Fglsl%2Fglslcompiler.cpp;h=0fd0855489d63ca4f6a5de05c30c0615a9307c89;hb=1e3605edd174bce94bb21b662c7a83f79f1df37f;hp=f38db45caa6c5638e06044a624055ef2f0e63ed4;hpb=e195322eb1251f2eb0d6dfb8c2dc0fff02e5fcfc;p=libs%2Fgl.git diff --git a/tests/glsl/glslcompiler.cpp b/tests/glsl/glslcompiler.cpp index f38db45c..0fd08554 100644 --- a/tests/glsl/glslcompiler.cpp +++ b/tests/glsl/glslcompiler.cpp @@ -7,51 +7,59 @@ #include #include -#include - -class GlslCompilerTest: public Msp::Test::RegisteredTest +class GlslCompilerHelper { -private: +protected: struct TestCase { std::string name; std::string source; + Msp::GL::SL::Compiler::Mode compile_mode; + std::map spec_values; std::map expected_output; + std::string expected_error; }; std::list test_cases; + void load_all_test_cases(const Msp::FS::Path &); + const TestCase &load_test_case(const std::string &); + + void verify_output(const std::string &, const std::string &); + void verify_error(const std::string &, const std::string &); + std::string extract_line(const std::string &, const std::string::const_iterator &); + virtual void fail(const std::string &) = 0; +}; + +class GlslCompilerTest: public Msp::Test::RegisteredTest, private GlslCompilerHelper +{ public: GlslCompilerTest(); static const char *get_name() { return "GLSL compiler"; } private: - const TestCase &load_test_case(const std::string &); - void run_test_case(const TestCase *); + virtual void fail(const std::string &m) { Test::fail(m); } }; using namespace std; using namespace Msp; -GlslCompilerTest::GlslCompilerTest() +void GlslCompilerHelper::load_all_test_cases(const FS::Path &tests_dir) { - FS::Path tests_dir = "glsl"; list test_files = FS::list_filtered(tests_dir, "\\.glsl$"); test_files.sort(); for(const auto &fn: test_files) load_test_case((tests_dir/fn).str()); - - for(const auto &tc: test_cases) - add(&GlslCompilerTest::run_test_case, &tc, tc.name); } -const GlslCompilerTest::TestCase &GlslCompilerTest::load_test_case(const string &fn) +const GlslCompilerHelper::TestCase &GlslCompilerHelper::load_test_case(const string &fn) { IO::BufferedFile file(fn); TestCase test_case; test_case.name = FS::basename(fn); + test_case.compile_mode = GL::SL::Compiler::PROGRAM; string *target = &test_case.source; while(!file.eof()) { @@ -62,10 +70,10 @@ const GlslCompilerTest::TestCase &GlslCompilerTest::load_test_case(const string if(line=="*/") continue; - string::size_type expected = line.find("Expected output:"); - if(expected!=string::npos) + string::size_type pos = line.find("Expected output:"); + if(pos!=string::npos) { - string stage = strip(line.substr(expected+16)); + string stage = strip(line.substr(pos+16)); if(stage=="vertex") target = &test_case.expected_output[GL::SL::Stage::VERTEX]; else if(stage=="geometry") @@ -77,6 +85,41 @@ const GlslCompilerTest::TestCase &GlslCompilerTest::load_test_case(const string continue; } + pos = line.find("Expected error:"); + if(pos!=string::npos) + { + target = &test_case.expected_error; + continue; + } + + pos = line.find("Compile mode:"); + if(pos!=string::npos) + { + string mode = strip(line.substr(pos+13)); + if(mode=="module") + test_case.compile_mode = GL::SL::Compiler::MODULE; + else if(mode=="program") + test_case.compile_mode = GL::SL::Compiler::PROGRAM; + else + throw runtime_error("Unknown compile mode "+mode); + continue; + } + + pos = line.find("Specialize:"); + if(pos!=string::npos) + { + vector parts = split(line.substr(pos+11)); + int value = 0; + if(parts[1]=="true") + value = 1; + else if(parts[1]=="false") + value = 0; + else + value = lexical_cast(parts[1]); + test_case.spec_values[parts[0]] = value; + continue; + } + *target += line; *target += '\n'; } @@ -85,11 +128,116 @@ const GlslCompilerTest::TestCase &GlslCompilerTest::load_test_case(const string return test_cases.back(); } +void GlslCompilerHelper::verify_output(const string &output, const string &expected) +{ + GL::SL::Tokenizer tokenizer; + tokenizer.begin(output, ""); + + GL::SL::Tokenizer expected_tkn; + expected_tkn.begin(expected, ""); + + while(1) + { + string token = expected_tkn.parse_token(); + + try + { + tokenizer.expect(token); + } + catch(const GL::SL::invalid_shader_source &exc) + { + fail(exc.what()); + } + + if(token.empty()) + break; + } +} + +void GlslCompilerHelper::verify_error(const string &output, const string &expected) +{ + auto i = output.begin(); + auto j = expected.begin(); + bool space = true; + while(i!=output.end() && j!=expected.end()) + { + if(*i==*j) + { + ++i; + ++j; + } + else if(isspace(*i) && isspace(*j)) + { + ++i; + ++j; + space = true; + } + else if(space && isspace(*i)) + ++i; + else if(space && isspace(*j)) + ++j; + else + { + string out_line = extract_line(output, i); + string expect_line = extract_line(expected, j); + fail(format("Incorrect error line:\n%s\nExpected:\n%s", out_line, expect_line)); + } + } + + while(i!=output.end() && isspace(*i)) + ++i; + while(j!=expected.end() && isspace(*j)) + ++j; + + if(i!=output.end()) + fail(format("Extra error line: %s", extract_line(output, i))); + if(j!=expected.end()) + fail(format("Missing error line: %s", extract_line(expected, j))); +} + +string GlslCompilerHelper::extract_line(const string &text, const string::const_iterator &iter) +{ + string::const_iterator begin = iter; + for(; (begin!=text.begin() && *begin!='\n'); --begin) ; + if(*begin=='\n') + ++begin; + string::const_iterator end = iter; + for(; (end!=text.end() && *end!='\n'); ++end) ; + return string(begin, end); +} + + +GlslCompilerTest::GlslCompilerTest() +{ + load_all_test_cases("glsl"); + for(const auto &tc: test_cases) + add(&GlslCompilerTest::run_test_case, &tc, tc.name); +} + void GlslCompilerTest::run_test_case(const TestCase *test_case) { GL::SL::Compiler compiler(GL::SL::Features::all()); - compiler.set_source(test_case->source, ""); - compiler.compile(GL::SL::Compiler::PROGRAM); + try + { + compiler.set_source(test_case->source, ""); + if(test_case->compile_mode==GL::SL::Compiler::PROGRAM) + compiler.specialize(test_case->spec_values); + compiler.compile(test_case->compile_mode); + } + catch(const GL::SL::invalid_shader_source &exc) + { + if(!test_case->expected_error.empty()) + { + debug("Errors from compile:"); + debug(exc.what()); + verify_error(exc.what(), test_case->expected_error); + return; + } + throw; + } + + if(!test_case->expected_error.empty()) + fail("Error expected but none thrown"); auto stages = compiler.get_stages(); for(auto s: stages) @@ -104,28 +252,7 @@ void GlslCompilerTest::run_test_case(const TestCase *test_case) for(unsigned j=0; j"); - - GL::SL::Tokenizer expected_tkn; - expected_tkn.begin(i->second, ""); - - while(1) - { - string token = expected_tkn.parse_token(); - - try - { - tokenizer.expect(token); - } - catch(const GL::SL::invalid_shader_source &exc) - { - fail(exc.what()); - } - - if(token.empty()) - break; - } + verify_output(output, i->second); } for(const auto &s: test_case->expected_output)