freebsd-dev/contrib/kyua/utils/text/templates_test.cpp
Brooks Davis b0d29bc47d Import the kyua test framework.
Having kyua in the base system will simplify automated testing in CI and
eliminates bootstrapping issues on new platforms.

The build of kyua is controlled by WITH(OUT)_TESTS_SUPPORT.

Reviewed by:	emaste
Obtained from:	CheriBSD
Sponsored by:	DARPA
Differential Revision:	https://reviews.freebsd.org/D24103
2020-03-23 19:01:23 +00:00

1002 lines
32 KiB
C++

// 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);
}