diff options
Diffstat (limited to 'utils/text/templates_test.cpp')
-rw-r--r-- | utils/text/templates_test.cpp | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/utils/text/templates_test.cpp b/utils/text/templates_test.cpp new file mode 100644 index 000000000000..4524dc61a416 --- /dev/null +++ b/utils/text/templates_test.cpp @@ -0,0 +1,1001 @@ +// 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); +} |