mirror of
https://github.com/pantor/inja.git
synced 2026-04-15 12:38:53 +00:00
Inja v2 (#67)
* inja2 * header only * reduce dependencies * code cleaning * c++17 * use stdc++ * code cleaning * infrastructure * header only * add infrastructure * fix tests * use minimum clang 6 * code cleaning, polyfill for c++11 * fix some file tests * fix readme * update appveyor * fix polyfill and ci * fix polyfill * fix ci? * test msvc __cplusplus * add doxygen * activate all tests * code cleaning * add coveralls, set default to dot notation * add html test * add doxygen comments * test single_include file * change build folder in appveyor * correct make arguments in appveyor * fix appveyor arguments
This commit is contained in:
@@ -1,92 +0,0 @@
|
||||
##
|
||||
## HUNTER
|
||||
##
|
||||
option(HUNTER_ENABLED "Use hunter to manage dependencies" OFF)
|
||||
if(HUNTER_ENABLED)
|
||||
include("../cmake/HunterGate.cmake")
|
||||
HunterGate(
|
||||
URL "https://github.com/ruslo/hunter/archive/v0.19.156.tar.gz"
|
||||
SHA1 "8d5e4635b137365e0d1ade4d60accf4e2bb41f0d"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
##
|
||||
## TESTS
|
||||
##
|
||||
add_executable(inja_test
|
||||
src/unit-files.cpp
|
||||
src/unit-renderer.cpp
|
||||
src/unit-string-helper.cpp
|
||||
src/unit.cpp
|
||||
)
|
||||
|
||||
add_executable(inja_single_test
|
||||
src/unit-files.cpp
|
||||
src/unit-renderer.cpp
|
||||
src/unit-string-helper.cpp
|
||||
src/unit.cpp
|
||||
)
|
||||
|
||||
|
||||
if(HUNTER_ENABLED) # Use Hunter to manage dependencies
|
||||
# Add Catch framework
|
||||
hunter_add_package(Catch)
|
||||
find_package(Catch CONFIG REQUIRED)
|
||||
|
||||
# Add JSON package
|
||||
hunter_add_package(nlohmann_json)
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
|
||||
# Add dependencies to target
|
||||
target_link_libraries(inja_test Catch::Catch nlohmann_json inja)
|
||||
else() # Manage dependencies manually
|
||||
# Prepare "Catch" library for other executables
|
||||
add_library(Catch INTERFACE)
|
||||
target_include_directories(Catch INTERFACE "src/catch")
|
||||
|
||||
# Prepare "hayai" library for other executables
|
||||
add_library(hayai INTERFACE)
|
||||
target_include_directories(hayai INTERFACE "src/hayai")
|
||||
|
||||
# Add dependencies to targets
|
||||
target_link_libraries(inja_test Catch inja)
|
||||
target_link_libraries(inja_single_test Catch inja_single)
|
||||
endif()
|
||||
|
||||
|
||||
##
|
||||
## BENCHMARK
|
||||
##
|
||||
if(BUILD_BENCHMARK)
|
||||
add_executable(inja_benchmark
|
||||
src/benchmark.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(inja_benchmark hayai inja)
|
||||
endif()
|
||||
|
||||
|
||||
##
|
||||
## Copy test files to build directory
|
||||
##
|
||||
add_custom_command(
|
||||
TARGET inja_test POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/data
|
||||
${CMAKE_CURRENT_BINARY_DIR}/data
|
||||
)
|
||||
|
||||
|
||||
##
|
||||
## Add tests to make
|
||||
##
|
||||
add_test(NAME inja_test
|
||||
COMMAND inja_test
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_test(NAME inja_single_test
|
||||
COMMAND inja_single_test
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "hayai/hayai.hpp"
|
||||
#include "inja.hpp"
|
||||
#include <inja/inja.hpp>
|
||||
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
|
||||
json data = {{"name", "Peter"}};
|
||||
|
||||
11
test/data/html/data.json
Normal file
11
test/data/html/data.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"author": "Pantor",
|
||||
"date": "23/12/2018",
|
||||
"tags": [
|
||||
"test",
|
||||
"templates"
|
||||
],
|
||||
"views": 123,
|
||||
"title": "Inja works.",
|
||||
"content": "Inja is the best and fastest template engine for C++. Period."
|
||||
}
|
||||
19
test/data/html/result.txt
Normal file
19
test/data/html/result.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Inja works.</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Inja works.</h1>
|
||||
<small>Written by Pantor</small>
|
||||
|
||||
<p>Inja is the best and fastest template engine for C++. Period.</p>
|
||||
<small>123 views</small>
|
||||
|
||||
<h5>Tags</h5>
|
||||
<ul>
|
||||
<li>test</li>
|
||||
<li>templates</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
20
test/data/html/template.txt
Normal file
20
test/data/html/template.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ title }}</h1>
|
||||
<small>Written by {{ author }}</small>
|
||||
|
||||
<p>{{ content }}</p>
|
||||
<small>{{ views }} views</small>
|
||||
|
||||
<h5>Tags</h5>
|
||||
<ul>
|
||||
## for tag in tags
|
||||
<li>{{ tag }}</li>
|
||||
## endfor
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
0
test/data/include.txt
Normal file → Executable file
0
test/data/include.txt
Normal file → Executable file
0
test/data/nested-line/data.json
Normal file → Executable file
0
test/data/nested-line/data.json
Normal file → Executable file
0
test/data/nested-line/result.txt
Normal file → Executable file
0
test/data/nested-line/result.txt
Normal file → Executable file
1
test/data/nested-line/template.txt
Normal file → Executable file
1
test/data/nested-line/template.txt
Normal file → Executable file
@@ -1,6 +1,5 @@
|
||||
## for x in xarray
|
||||
## for y in yarray
|
||||
{{x}}-{{y}}
|
||||
|
||||
## endfor
|
||||
## endfor
|
||||
|
||||
0
test/data/nested/data.json
Normal file → Executable file
0
test/data/nested/data.json
Normal file → Executable file
0
test/data/nested/result.txt
Normal file → Executable file
0
test/data/nested/result.txt
Normal file → Executable file
0
test/data/nested/template.txt
Normal file → Executable file
0
test/data/nested/template.txt
Normal file → Executable file
0
test/data/simple-file/data.json
Normal file → Executable file
0
test/data/simple-file/data.json
Normal file → Executable file
0
test/data/simple-file/result.txt
Normal file → Executable file
0
test/data/simple-file/result.txt
Normal file → Executable file
0
test/data/simple-file/template.txt
Normal file → Executable file
0
test/data/simple-file/template.txt
Normal file → Executable file
0
test/data/simple.txt
Normal file → Executable file
0
test/data/simple.txt
Normal file → Executable file
@@ -256,7 +256,7 @@ namespace hayai
|
||||
# elif defined(CLOCK_REALTIME)
|
||||
clock_gettime(CLOCK_REALTIME, &result);
|
||||
# else
|
||||
clock_gettime((clockid_t)-1, &result);
|
||||
clock_gettime((clocId_t)-1, &result);
|
||||
# endif
|
||||
return result;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
unit_test = executable(
|
||||
'inja-test',
|
||||
'src/unit.cpp',
|
||||
'src/unit-files.cpp',
|
||||
'src/unit-renderer.cpp',
|
||||
'src/unit-string-helper.cpp',
|
||||
dependencies: inja_dep
|
||||
)
|
||||
|
||||
unit_single_test = executable(
|
||||
'inja-single-test',
|
||||
'src/unit.cpp',
|
||||
'src/unit-files.cpp',
|
||||
'src/unit-renderer.cpp',
|
||||
'src/unit-string-helper.cpp',
|
||||
dependencies: inja_single_dep
|
||||
)
|
||||
|
||||
inja_benchmark = executable(
|
||||
'inja_benchmark',
|
||||
'src/benchmark.cpp',
|
||||
dependencies: inja_dep
|
||||
)
|
||||
|
||||
test('Inja unit test', unit_test)
|
||||
test('Inja single unit test', unit_single_test)
|
||||
@@ -1,164 +0,0 @@
|
||||
#include "catch/catch.hpp"
|
||||
#include "inja.hpp"
|
||||
|
||||
|
||||
TEST_CASE("dot to pointer") {
|
||||
CHECK( inja::Parser::dot_to_json_pointer_notation("person.names.surname") == "/person/names/surname" );
|
||||
CHECK( inja::Parser::dot_to_json_pointer_notation("guests.2") == "/guests/2" );
|
||||
}
|
||||
|
||||
TEST_CASE("basic-search") {
|
||||
std::string input = "lorem ipsum dolor it";
|
||||
inja::Regex regex("i(.*)m");
|
||||
|
||||
SECTION("from start") {
|
||||
inja::Match match = inja::search(input, regex, 0);
|
||||
CHECK( match.found() == true );
|
||||
CHECK( match.position() == 6 );
|
||||
CHECK( match.length() == 5 );
|
||||
CHECK( match.end_position() == 11 );
|
||||
CHECK( match.str() == "ipsum" );
|
||||
CHECK( match.str(1) == "psu" );
|
||||
}
|
||||
|
||||
SECTION("from position") {
|
||||
inja::Match match = inja::search(input, regex, 8);
|
||||
CHECK( match.found() == false );
|
||||
CHECK( match.length() == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("search-multiple-regexes") {
|
||||
std::string input = "lorem ipsum dolor amit estas tronum.";
|
||||
|
||||
SECTION("basic 1") {
|
||||
std::map<int, inja::Regex> regex_patterns = {
|
||||
{0, inja::Regex("tras")},
|
||||
{1, inja::Regex("do(\\w*)or")},
|
||||
{2, inja::Regex("es(\\w*)as")},
|
||||
{3, inja::Regex("ip(\\w*)um")}
|
||||
};
|
||||
inja::MatchType<int> match = inja::search(input, regex_patterns, 0);
|
||||
CHECK( match.type() == 3 );
|
||||
CHECK( match.str() == "ipsum" );
|
||||
CHECK( match.str(1) == "s" );
|
||||
}
|
||||
|
||||
SECTION("basic 2") {
|
||||
std::map<int, inja::Regex> regex_patterns = {
|
||||
{11, inja::Regex("tras")},
|
||||
{21, inja::Regex("ip(\\w*)um")},
|
||||
{31, inja::Regex("do(\\w*)or")},
|
||||
{41, inja::Regex("es(\\w*)as")}
|
||||
};
|
||||
inja::MatchType<int> match = inja::search(input, regex_patterns, 0);
|
||||
CHECK( match.type() == 21 );
|
||||
CHECK( match.str() == "ipsum" );
|
||||
CHECK( match.str(1) == "s" );
|
||||
}
|
||||
|
||||
SECTION("basic 3") {
|
||||
auto map_functions = inja::Parser().regex_map_functions;
|
||||
std::map<int, inja::Regex> regex_patterns = {
|
||||
{0, map_functions.at(inja::Parsed::Function::Upper)},
|
||||
{1, map_functions.at(inja::Parsed::Function::Lower)},
|
||||
{2, map_functions.at(inja::Parsed::Function::ReadJson)}
|
||||
};
|
||||
|
||||
const std::string input_1 = "upper(name)";
|
||||
inja::MatchType<int> match = inja::search(input_1, regex_patterns, 0);
|
||||
CHECK( match.type() == 0 );
|
||||
CHECK( match.str(0) == "upper(name)" );
|
||||
CHECK( match.str(1) == "name" );
|
||||
|
||||
const std::string input_2 = "upper(lower(name))";
|
||||
inja::MatchType<int> match2 = inja::search(input_2, regex_patterns, 0);
|
||||
CHECK( match2.type() == 0 );
|
||||
CHECK( match2.str(0) == "upper(lower(name))" );
|
||||
CHECK( match2.str(1) == "lower(name)" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("match-multiple-regexes") {
|
||||
std::string input = "ipsum";
|
||||
|
||||
SECTION("basic 1") {
|
||||
std::map<int, inja::Regex> regex_patterns = {
|
||||
{1, inja::Regex("tras")},
|
||||
{2, inja::Regex("ip(\\w*)um")},
|
||||
{3, inja::Regex("do(\\w*)or")},
|
||||
{4, inja::Regex("es(\\w*)as")}
|
||||
};
|
||||
inja::MatchType<int> match = inja::match(input, regex_patterns);
|
||||
CHECK( match.type() == 2 );
|
||||
CHECK( match.str() == "ipsum" );
|
||||
CHECK( match.str(1) == "s" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("search-on-level") {
|
||||
std::string input = "(% up %)(% up %)Test(% N1 %)(% down %)...(% up %)(% N2 %)(% up %)(% N3 %)(% down %)(% N4 %)(% down %)(% N5 %)(% down %)";
|
||||
|
||||
inja::Regex regex_statement("\\(\\% (.*?) \\%\\)");
|
||||
inja::Regex regex_level_up("up");
|
||||
inja::Regex regex_level_down("down");
|
||||
inja::Regex regex_search("N(\\d+)");
|
||||
|
||||
SECTION("first instance") {
|
||||
inja::Match open_match = inja::search(input, regex_statement, 0);
|
||||
CHECK( open_match.position() == 0 );
|
||||
CHECK( open_match.end_position() == 8 );
|
||||
CHECK( open_match.str(1) == "up" );
|
||||
|
||||
inja::MatchClosed match = inja::search_closed_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match);
|
||||
CHECK( match.position() == 0 );
|
||||
CHECK( match.end_position() == 109 );
|
||||
}
|
||||
|
||||
SECTION("second instance") {
|
||||
inja::Match open_match = inja::search(input, regex_statement, 4);
|
||||
|
||||
CHECK( open_match.position() == 8 );
|
||||
CHECK( open_match.end_position() == 16 );
|
||||
CHECK( open_match.str(1) == "up" );
|
||||
|
||||
inja::MatchClosed match = inja::search_closed_on_level(input, regex_statement, regex_level_up, regex_level_down, regex_search, open_match);
|
||||
|
||||
CHECK( match.open_match.position() == 8 );
|
||||
CHECK( match.open_match.end_position() == 16 );
|
||||
CHECK( match.close_match.position() == 20 );
|
||||
CHECK( match.close_match.end_position() == 28 );
|
||||
CHECK( match.position() == 8 );
|
||||
CHECK( match.end_position() == 28 );
|
||||
CHECK( match.outer() == "(% up %)Test(% N1 %)" );
|
||||
CHECK( match.inner() == "Test" );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("match-functions") {
|
||||
auto map_regex = inja::Parser().regex_map_functions;
|
||||
|
||||
CHECK( inja::match("not test", map_regex).type() == inja::Parsed::Function::Not );
|
||||
CHECK( inja::match("not test", map_regex).type() != inja::Parsed::Function::And );
|
||||
CHECK( inja::match("2 == 3", map_regex).type() == inja::Parsed::Function::Equal );
|
||||
CHECK( inja::match("test and test", map_regex).type() == inja::Parsed::Function::And );
|
||||
CHECK( inja::match("test and test", map_regex).type() != inja::Parsed::Function::ReadJson );
|
||||
CHECK( inja::match("test", map_regex).type() == inja::Parsed::Function::ReadJson );
|
||||
CHECK( inja::match("upper", map_regex).type() == inja::Parsed::Function::ReadJson );
|
||||
CHECK( inja::match("upper()", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match("upper(var)", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match("upper( var )", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match("upper(lower())", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match("upper( lower() )", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match(" upper(lower()) ", map_regex).type() == inja::Parsed::Function::Upper );
|
||||
CHECK( inja::match("lower(upper(test))", map_regex).type() == inja::Parsed::Function::Lower );
|
||||
CHECK( inja::match("round(2, 3)", map_regex).type() == inja::Parsed::Function::Round );
|
||||
CHECK( inja::match("exists(\"var\")", map_regex).type() == inja::Parsed::Function::Exists );
|
||||
CHECK( inja::match("existsIn(var, \"othervar\")", map_regex).type() == inja::Parsed::Function::ExistsInObject );
|
||||
}
|
||||
|
||||
TEST_CASE("create-regex-functions") {
|
||||
CHECK( inja::Parser::function_regex("upper", 1).pattern() == "\\s*upper(?:\\((.*)\\))\\s*" );
|
||||
CHECK( inja::Parser::function_regex("upper", 0).pattern() == "\\s*upper(?:\\(\\))?\\s*" );
|
||||
CHECK( inja::Parser::function_regex("lower", 2).pattern() == "\\s*lower(?:\\((.*),(.*)\\))\\s*" );
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "catch/catch.hpp"
|
||||
#include "inja.hpp"
|
||||
#include "inja/inja.hpp"
|
||||
|
||||
|
||||
using json = nlohmann::json;
|
||||
@@ -11,7 +11,7 @@ TEST_CASE("loading") {
|
||||
data["name"] = "Jeff";
|
||||
|
||||
SECTION("Files should be loaded") {
|
||||
CHECK( env.load_global_file("../test/data/simple.txt") == "Hello {{ name }}." );
|
||||
CHECK( env.load_file("../test/data/simple.txt") == "Hello {{ name }}." );
|
||||
}
|
||||
|
||||
SECTION("Files should be rendered") {
|
||||
@@ -26,9 +26,9 @@ TEST_CASE("loading") {
|
||||
TEST_CASE("complete-files") {
|
||||
inja::Environment env = inja::Environment("../test/data/");
|
||||
|
||||
for (std::string test_name : {"simple-file", "nested", "nested-line"}) {
|
||||
for (std::string test_name : {"simple-file", "nested", "nested-line", "html"}) {
|
||||
SECTION(test_name) {
|
||||
CHECK( env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_global_file(test_name + "/result.txt") );
|
||||
CHECK( env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_file(test_name + "/result.txt") );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,6 @@ TEST_CASE("global-path") {
|
||||
|
||||
SECTION("Files should be written") {
|
||||
env.write("simple.txt", data, "global-path-result.txt");
|
||||
CHECK( env_result.load_global_file("global-path-result.txt") == "Hello Jeff." );
|
||||
CHECK( env_result.load_file("global-path-result.txt") == "Hello Jeff." );
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
#include "catch/catch.hpp"
|
||||
#include "inja.hpp"
|
||||
#include "inja/inja.hpp"
|
||||
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
TEST_CASE("dot-to-pointer") {
|
||||
std::string buffer;
|
||||
CHECK( inja::convert_dot_to_json_pointer("person.names.surname", buffer) == "/person/names/surname" );
|
||||
CHECK( inja::convert_dot_to_json_pointer("guests.2", buffer) == "/guests/2" );
|
||||
}
|
||||
|
||||
TEST_CASE("types") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
json data;
|
||||
data["name"] = "Peter";
|
||||
data["city"] = "Brunswick";
|
||||
@@ -34,11 +40,11 @@ TEST_CASE("types") {
|
||||
CHECK( env.render("{{name}}", data) == "Peter" );
|
||||
CHECK( env.render("{{ name }} is {{ age }} years old.", data) == "Peter is 29 years old." );
|
||||
CHECK( env.render("Hello {{ name }}! I come from {{ city }}.", data) == "Hello Peter! I come from Brunswick." );
|
||||
CHECK( env.render("Hello {{ names/1 }}!", data) == "Hello Seb!" );
|
||||
CHECK( env.render("Hello {{ brother/name }}!", data) == "Hello Chris!" );
|
||||
CHECK( env.render("Hello {{ brother/daughter0/name }}!", data) == "Hello Maria!" );
|
||||
CHECK( env.render("Hello {{ names.1 }}!", data) == "Hello Seb!" );
|
||||
CHECK( env.render("Hello {{ brother.name }}!", data) == "Hello Chris!" );
|
||||
CHECK( env.render("Hello {{ brother.daughter0.name }}!", data) == "Hello Maria!" );
|
||||
|
||||
CHECK_THROWS_WITH( env.render("{{unknown}}", data), "[inja.exception.render_error] variable '/unknown' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{unknown}}", data), "[inja.exception.render_error] variable 'unknown' not found" );
|
||||
}
|
||||
|
||||
SECTION("comments") {
|
||||
@@ -49,17 +55,17 @@ TEST_CASE("types") {
|
||||
SECTION("loops") {
|
||||
CHECK( env.render("{% for name in names %}a{% endfor %}", data) == "aa" );
|
||||
CHECK( env.render("Hello {% for name in names %}{{ name }} {% endfor %}!", data) == "Hello Jeff Seb !" );
|
||||
CHECK( env.render("Hello {% for name in names %}{{ loop/index }}: {{ name }}, {% endfor %}!", data) == "Hello 0: Jeff, 1: Seb, !" );
|
||||
CHECK( env.render("Hello {% for name in names %}{{ loop.index }}: {{ name }}, {% endfor %}!", data) == "Hello 0: Jeff, 1: Seb, !" );
|
||||
CHECK( env.render("{% for type, name in relatives %}{{ type }}: {{ name }}, {% endfor %}", data) == "brother: Chris, mother: Maria, sister: Jenny, " );
|
||||
CHECK( env.render("{% for v in vars %}{% if v > 0 %}+{% endif %}{% endfor %}", data) == "+++" );
|
||||
CHECK( env.render("{% for name in names %}{{ loop/index }}: {{ name }}{% if not loop/is_last %}, {% endif %}{% endfor %}!", data) == "0: Jeff, 1: Seb!" );
|
||||
CHECK( env.render("{% for name in names %}{{ loop/index }}: {{ name }}{% if loop/is_last == false %}, {% endif %}{% endfor %}!", data) == "0: Jeff, 1: Seb!" );
|
||||
CHECK( env.render("{% for name in names %}{{ loop.index }}: {{ name }}{% if not loop.is_last %}, {% endif %}{% endfor %}!", data) == "0: Jeff, 1: Seb!" );
|
||||
CHECK( env.render("{% for name in names %}{{ loop.index }}: {{ name }}{% if loop.is_last == false %}, {% endif %}{% endfor %}!", data) == "0: Jeff, 1: Seb!" );
|
||||
|
||||
data["empty_loop"] = {};
|
||||
CHECK( env.render("{% for name in empty_loop %}a{% endfor %}", data) == "" );
|
||||
CHECK( env.render("{% for name in {} %}a{% endfor %}", data) == "" );
|
||||
|
||||
CHECK_THROWS_WITH( env.render("{% for name ins names %}a{% endfor %}", data), "[inja.exception.parser_error] unknown loop statement: for name ins names" );
|
||||
CHECK_THROWS_WITH( env.render("{% for name ins names %}a{% endfor %}", data), "[inja.exception.parser_error] expected 'in', got 'ins'" );
|
||||
// CHECK_THROWS_WITH( env.render("{% for name in relatives %}{{ name }}{% endfor %}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is object" );
|
||||
}
|
||||
|
||||
@@ -77,25 +83,28 @@ TEST_CASE("types") {
|
||||
CHECK( env.render("{% if age == 26 %}26{% else if age == 27 %}27{% else if age == 28 %}28{% else %}29{% endif %}", data) == "29" );
|
||||
CHECK( env.render("{% if age == 25 %}+{% endif %}{% if age == 29 %}+{% else %}-{% endif %}", data) == "+" );
|
||||
|
||||
CHECK_THROWS_WITH( env.render("{% if is_happy %}{% if is_happy %}{% endif %}", data), "[inja.exception.parser_error] misordered if statement" );
|
||||
CHECK_THROWS_WITH( env.render("{% if is_happy %}{% else if is_happy %}{% end if %}", data), "[inja.exception.parser_error] misordered if statement" );
|
||||
CHECK_THROWS_WITH( env.render("{% if is_happy %}{% if is_happy %}{% endif %}", data), "[inja.exception.parser_error] unmatched if" );
|
||||
CHECK_THROWS_WITH( env.render("{% if is_happy %}{% else if is_happy %}{% end if %}", data), "[inja.exception.parser_error] expected statement, got 'end'" );
|
||||
}
|
||||
|
||||
SECTION("line statements") {
|
||||
CHECK( env.render(R"(## if is_happy
|
||||
Yeah!
|
||||
## endif)", data) == "Yeah!" );
|
||||
## endif)", data) == R"(Yeah!
|
||||
)" );
|
||||
|
||||
CHECK( env.render(R"(## if is_happy
|
||||
## if is_happy
|
||||
Yeah!
|
||||
## endif
|
||||
## endif )", data) == "Yeah!" );
|
||||
}
|
||||
## endif )", data) == R"(Yeah!
|
||||
)" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("functions") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
|
||||
json data;
|
||||
data["name"] = "Peter";
|
||||
@@ -206,7 +215,7 @@ TEST_CASE("functions") {
|
||||
CHECK( env.render("{{ default(nothing, 0) }}", data) == "0" );
|
||||
CHECK( env.render("{{ default(name, \"nobody\") }}", data) == "Peter" );
|
||||
CHECK( env.render("{{ default(surname, \"nobody\") }}", data) == "nobody" );
|
||||
CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable '/lastname' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable 'lastname' not found" );
|
||||
}
|
||||
|
||||
SECTION("exists") {
|
||||
@@ -221,8 +230,8 @@ TEST_CASE("functions") {
|
||||
CHECK( env.render("{{ existsIn(brother, \"parents\") }}", data) == "false" );
|
||||
CHECK( env.render("{{ existsIn(brother, property) }}", data) == "true" );
|
||||
CHECK( env.render("{{ existsIn(brother, name) }}", data) == "false" );
|
||||
CHECK_THROWS_WITH( env.render("{{ existsIn(sister, \"lastname\") }}", data), "[inja.exception.render_error] variable '/sister' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{ existsIn(brother, sister) }}", data), "[inja.exception.render_error] variable '/sister' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{ existsIn(sister, \"lastname\") }}", data), "[inja.exception.render_error] variable 'sister' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{ existsIn(brother, sister) }}", data), "[inja.exception.render_error] variable 'sister' not found" );
|
||||
}
|
||||
|
||||
SECTION("isType") {
|
||||
@@ -243,40 +252,41 @@ TEST_CASE("functions") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("callbacks") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
json data;
|
||||
data["age"] = 28;
|
||||
|
||||
env.add_callback("double", 1, [&env](inja::Parsed::Arguments args, json data) {
|
||||
int number = env.get_argument<double>(args, 0, data);
|
||||
env.add_callback("double", 1, [](inja::Arguments& args) {
|
||||
int number = args.at(0)->get<double>();
|
||||
return 2 * number;
|
||||
});
|
||||
|
||||
env.add_callback("half", 1, [&env](inja::Parsed::Arguments args, json data) {
|
||||
int number = env.get_argument<double>(args, 0, data);
|
||||
env.add_callback("half", 1, [](inja::Arguments args) {
|
||||
int number = args.at(0)->get<double>();
|
||||
return number / 2;
|
||||
});
|
||||
|
||||
std::string greet = "Hello";
|
||||
env.add_callback("double-greetings", 0, [greet](inja::Parsed::Arguments args, json data) {
|
||||
env.add_callback("double-greetings", 0, [greet](inja::Arguments args) {
|
||||
return greet + " " + greet + "!";
|
||||
});
|
||||
|
||||
env.add_callback("multiply", 2, [&env](inja::Parsed::Arguments args, json data) {
|
||||
double number1 = env.get_argument(args, 0, data);
|
||||
auto number2 = env.get_argument<double>(args, 1, data);
|
||||
env.add_callback("multiply", 2, [](inja::Arguments args) {
|
||||
double number1 = args.at(0)->get<double>();
|
||||
auto number2 = args.at(1)->get<double>();
|
||||
return number1 * number2;
|
||||
});
|
||||
|
||||
env.add_callback("multiply", 3, [&env](inja::Parsed::Arguments args, json data) {
|
||||
double number1 = env.get_argument(args, 0, data);
|
||||
double number2 = env.get_argument(args, 1, data);
|
||||
double number3 = env.get_argument(args, 2, data);
|
||||
env.add_callback("multiply", 3, [](inja::Arguments args) {
|
||||
double number1 = args.at(0)->get<double>();
|
||||
double number2 = args.at(1)->get<double>();
|
||||
double number3 = args.at(2)->get<double>();
|
||||
return number1 * number2 * number3;
|
||||
});
|
||||
|
||||
env.add_callback("multiply", 0, [](inja::Parsed::Arguments args, json data) {
|
||||
env.add_callback("multiply", 0, [](inja::Arguments args) {
|
||||
return 1.0;
|
||||
});
|
||||
|
||||
@@ -289,8 +299,9 @@ TEST_CASE("callbacks") {
|
||||
CHECK( env.render("{{ multiply }}", data) == "1.0" );
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("combinations") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
json data;
|
||||
data["name"] = "Peter";
|
||||
data["city"] = "Brunswick";
|
||||
@@ -303,7 +314,7 @@ TEST_CASE("combinations") {
|
||||
|
||||
CHECK( env.render("{% if upper(\"Peter\") == \"PETER\" %}TRUE{% endif %}", data) == "TRUE" );
|
||||
CHECK( env.render("{% if lower(upper(name)) == \"peter\" %}TRUE{% endif %}", data) == "TRUE" );
|
||||
CHECK( env.render("{% for i in range(4) %}{{ loop/index1 }}{% endfor %}", data) == "1234" );
|
||||
CHECK( env.render("{% for i in range(4) %}{{ loop.index1 }}{% endfor %}", data) == "1234" );
|
||||
}
|
||||
|
||||
TEST_CASE("templates") {
|
||||
@@ -313,26 +324,27 @@ TEST_CASE("templates") {
|
||||
data["is_happy"] = true;
|
||||
|
||||
SECTION("reuse") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
inja::Template temp = env.parse("{% if is_happy %}{{ name }}{% else %}{{ city }}{% endif %}");
|
||||
|
||||
CHECK( env.render_template(temp, data) == "Peter" );
|
||||
CHECK( env.render(temp, data) == "Peter" );
|
||||
|
||||
data["is_happy"] = false;
|
||||
|
||||
CHECK( env.render_template(temp, data) == "Brunswick" );
|
||||
CHECK( env.render(temp, data) == "Brunswick" );
|
||||
}
|
||||
|
||||
SECTION("include") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
inja::Template t1 = env.parse("Hello {{ name }}");
|
||||
env.include_template("greeting", t1);
|
||||
|
||||
inja::Template t2 = env.parse("{% include \"greeting\" %}!");
|
||||
CHECK( env.render_template(t2, data) == "Hello Peter!" );
|
||||
CHECK( env.render(t2, data) == "Hello Peter!" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("other-syntax") {
|
||||
json data;
|
||||
data["name"] = "Peter";
|
||||
@@ -345,31 +357,31 @@ TEST_CASE("other-syntax") {
|
||||
data["is_happy"] = true;
|
||||
|
||||
SECTION("variables") {
|
||||
inja::Environment env = inja::Environment();
|
||||
env.set_element_notation(inja::ElementNotation::Dot);
|
||||
inja::Environment env;
|
||||
env.set_element_notation(inja::ElementNotation::Pointer);
|
||||
|
||||
CHECK( env.render("{{ name }}", data) == "Peter" );
|
||||
CHECK( env.render("Hello {{ names.1 }}!", data) == "Hello Seb!" );
|
||||
CHECK( env.render("Hello {{ brother.name }}!", data) == "Hello Chris!" );
|
||||
CHECK( env.render("Hello {{ brother.daughter0.name }}!", data) == "Hello Maria!" );
|
||||
CHECK( env.render("Hello {{ names/1 }}!", data) == "Hello Seb!" );
|
||||
CHECK( env.render("Hello {{ brother/name }}!", data) == "Hello Chris!" );
|
||||
CHECK( env.render("Hello {{ brother/daughter0/name }}!", data) == "Hello Maria!" );
|
||||
|
||||
CHECK_THROWS_WITH( env.render("{{unknown.name}}", data), "[inja.exception.render_error] variable '/unknown/name' not found" );
|
||||
CHECK_THROWS_WITH( env.render("{{unknown/name}}", data), "[inja.exception.render_error] variable 'unknown/name' not found" );
|
||||
}
|
||||
|
||||
SECTION("other expression syntax") {
|
||||
inja::Environment env = inja::Environment();
|
||||
inja::Environment env;
|
||||
|
||||
CHECK( env.render("Hello {{ name }}!", data) == "Hello Peter!" );
|
||||
|
||||
env.set_expression("\\(&", "&\\)");
|
||||
env.set_expression("(&", "&)");
|
||||
|
||||
CHECK( env.render("Hello {{ name }}!", data) == "Hello {{ name }}!" );
|
||||
CHECK( env.render("Hello (& name &)!", data) == "Hello Peter!" );
|
||||
}
|
||||
|
||||
SECTION("other comment syntax") {
|
||||
inja::Environment env = inja::Environment();
|
||||
env.set_comment("\\(&", "&\\)");
|
||||
inja::Environment env;
|
||||
env.set_comment("(&", "&)");
|
||||
|
||||
CHECK( env.render("Hello {# Test #}", data) == "Hello {# Test #}" );
|
||||
CHECK( env.render("Hello (& Test &)", data) == "Hello " );
|
||||
Reference in New Issue
Block a user