// Copyright 2012 The Kyua Authors. // 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. #include "utils/text/templates.hpp" #include <fstream> #include <sstream> #include <atf-c++.hpp> #include "utils/fs/operations.hpp" #include "utils/fs/path.hpp" #include "utils/text/exceptions.hpp" namespace fs = utils::fs; namespace text = utils::text; namespace { /// Applies a set of templates to an input string and validates the output. /// /// This fails the test case if exp_output does not match the document generated /// by the application of the templates. /// /// \param templates The templates to apply. /// \param input_str The input document to which to apply the templates. /// \param exp_output The expected output document. static void do_test_ok(const text::templates_def& templates, const std::string& input_str, const std::string& exp_output) { std::istringstream input(input_str); std::ostringstream output; text::instantiate(templates, input, output); ATF_REQUIRE_EQ(exp_output, output.str()); } /// Applies a set of templates to an input string and checks for an error. /// /// This fails the test case if the exception raised by the template processing /// does not match the expected message. /// /// \param templates The templates to apply. /// \param input_str The input document to which to apply the templates. /// \param exp_message The expected error message in the raised exception. static void do_test_fail(const text::templates_def& templates, const std::string& input_str, const std::string& exp_message) { std::istringstream input(input_str); std::ostringstream output; ATF_REQUIRE_THROW_RE(text::syntax_error, exp_message, text::instantiate(templates, input, output)); } } // anonymous namespace ATF_TEST_CASE_WITHOUT_HEAD(templates_def__add_variable__first); ATF_TEST_CASE_BODY(templates_def__add_variable__first) { text::templates_def templates; templates.add_variable("the-name", "first-value"); ATF_REQUIRE_EQ("first-value", templates.get_variable("the-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__add_variable__replace); ATF_TEST_CASE_BODY(templates_def__add_variable__replace) { text::templates_def templates; templates.add_variable("the-name", "first-value"); templates.add_variable("the-name", "second-value"); ATF_REQUIRE_EQ("second-value", templates.get_variable("the-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__remove_variable); ATF_TEST_CASE_BODY(templates_def__remove_variable) { text::templates_def templates; templates.add_variable("the-name", "the-value"); templates.get_variable("the-name"); // Should not throw. templates.remove_variable("the-name"); ATF_REQUIRE_THROW(text::syntax_error, templates.get_variable("the-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__add_vector__first); ATF_TEST_CASE_BODY(templates_def__add_vector__first) { text::templates_def templates; templates.add_vector("the-name"); ATF_REQUIRE(templates.get_vector("the-name").empty()); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__add_vector__replace); ATF_TEST_CASE_BODY(templates_def__add_vector__replace) { text::templates_def templates; templates.add_vector("the-name"); templates.add_to_vector("the-name", "foo"); ATF_REQUIRE(!templates.get_vector("the-name").empty()); templates.add_vector("the-name"); ATF_REQUIRE(templates.get_vector("the-name").empty()); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__add_to_vector); ATF_TEST_CASE_BODY(templates_def__add_to_vector) { text::templates_def templates; templates.add_vector("the-name"); ATF_REQUIRE_EQ(0, templates.get_vector("the-name").size()); templates.add_to_vector("the-name", "first"); ATF_REQUIRE_EQ(1, templates.get_vector("the-name").size()); templates.add_to_vector("the-name", "second"); ATF_REQUIRE_EQ(2, templates.get_vector("the-name").size()); templates.add_to_vector("the-name", "third"); ATF_REQUIRE_EQ(3, templates.get_vector("the-name").size()); std::vector< std::string > expected; expected.push_back("first"); expected.push_back("second"); expected.push_back("third"); ATF_REQUIRE(expected == templates.get_vector("the-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__exists__variable); ATF_TEST_CASE_BODY(templates_def__exists__variable) { text::templates_def templates; ATF_REQUIRE(!templates.exists("some-name")); templates.add_variable("some-name ", "foo"); ATF_REQUIRE(!templates.exists("some-name")); templates.add_variable("some-name", "foo"); ATF_REQUIRE(templates.exists("some-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__exists__vector); ATF_TEST_CASE_BODY(templates_def__exists__vector) { text::templates_def templates; ATF_REQUIRE(!templates.exists("some-name")); templates.add_vector("some-name "); ATF_REQUIRE(!templates.exists("some-name")); templates.add_vector("some-name"); ATF_REQUIRE(templates.exists("some-name")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__get_variable__ok); ATF_TEST_CASE_BODY(templates_def__get_variable__ok) { text::templates_def templates; templates.add_variable("foo", ""); templates.add_variable("bar", " baz "); ATF_REQUIRE_EQ("", templates.get_variable("foo")); ATF_REQUIRE_EQ(" baz ", templates.get_variable("bar")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__get_variable__unknown); ATF_TEST_CASE_BODY(templates_def__get_variable__unknown) { text::templates_def templates; templates.add_variable("foo", ""); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown variable 'foo '", templates.get_variable("foo ")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__get_vector__ok); ATF_TEST_CASE_BODY(templates_def__get_vector__ok) { text::templates_def templates; templates.add_vector("foo"); templates.add_vector("bar"); templates.add_to_vector("bar", "baz"); ATF_REQUIRE_EQ(0, templates.get_vector("foo").size()); ATF_REQUIRE_EQ(1, templates.get_vector("bar").size()); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__get_vector__unknown); ATF_TEST_CASE_BODY(templates_def__get_vector__unknown) { text::templates_def templates; templates.add_vector("foo"); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown vector 'foo '", templates.get_vector("foo ")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__variable__ok); ATF_TEST_CASE_BODY(templates_def__evaluate__variable__ok) { text::templates_def templates; templates.add_variable("foo", ""); templates.add_variable("bar", " baz "); ATF_REQUIRE_EQ("", templates.evaluate("foo")); ATF_REQUIRE_EQ(" baz ", templates.evaluate("bar")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__variable__unknown); ATF_TEST_CASE_BODY(templates_def__evaluate__variable__unknown) { text::templates_def templates; templates.add_variable("foo", ""); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown variable 'foo1'", templates.evaluate("foo1")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__vector__ok); ATF_TEST_CASE_BODY(templates_def__evaluate__vector__ok) { text::templates_def templates; templates.add_vector("v"); templates.add_to_vector("v", "foo"); templates.add_to_vector("v", "bar"); templates.add_to_vector("v", "baz"); templates.add_variable("index", "0"); ATF_REQUIRE_EQ("foo", templates.evaluate("v(index)")); templates.add_variable("index", "1"); ATF_REQUIRE_EQ("bar", templates.evaluate("v(index)")); templates.add_variable("index", "2"); ATF_REQUIRE_EQ("baz", templates.evaluate("v(index)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__vector__unknown_vector); ATF_TEST_CASE_BODY(templates_def__evaluate__vector__unknown_vector) { text::templates_def templates; templates.add_vector("v"); templates.add_to_vector("v", "foo"); templates.add_variable("index", "0"); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown vector 'fooz'", templates.evaluate("fooz(index)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__vector__unknown_index); ATF_TEST_CASE_BODY(templates_def__evaluate__vector__unknown_index) { text::templates_def templates; templates.add_vector("v"); templates.add_to_vector("v", "foo"); templates.add_variable("index", "0"); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown variable 'indexz'", templates.evaluate("v(indexz)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__vector__out_of_range); ATF_TEST_CASE_BODY(templates_def__evaluate__vector__out_of_range) { text::templates_def templates; templates.add_vector("v"); templates.add_to_vector("v", "foo"); templates.add_variable("index", "1"); ATF_REQUIRE_THROW_RE(text::syntax_error, "Index 'index' out of range " "at position '1'", templates.evaluate("v(index)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__defined); ATF_TEST_CASE_BODY(templates_def__evaluate__defined) { text::templates_def templates; templates.add_vector("the-variable"); templates.add_vector("the-vector"); ATF_REQUIRE_EQ("false", templates.evaluate("defined(the-variabl)")); ATF_REQUIRE_EQ("false", templates.evaluate("defined(the-vecto)")); ATF_REQUIRE_EQ("true", templates.evaluate("defined(the-variable)")); ATF_REQUIRE_EQ("true", templates.evaluate("defined(the-vector)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__length__ok); ATF_TEST_CASE_BODY(templates_def__evaluate__length__ok) { text::templates_def templates; templates.add_vector("v"); ATF_REQUIRE_EQ("0", templates.evaluate("length(v)")); templates.add_to_vector("v", "foo"); ATF_REQUIRE_EQ("1", templates.evaluate("length(v)")); templates.add_to_vector("v", "bar"); ATF_REQUIRE_EQ("2", templates.evaluate("length(v)")); templates.add_to_vector("v", "baz"); ATF_REQUIRE_EQ("3", templates.evaluate("length(v)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__length__unknown_vector); ATF_TEST_CASE_BODY(templates_def__evaluate__length__unknown_vector) { text::templates_def templates; templates.add_vector("foo1"); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unknown vector 'foo'", templates.evaluate("length(foo)")); } ATF_TEST_CASE_WITHOUT_HEAD(templates_def__evaluate__parenthesis_error); ATF_TEST_CASE_BODY(templates_def__evaluate__parenthesis_error) { text::templates_def templates; ATF_REQUIRE_THROW_RE(text::syntax_error, "Expected '\\)' in.*'foo\\(abc'", templates.evaluate("foo(abc")); ATF_REQUIRE_THROW_RE(text::syntax_error, "Unexpected text.*'\\)' in.*'a\\(b\\)c'", templates.evaluate("a(b)c")); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__empty_input); ATF_TEST_CASE_BODY(instantiate__empty_input) { const text::templates_def templates; do_test_ok(templates, "", ""); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__value__ok); ATF_TEST_CASE_BODY(instantiate__value__ok) { const std::string input = "first line\n" "%%testvar1%%\n" "third line\n" "%%testvar2%% %%testvar3%%%%testvar4%%\n" "fifth line\n"; const std::string exp_output = "first line\n" "second line\n" "third line\n" "fourth line.\n" "fifth line\n"; text::templates_def templates; templates.add_variable("testvar1", "second line"); templates.add_variable("testvar2", "fourth"); templates.add_variable("testvar3", "line"); templates.add_variable("testvar4", "."); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__value__unknown_variable); ATF_TEST_CASE_BODY(instantiate__value__unknown_variable) { const std::string input = "%%testvar1%%\n"; text::templates_def templates; templates.add_variable("testvar2", "fourth line"); do_test_fail(templates, input, "Unknown variable 'testvar1'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_length__ok); ATF_TEST_CASE_BODY(instantiate__vector_length__ok) { const std::string input = "%%length(testvector1)%%\n" "%%length(testvector2)%% - %%length(testvector3)%%\n"; const std::string exp_output = "4\n" "0 - 1\n"; text::templates_def templates; templates.add_vector("testvector1"); templates.add_to_vector("testvector1", "000"); templates.add_to_vector("testvector1", "111"); templates.add_to_vector("testvector1", "543"); templates.add_to_vector("testvector1", "999"); templates.add_vector("testvector2"); templates.add_vector("testvector3"); templates.add_to_vector("testvector3", "123"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_length__unknown_vector); ATF_TEST_CASE_BODY(instantiate__vector_length__unknown_vector) { const std::string input = "%%length(testvector)%%\n"; text::templates_def templates; templates.add_vector("testvector2"); do_test_fail(templates, input, "Unknown vector 'testvector'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_value__ok); ATF_TEST_CASE_BODY(instantiate__vector_value__ok) { const std::string input = "first line\n" "%%testvector1(i)%%\n" "third line\n" "%%testvector2(j)%%\n" "fifth line\n"; const std::string exp_output = "first line\n" "543\n" "third line\n" "123\n" "fifth line\n"; text::templates_def templates; templates.add_variable("i", "2"); templates.add_variable("j", "0"); templates.add_vector("testvector1"); templates.add_to_vector("testvector1", "000"); templates.add_to_vector("testvector1", "111"); templates.add_to_vector("testvector1", "543"); templates.add_to_vector("testvector1", "999"); templates.add_vector("testvector2"); templates.add_to_vector("testvector2", "123"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_value__unknown_vector); ATF_TEST_CASE_BODY(instantiate__vector_value__unknown_vector) { const std::string input = "%%testvector(j)%%\n"; text::templates_def templates; templates.add_vector("testvector2"); do_test_fail(templates, input, "Unknown vector 'testvector'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_value__out_of_range__empty); ATF_TEST_CASE_BODY(instantiate__vector_value__out_of_range__empty) { const std::string input = "%%testvector(j)%%\n"; text::templates_def templates; templates.add_vector("testvector"); templates.add_variable("j", "0"); do_test_fail(templates, input, "Index 'j' out of range at position '0'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__vector_value__out_of_range__not_empty); ATF_TEST_CASE_BODY(instantiate__vector_value__out_of_range__not_empty) { const std::string input = "%%testvector(j)%%\n"; text::templates_def templates; templates.add_vector("testvector"); templates.add_to_vector("testvector", "a"); templates.add_to_vector("testvector", "b"); templates.add_variable("j", "2"); do_test_fail(templates, input, "Index 'j' out of range at position '2'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__if__one_level__taken); ATF_TEST_CASE_BODY(instantiate__if__one_level__taken) { const std::string input = "first line\n" "%if defined(some_var)\n" "hello from within the variable conditional\n" "%endif\n" "%if defined(some_vector)\n" "hello from within the vector conditional\n" "%else\n" "bye from within the vector conditional\n" "%endif\n" "some more\n"; const std::string exp_output = "first line\n" "hello from within the variable conditional\n" "hello from within the vector conditional\n" "some more\n"; text::templates_def templates; templates.add_variable("some_var", "zzz"); templates.add_vector("some_vector"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__if__one_level__not_taken); ATF_TEST_CASE_BODY(instantiate__if__one_level__not_taken) { const std::string input = "first line\n" "%if defined(some_var)\n" "hello from within the variable conditional\n" "%endif\n" "%if defined(some_vector)\n" "hello from within the vector conditional\n" "%else\n" "bye from within the vector conditional\n" "%endif\n" "some more\n"; const std::string exp_output = "first line\n" "bye from within the vector conditional\n" "some more\n"; text::templates_def templates; do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__if__multiple_levels__taken); ATF_TEST_CASE_BODY(instantiate__if__multiple_levels__taken) { const std::string input = "first line\n" "%if defined(var1)\n" "first before\n" "%if length(var2)\n" "second before\n" "%if defined(var3)\n" "third before\n" "hello from within the conditional\n" "third after\n" "%endif\n" "second after\n" "%else\n" "second after not shown\n" "%endif\n" "first after\n" "%endif\n" "some more\n"; const std::string exp_output = "first line\n" "first before\n" "second before\n" "third before\n" "hello from within the conditional\n" "third after\n" "second after\n" "first after\n" "some more\n"; text::templates_def templates; templates.add_variable("var1", "false"); templates.add_vector("var2"); templates.add_to_vector("var2", "not-empty"); templates.add_variable("var3", "foobar"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__if__multiple_levels__not_taken); ATF_TEST_CASE_BODY(instantiate__if__multiple_levels__not_taken) { const std::string input = "first line\n" "%if defined(var1)\n" "first before\n" "%if length(var2)\n" "second before\n" "%if defined(var3)\n" "third before\n" "hello from within the conditional\n" "third after\n" "%else\n" "will not be shown either\n" "%endif\n" "second after\n" "%else\n" "second after shown\n" "%endif\n" "first after\n" "%endif\n" "some more\n"; const std::string exp_output = "first line\n" "first before\n" "second after shown\n" "first after\n" "some more\n"; text::templates_def templates; templates.add_variable("var1", "false"); templates.add_vector("var2"); templates.add_vector("var3"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__no_iterations); ATF_TEST_CASE_BODY(instantiate__loop__no_iterations) { const std::string input = "first line\n" "%loop table1 i\n" "hello\n" "value in vector: %%table1(i)%%\n" "%if defined(var1)\n" "some other text\n" "%endif\n" "%endloop\n" "some more\n"; const std::string exp_output = "first line\n" "some more\n"; text::templates_def templates; templates.add_variable("var1", "defined"); templates.add_vector("table1"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__multiple_iterations); ATF_TEST_CASE_BODY(instantiate__loop__multiple_iterations) { const std::string input = "first line\n" "%loop table1 i\n" "hello %%table1(i)%% %%table2(i)%%\n" "%endloop\n" "some more\n"; const std::string exp_output = "first line\n" "hello foo1 foo2\n" "hello bar1 bar2\n" "some more\n"; text::templates_def templates; templates.add_vector("table1"); templates.add_to_vector("table1", "foo1"); templates.add_to_vector("table1", "bar1"); templates.add_vector("table2"); templates.add_to_vector("table2", "foo2"); templates.add_to_vector("table2", "bar2"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__nested__no_iterations); ATF_TEST_CASE_BODY(instantiate__loop__nested__no_iterations) { const std::string input = "first line\n" "%loop table1 i\n" "before: %%table1(i)%%\n" "%loop table2 j\n" "before: %%table2(j)%%\n" "%loop table3 k\n" "%%table3(k)%%\n" "%endloop\n" "after: %%table2(i)%%\n" "%endloop\n" "after: %%table1(i)%%\n" "%endloop\n" "some more\n"; const std::string exp_output = "first line\n" "before: a\n" "after: a\n" "before: b\n" "after: b\n" "some more\n"; text::templates_def templates; templates.add_vector("table1"); templates.add_to_vector("table1", "a"); templates.add_to_vector("table1", "b"); templates.add_vector("table2"); templates.add_vector("table3"); templates.add_to_vector("table3", "1"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__nested__multiple_iterations); ATF_TEST_CASE_BODY(instantiate__loop__nested__multiple_iterations) { const std::string input = "first line\n" "%loop table1 i\n" "%loop table2 j\n" "%%table1(i)%% %%table2(j)%%\n" "%endloop\n" "%endloop\n" "some more\n"; const std::string exp_output = "first line\n" "a 1\n" "a 2\n" "a 3\n" "b 1\n" "b 2\n" "b 3\n" "some more\n"; text::templates_def templates; templates.add_vector("table1"); templates.add_to_vector("table1", "a"); templates.add_to_vector("table1", "b"); templates.add_vector("table2"); templates.add_to_vector("table2", "1"); templates.add_to_vector("table2", "2"); templates.add_to_vector("table2", "3"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__sequential); ATF_TEST_CASE_BODY(instantiate__loop__sequential) { const std::string input = "first line\n" "%loop table1 iter\n" "1: %%table1(iter)%%\n" "%endloop\n" "divider\n" "%loop table2 iter\n" "2: %%table2(iter)%%\n" "%endloop\n" "divider\n" "%loop table3 iter\n" "3: %%table3(iter)%%\n" "%endloop\n" "divider\n" "%loop table4 iter\n" "4: %%table4(iter)%%\n" "%endloop\n" "some more\n"; const std::string exp_output = "first line\n" "1: a\n" "1: b\n" "divider\n" "divider\n" "divider\n" "4: 1\n" "4: 2\n" "4: 3\n" "some more\n"; text::templates_def templates; templates.add_vector("table1"); templates.add_to_vector("table1", "a"); templates.add_to_vector("table1", "b"); templates.add_vector("table2"); templates.add_vector("table3"); templates.add_vector("table4"); templates.add_to_vector("table4", "1"); templates.add_to_vector("table4", "2"); templates.add_to_vector("table4", "3"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__loop__scoping); ATF_TEST_CASE_BODY(instantiate__loop__scoping) { const std::string input = "%loop table1 i\n" "%if defined(i)\n" "i defined inside scope 1\n" "%endif\n" "%loop table2 j\n" "%if defined(i)\n" "i defined inside scope 2\n" "%endif\n" "%if defined(j)\n" "j defined inside scope 2\n" "%endif\n" "%endloop\n" "%if defined(j)\n" "j defined inside scope 1\n" "%endif\n" "%endloop\n" "%if defined(i)\n" "i defined outside\n" "%endif\n" "%if defined(j)\n" "j defined outside\n" "%endif\n"; const std::string exp_output = "i defined inside scope 1\n" "i defined inside scope 2\n" "j defined inside scope 2\n" "i defined inside scope 1\n" "i defined inside scope 2\n" "j defined inside scope 2\n"; text::templates_def templates; templates.add_vector("table1"); templates.add_to_vector("table1", "first"); templates.add_to_vector("table1", "second"); templates.add_vector("table2"); templates.add_to_vector("table2", "first"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__mismatched_delimiters); ATF_TEST_CASE_BODY(instantiate__mismatched_delimiters) { const std::string input = "this is some %% text\n" "and this is %%var%% text%%\n"; const std::string exp_output = "this is some %% text\n" "and this is some more text%%\n"; text::templates_def templates; templates.add_variable("var", "some more"); do_test_ok(templates, input, exp_output); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__empty_statement); ATF_TEST_CASE_BODY(instantiate__empty_statement) { do_test_fail(text::templates_def(), "%\n", "Empty statement"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__unknown_statement); ATF_TEST_CASE_BODY(instantiate__unknown_statement) { do_test_fail(text::templates_def(), "%if2\n", "Unknown statement 'if2'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__invalid_narguments); ATF_TEST_CASE_BODY(instantiate__invalid_narguments) { do_test_fail(text::templates_def(), "%if a b\n", "Invalid number of arguments for statement 'if'"); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__files__ok); ATF_TEST_CASE_BODY(instantiate__files__ok) { text::templates_def templates; templates.add_variable("string", "Hello, world!"); atf::utils::create_file("input.txt", "The string is: %%string%%\n"); text::instantiate(templates, fs::path("input.txt"), fs::path("output.txt")); std::ifstream output("output.txt"); std::string line; ATF_REQUIRE(std::getline(output, line).good()); ATF_REQUIRE_EQ(line, "The string is: Hello, world!"); ATF_REQUIRE(std::getline(output, line).eof()); } ATF_TEST_CASE_WITHOUT_HEAD(instantiate__files__input_error); ATF_TEST_CASE_BODY(instantiate__files__input_error) { text::templates_def templates; ATF_REQUIRE_THROW_RE(text::error, "Failed to open input.txt for read", text::instantiate(templates, fs::path("input.txt"), fs::path("output.txt"))); } ATF_TEST_CASE(instantiate__files__output_error); ATF_TEST_CASE_HEAD(instantiate__files__output_error) { set_md_var("require.user", "unprivileged"); } ATF_TEST_CASE_BODY(instantiate__files__output_error) { text::templates_def templates; atf::utils::create_file("input.txt", ""); fs::mkdir(fs::path("dir"), 0444); ATF_REQUIRE_THROW_RE(text::error, "Failed to open dir/output.txt for write", text::instantiate(templates, fs::path("input.txt"), fs::path("dir/output.txt"))); } ATF_INIT_TEST_CASES(tcs) { ATF_ADD_TEST_CASE(tcs, templates_def__add_variable__first); ATF_ADD_TEST_CASE(tcs, templates_def__add_variable__replace); ATF_ADD_TEST_CASE(tcs, templates_def__remove_variable); ATF_ADD_TEST_CASE(tcs, templates_def__add_vector__first); ATF_ADD_TEST_CASE(tcs, templates_def__add_vector__replace); ATF_ADD_TEST_CASE(tcs, templates_def__add_to_vector); ATF_ADD_TEST_CASE(tcs, templates_def__exists__variable); ATF_ADD_TEST_CASE(tcs, templates_def__exists__vector); ATF_ADD_TEST_CASE(tcs, templates_def__get_variable__ok); ATF_ADD_TEST_CASE(tcs, templates_def__get_variable__unknown); ATF_ADD_TEST_CASE(tcs, templates_def__get_vector__ok); ATF_ADD_TEST_CASE(tcs, templates_def__get_vector__unknown); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__variable__ok); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__variable__unknown); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__vector__ok); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__vector__unknown_vector); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__vector__unknown_index); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__vector__out_of_range); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__defined); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__length__ok); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__length__unknown_vector); ATF_ADD_TEST_CASE(tcs, templates_def__evaluate__parenthesis_error); ATF_ADD_TEST_CASE(tcs, instantiate__empty_input); ATF_ADD_TEST_CASE(tcs, instantiate__value__ok); ATF_ADD_TEST_CASE(tcs, instantiate__value__unknown_variable); ATF_ADD_TEST_CASE(tcs, instantiate__vector_length__ok); ATF_ADD_TEST_CASE(tcs, instantiate__vector_length__unknown_vector); ATF_ADD_TEST_CASE(tcs, instantiate__vector_value__ok); ATF_ADD_TEST_CASE(tcs, instantiate__vector_value__unknown_vector); ATF_ADD_TEST_CASE(tcs, instantiate__vector_value__out_of_range__empty); ATF_ADD_TEST_CASE(tcs, instantiate__vector_value__out_of_range__not_empty); ATF_ADD_TEST_CASE(tcs, instantiate__if__one_level__taken); ATF_ADD_TEST_CASE(tcs, instantiate__if__one_level__not_taken); ATF_ADD_TEST_CASE(tcs, instantiate__if__multiple_levels__taken); ATF_ADD_TEST_CASE(tcs, instantiate__if__multiple_levels__not_taken); ATF_ADD_TEST_CASE(tcs, instantiate__loop__no_iterations); ATF_ADD_TEST_CASE(tcs, instantiate__loop__multiple_iterations); ATF_ADD_TEST_CASE(tcs, instantiate__loop__nested__no_iterations); ATF_ADD_TEST_CASE(tcs, instantiate__loop__nested__multiple_iterations); ATF_ADD_TEST_CASE(tcs, instantiate__loop__sequential); ATF_ADD_TEST_CASE(tcs, instantiate__loop__scoping); ATF_ADD_TEST_CASE(tcs, instantiate__mismatched_delimiters); ATF_ADD_TEST_CASE(tcs, instantiate__empty_statement); ATF_ADD_TEST_CASE(tcs, instantiate__unknown_statement); ATF_ADD_TEST_CASE(tcs, instantiate__invalid_narguments); ATF_ADD_TEST_CASE(tcs, instantiate__files__ok); ATF_ADD_TEST_CASE(tcs, instantiate__files__input_error); ATF_ADD_TEST_CASE(tcs, instantiate__files__output_error); }