1002 lines
32 KiB
C++
1002 lines
32 KiB
C++
|
// 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);
|
||
|
}
|