// Copyright 2012 Google Inc.
// 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);
}