+void GlslCompilerHelper::verify_output(const string &output, const string &expected)
+{
+ GL::SL::Tokenizer tokenizer;
+ tokenizer.begin(output, "<output>");
+
+ GL::SL::Tokenizer expected_tkn;
+ expected_tkn.begin(expected, "<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);
+}
+