From a6a61586a46717e30bee3235df9859d9c5d70d16 Mon Sep 17 00:00:00 2001 From: pantor Date: Sat, 14 Sep 2019 12:05:51 +0200 Subject: [PATCH] code style (cpplint) --- include/inja/bytecode.hpp | 11 +- include/inja/config.hpp | 10 +- include/inja/environment.hpp | 70 ++-- include/inja/function_storage.hpp | 12 +- include/inja/inja.hpp | 8 +- include/inja/lexer.hpp | 10 +- include/inja/parser.hpp | 19 +- include/inja/polyfill.hpp | 62 +-- include/inja/renderer.hpp | 30 +- include/inja/template.hpp | 11 +- include/inja/token.hpp | 10 +- include/inja/utils.hpp | 15 +- single_include/inja/inja.hpp | 34 +- test/unit-files.cpp | 80 ++-- test/unit-renderer.cpp | 674 +++++++++++++++--------------- 15 files changed, 556 insertions(+), 500 deletions(-) diff --git a/include/inja/bytecode.hpp b/include/inja/bytecode.hpp index 8a3bce3..b91337a 100644 --- a/include/inja/bytecode.hpp +++ b/include/inja/bytecode.hpp @@ -1,6 +1,9 @@ -#ifndef PANTOR_INJA_BYTECODE_HPP -#define PANTOR_INJA_BYTECODE_HPP +// Copyright (c) 2019 Pantor. All rights reserved. +#ifndef INCLUDE_INJA_BYTECODE_HPP_ +#define INCLUDE_INJA_BYTECODE_HPP_ + +#include #include #include @@ -10,7 +13,7 @@ namespace inja { -using namespace nlohmann; +using json = nlohmann::json; struct Bytecode { @@ -128,4 +131,4 @@ struct Bytecode { } // namespace inja -#endif // PANTOR_INJA_BYTECODE_HPP +#endif // INCLUDE_INJA_BYTECODE_HPP_ diff --git a/include/inja/config.hpp b/include/inja/config.hpp index bf943f1..d3089f5 100644 --- a/include/inja/config.hpp +++ b/include/inja/config.hpp @@ -1,5 +1,7 @@ -#ifndef PANTOR_INJA_CONFIG_HPP -#define PANTOR_INJA_CONFIG_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_CONFIG_HPP_ +#define INCLUDE_INJA_CONFIG_HPP_ #include #include @@ -54,6 +56,6 @@ struct ParserConfig { ElementNotation notation {ElementNotation::Dot}; }; -} +} // namespace inja -#endif // PANTOR_INJA_CONFIG_HPP +#endif // INCLUDE_INJA_CONFIG_HPP_ diff --git a/include/inja/environment.hpp b/include/inja/environment.hpp index 378a916..05bb5e8 100644 --- a/include/inja/environment.hpp +++ b/include/inja/environment.hpp @@ -1,5 +1,7 @@ -#ifndef PANTOR_INJA_ENVIRONMENT_HPP -#define PANTOR_INJA_ENVIRONMENT_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_ENVIRONMENT_HPP_ +#define INCLUDE_INJA_ENVIRONMENT_HPP_ #include #include @@ -20,7 +22,7 @@ namespace inja { -using namespace nlohmann; +using json = nlohmann::json; /*! * \brief Class for changing the configuration. @@ -103,8 +105,8 @@ class Environment { Template parse_template(const std::string& filename) { Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates); - return parser.parse_template(m_impl->input_path + static_cast(filename)); - } + return parser.parse_template(m_impl->input_path + static_cast(filename)); + } std::string render(nonstd::string_view input, const json& data) { return render(parse(input), data); @@ -117,35 +119,35 @@ class Environment { } std::string render_file(const std::string& filename, const json& data) { - return render(parse_template(filename), data); - } + return render(parse_template(filename), data); + } std::string render_file_with_json_file(const std::string& filename, const std::string& filename_data) { - const json data = load_json(filename_data); - return render_file(filename, data); - } + const json data = load_json(filename_data); + return render_file(filename, data); + } void write(const std::string& filename, const json& data, const std::string& filename_out) { - std::ofstream file(m_impl->output_path + filename_out); - file << render_file(filename, data); - file.close(); - } + std::ofstream file(m_impl->output_path + filename_out); + file << render_file(filename, data); + file.close(); + } void write(const Template& temp, const json& data, const std::string& filename_out) { - std::ofstream file(m_impl->output_path + filename_out); - file << render(temp, data); - file.close(); - } + std::ofstream file(m_impl->output_path + filename_out); + file << render(temp, data); + file.close(); + } - void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) { - const json data = load_json(filename_data); - write(filename, data, filename_out); - } + void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) { + const json data = load_json(filename_data); + write(filename, data, filename_out); + } - void write_with_json_file(const Template& temp, const std::string& filename_data, const std::string& filename_out) { - const json data = load_json(filename_data); - write(temp, data, filename_out); - } + void write_with_json_file(const Template& temp, const std::string& filename_data, const std::string& filename_out) { + const json data = load_json(filename_data); + write(temp, data, filename_out); + } std::ostream& render_to(std::ostream& os, const Template& tmpl, const json& data) { Renderer(m_impl->included_templates, m_impl->callbacks).render_to(os, tmpl, data); @@ -154,15 +156,15 @@ class Environment { std::string load_file(const std::string& filename) { Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates); - return parser.load_file(m_impl->input_path + filename); - } + return parser.load_file(m_impl->input_path + filename); + } json load_json(const std::string& filename) { - std::ifstream file = open_file_or_throw(m_impl->input_path + filename); - json j; - file >> j; - return j; - } + std::ifstream file = open_file_or_throw(m_impl->input_path + filename); + json j; + file >> j; + return j; + } void add_callback(const std::string& name, unsigned int numArgs, const CallbackFunction& callback) { m_impl->callbacks.add_callback(name, numArgs, callback); @@ -194,4 +196,4 @@ inline void render_to(std::ostream& os, nonstd::string_view input, const json& d } -#endif // PANTOR_INJA_ENVIRONMENT_HPP +#endif // INCLUDE_INJA_ENVIRONMENT_HPP_ diff --git a/include/inja/function_storage.hpp b/include/inja/function_storage.hpp index 7a6f3db..1b9247b 100644 --- a/include/inja/function_storage.hpp +++ b/include/inja/function_storage.hpp @@ -1,5 +1,9 @@ -#ifndef PANTOR_INJA_FUNCTION_STORAGE_HPP -#define PANTOR_INJA_FUNCTION_STORAGE_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_FUNCTION_STORAGE_HPP_ +#define INCLUDE_INJA_FUNCTION_STORAGE_HPP_ + +#include #include "bytecode.hpp" #include "string_view.hpp" @@ -7,7 +11,7 @@ namespace inja { -using namespace nlohmann; +using json = nlohmann::json; using Arguments = std::vector; using CallbackFunction = std::function; @@ -72,4 +76,4 @@ class FunctionStorage { } -#endif // PANTOR_INJA_FUNCTION_STORAGE_HPP +#endif // INCLUDE_INJA_FUNCTION_STORAGE_HPP_ diff --git a/include/inja/inja.hpp b/include/inja/inja.hpp index a6be6eb..e8dd05a 100644 --- a/include/inja/inja.hpp +++ b/include/inja/inja.hpp @@ -1,5 +1,7 @@ -#ifndef PANTOR_INJA_HPP -#define PANTOR_INJA_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_INJA_HPP_ +#define INCLUDE_INJA_INJA_HPP_ #include #include @@ -18,4 +20,4 @@ #include "renderer.hpp" -#endif // PANTOR_INJA_HPP +#endif // INCLUDE_INJA_INJA_HPP_ diff --git a/include/inja/lexer.hpp b/include/inja/lexer.hpp index 28d5b89..c9b4d69 100644 --- a/include/inja/lexer.hpp +++ b/include/inja/lexer.hpp @@ -1,5 +1,7 @@ -#ifndef PANTOR_INJA_LEXER_HPP -#define PANTOR_INJA_LEXER_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_LEXER_HPP_ +#define INCLUDE_INJA_LEXER_HPP_ #include #include @@ -75,7 +77,7 @@ class Lexer { inja::string_view::starts_with(open_str, m_config.line_statement)) { m_state = State::LineStart; } else { - m_pos += 1; // wasn't actually an opening sequence + m_pos += 1; // wasn't actually an opening sequence goto again; } @@ -303,4 +305,4 @@ class Lexer { } -#endif // PANTOR_INJA_LEXER_HPP +#endif // INCLUDE_INJA_LEXER_HPP_ diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp index cc80535..461f693 100644 --- a/include/inja/parser.hpp +++ b/include/inja/parser.hpp @@ -1,7 +1,12 @@ -#ifndef PANTOR_INJA_PARSER_HPP -#define PANTOR_INJA_PARSER_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_PARSER_HPP_ +#define INCLUDE_INJA_PARSER_HPP_ #include +#include +#include +#include #include "bytecode.hpp" #include "config.hpp" @@ -510,10 +515,10 @@ class Parser { } std::string load_file(nonstd::string_view filename) { - std::ifstream file = open_file_or_throw(static_cast(filename)); - std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return text; - } + std::ifstream file = open_file_or_throw(static_cast(filename)); + std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + return text; + } private: const ParserConfig& m_config; @@ -553,4 +558,4 @@ class Parser { } // namespace inja -#endif // PANTOR_INJA_PARSER_HPP +#endif // INCLUDE_INJA_PARSER_HPP_ diff --git a/include/inja/polyfill.hpp b/include/inja/polyfill.hpp index d87fb9f..58ce5de 100644 --- a/include/inja/polyfill.hpp +++ b/include/inja/polyfill.hpp @@ -1,50 +1,54 @@ -#ifndef PANTOR_INJA_POLYFILL_HPP -#define PANTOR_INJA_POLYFILL_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_POLYFILL_HPP_ +#define INCLUDE_INJA_POLYFILL_HPP_ #if __cplusplus < 201402L #include +#include #include #include namespace stdinja { - template struct _Unique_if { - typedef std::unique_ptr _Single_object; - }; - template struct _Unique_if { - typedef std::unique_ptr _Unknown_bound; - }; +template struct _Unique_if { + typedef std::unique_ptr _Single_object; +}; - template struct _Unique_if { - typedef void _Known_bound; - }; +template struct _Unique_if { + typedef std::unique_ptr _Unknown_bound; +}; - template - typename _Unique_if::_Single_object - make_unique(Args&&... args) { - return std::unique_ptr(new T(std::forward(args)...)); - } +template struct _Unique_if { + typedef void _Known_bound; +}; - template - typename _Unique_if::_Unknown_bound - make_unique(size_t n) { - typedef typename std::remove_extent::type U; - return std::unique_ptr(new U[n]()); - } - - template - typename _Unique_if::_Known_bound - make_unique(Args&&...) = delete; +template +typename _Unique_if::_Single_object +make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); } +template +typename _Unique_if::_Unknown_bound +make_unique(size_t n) { + typedef typename std::remove_extent::type U; + return std::unique_ptr(new U[n]()); +} + +template +typename _Unique_if::_Known_bound +make_unique(Args&&...) = delete; + +} // namespace stdinja + #else namespace stdinja = std; -#endif // memory */ +#endif // memory */ - -#endif // PANTOR_INJA_POLYFILL_HPP +#endif // INCLUDE_INJA_POLYFILL_HPP_ diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp index d3ced6f..e7a90d4 100644 --- a/include/inja/renderer.hpp +++ b/include/inja/renderer.hpp @@ -1,8 +1,13 @@ -#ifndef PANTOR_INJA_RENDERER_HPP -#define PANTOR_INJA_RENDERER_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_RENDERER_HPP_ +#define INCLUDE_INJA_RENDERER_HPP_ #include #include +#include +#include +#include #include @@ -113,7 +118,7 @@ class Renderer { LoopLevel& level = m_loop_stack.back(); if (level.loop_type == LoopLevel::Type::Array) { - level.data[static_cast(level.value_name)] = level.values.at(level.index); // *level.it; + level.data[static_cast(level.value_name)] = level.values.at(level.index); // *level.it; auto& loopData = level.data["loop"]; loopData["index"] = level.index; loopData["index1"] = level.index + 1; @@ -135,22 +140,21 @@ class Renderer { enum class Type { Map, Array }; Type loop_type; - nonstd::string_view key_name; // variable name for keys - nonstd::string_view value_name; // variable name for values - json data; // data with loop info added + nonstd::string_view key_name; // variable name for keys + nonstd::string_view value_name; // variable name for values + json data; // data with loop info added - json values; // values to iterate over + json values; // values to iterate over // loop over list - size_t index; // current list index - size_t size; // length of list + size_t index; // current list index + size_t size; // length of list // loop over map using KeyValue = std::pair; using MapValues = std::vector; - MapValues map_values; // values to iterate over - MapValues::iterator map_it; // iterator over values - + MapValues map_values; // values to iterate over + MapValues::iterator map_it; // iterator over values }; std::vector m_loop_stack; @@ -573,4 +577,4 @@ class Renderer { } // namespace inja -#endif // PANTOR_INJA_RENDERER_HPP +#endif // INCLUDE_INJA_RENDERER_HPP_ diff --git a/include/inja/template.hpp b/include/inja/template.hpp index b3c77db..d3d0fbc 100644 --- a/include/inja/template.hpp +++ b/include/inja/template.hpp @@ -1,6 +1,9 @@ -#ifndef PANTOR_INJA_TEMPLATE_HPP -#define PANTOR_INJA_TEMPLATE_HPP +// Copyright (c) 2019 Pantor. All rights reserved. +#ifndef INCLUDE_INJA_TEMPLATE_HPP_ +#define INCLUDE_INJA_TEMPLATE_HPP_ + +#include #include #include @@ -19,6 +22,6 @@ struct Template { using TemplateStorage = std::map; -} +} // namespace inja -#endif // PANTOR_INJA_TEMPLATE_HPP +#endif // INCLUDE_INJA_TEMPLATE_HPP_ diff --git a/include/inja/token.hpp b/include/inja/token.hpp index 5755956..2f0c2f0 100644 --- a/include/inja/token.hpp +++ b/include/inja/token.hpp @@ -1,5 +1,9 @@ -#ifndef PANTOR_INJA_TOKEN_HPP -#define PANTOR_INJA_TOKEN_HPP +// Copyright (c) 2019 Pantor. All rights reserved. + +#ifndef INCLUDE_INJA_TOKEN_HPP_ +#define INCLUDE_INJA_TOKEN_HPP_ + +#include #include "string_view.hpp" @@ -62,4 +66,4 @@ struct Token { } -#endif // PANTOR_INJA_TOKEN_HPP +#endif // INCLUDE_INJA_TOKEN_HPP_ diff --git a/include/inja/utils.hpp b/include/inja/utils.hpp index 77c65c8..d1ac141 100644 --- a/include/inja/utils.hpp +++ b/include/inja/utils.hpp @@ -1,8 +1,13 @@ -#ifndef PANTOR_INJA_UTILS_HPP -#define PANTOR_INJA_UTILS_HPP +// Copyright (c) 2019 Pantor. All rights reserved. +#ifndef INCLUDE_INJA_UTILS_HPP_ +#define INCLUDE_INJA_UTILS_HPP_ + +#include #include #include +#include +#include #include "string_view.hpp" @@ -28,7 +33,7 @@ namespace string_view { inline nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end) { start = std::min(start, view.size()); end = std::min(std::max(start, end), view.size()); - return view.substr(start, end - start); // StringRef(Data + Start, End - Start); + return view.substr(start, end - start); // StringRef(Data + Start, End - Start); } inline std::pair split(nonstd::string_view view, char Separator) { @@ -42,8 +47,8 @@ namespace string_view { inline bool starts_with(nonstd::string_view view, nonstd::string_view prefix) { return (view.size() >= prefix.size() && view.compare(0, prefix.size(), prefix) == 0); } -} // namespace string +} // namespace string_view } // namespace inja -#endif // PANTOR_INJA_UTILS_HPP +#endif // INCLUDE_INJA_UTILS_HPP_ diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index a6ad38e..cd77c2c 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -1408,10 +1408,13 @@ struct ParserConfig { #ifndef PANTOR_INJA_FUNCTION_STORAGE_HPP #define PANTOR_INJA_FUNCTION_STORAGE_HPP +#include + // #include "bytecode.hpp" #ifndef PANTOR_INJA_BYTECODE_HPP #define PANTOR_INJA_BYTECODE_HPP +#include #include #include @@ -1422,7 +1425,7 @@ struct ParserConfig { namespace inja { -using namespace nlohmann; +using json = nlohmann::json; struct Bytecode { @@ -1620,6 +1623,9 @@ class FunctionStorage { #define PANTOR_INJA_PARSER_HPP #include +#include +#include +#include // #include "bytecode.hpp" @@ -1640,6 +1646,8 @@ class FunctionStorage { #ifndef PANTOR_INJA_TOKEN_HPP #define PANTOR_INJA_TOKEN_HPP +#include + // #include "string_view.hpp" @@ -1702,14 +1710,17 @@ struct Token { } -#endif // PANTOR_INJA_TOKEN_HPP +#endif // PANTOR_INJA_TOKEN_HPP // #include "utils.hpp" #ifndef PANTOR_INJA_UTILS_HPP #define PANTOR_INJA_UTILS_HPP +#include #include #include +#include +#include // #include "string_view.hpp" @@ -1736,7 +1747,7 @@ namespace string_view { inline nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end) { start = std::min(start, view.size()); end = std::min(std::max(start, end), view.size()); - return view.substr(start, end - start); // StringRef(Data + Start, End - Start); + return view.substr(start, end - start); // StringRef(Data + Start, End - Start); } inline std::pair split(nonstd::string_view view, char Separator) { @@ -2058,6 +2069,7 @@ class Lexer { #ifndef PANTOR_INJA_TEMPLATE_HPP #define PANTOR_INJA_TEMPLATE_HPP +#include #include #include @@ -2079,7 +2091,7 @@ using TemplateStorage = std::map; } -#endif // PANTOR_INJA_TEMPLATE_HPP +#endif // PANTOR_INJA_TEMPLATE_HPP // #include "token.hpp" @@ -2585,10 +2597,10 @@ class Parser { } std::string load_file(nonstd::string_view filename) { - std::ifstream file = open_file_or_throw(static_cast(filename)); - std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - return text; - } + std::ifstream file = open_file_or_throw(static_cast(filename)); + std::string text((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + return text; + } private: const ParserConfig& m_config; @@ -2638,6 +2650,7 @@ class Parser { #if __cplusplus < 201402L #include +#include #include #include @@ -2688,6 +2701,9 @@ namespace stdinja = std; #include #include +#include +#include +#include #include @@ -2801,7 +2817,7 @@ class Renderer { LoopLevel& level = m_loop_stack.back(); if (level.loop_type == LoopLevel::Type::Array) { - level.data[static_cast(level.value_name)] = level.values.at(level.index); // *level.it; + level.data[static_cast(level.value_name)] = level.values.at(level.index); // *level.it; auto& loopData = level.data["loop"]; loopData["index"] = level.index; loopData["index1"] = level.index + 1; diff --git a/test/unit-files.cpp b/test/unit-files.cpp index 0c6747d..8292f47 100644 --- a/test/unit-files.cpp +++ b/test/unit-files.cpp @@ -8,59 +8,59 @@ using json = nlohmann::json; const std::string test_file_directory {"../test/data/"}; TEST_CASE("loading") { - inja::Environment env; - json data; - data["name"] = "Jeff"; + inja::Environment env; + json data; + data["name"] = "Jeff"; - SECTION("Files should be loaded") { - CHECK( env.load_file(test_file_directory + "simple.txt") == "Hello {{ name }}." ); - } + SECTION("Files should be loaded") { + CHECK( env.load_file(test_file_directory + "simple.txt") == "Hello {{ name }}." ); + } - SECTION("Files should be rendered") { - CHECK( env.render_file(test_file_directory + "simple.txt", data) == "Hello Jeff." ); - } + SECTION("Files should be rendered") { + CHECK( env.render_file(test_file_directory + "simple.txt", data) == "Hello Jeff." ); + } - SECTION("File includes should be rendered") { - CHECK( env.render_file(test_file_directory + "include.txt", data) == "Answer: Hello Jeff." ); - } + SECTION("File includes should be rendered") { + CHECK( env.render_file(test_file_directory + "include.txt", data) == "Answer: Hello Jeff." ); + } - SECTION("File error should throw") { - std::string path(test_file_directory + "does-not-exist"); - CHECK_THROWS_WITH( env.load_file(path), "[inja.exception.file_error] failed accessing file at '" + path + "'" ); - CHECK_THROWS_WITH( env.load_json(path), "[inja.exception.file_error] failed accessing file at '" + path + "'" ); - } + SECTION("File error should throw") { + std::string path(test_file_directory + "does-not-exist"); + CHECK_THROWS_WITH( env.load_file(path), "[inja.exception.file_error] failed accessing file at '" + path + "'" ); + CHECK_THROWS_WITH( env.load_json(path), "[inja.exception.file_error] failed accessing file at '" + path + "'" ); + } } TEST_CASE("complete-files") { - inja::Environment env {test_file_directory}; + inja::Environment env {test_file_directory}; - 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_file(test_name + "/result.txt") ); - } - } + 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_file(test_name + "/result.txt") ); + } + } } TEST_CASE("complete-files-whitespace-control") { - inja::Environment env {test_file_directory}; - env.set_trim_blocks(true); - env.set_lstrip_blocks(true); - - for (std::string test_name : {"nested-whitespace"}) { - SECTION(test_name) { - CHECK( env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_file(test_name + "/result.txt") ); - } - } + inja::Environment env {test_file_directory}; + env.set_trim_blocks(true); + env.set_lstrip_blocks(true); + + for (std::string test_name : {"nested-whitespace"}) { + SECTION(test_name) { + CHECK( env.render_file_with_json_file(test_name + "/template.txt", test_name + "/data.json") == env.load_file(test_name + "/result.txt") ); + } + } } TEST_CASE("global-path") { - inja::Environment env {test_file_directory, "./"}; - inja::Environment env_result {"./"}; - json data; - data["name"] = "Jeff"; + inja::Environment env {test_file_directory, "./"}; + inja::Environment env_result {"./"}; + json data; + data["name"] = "Jeff"; - SECTION("Files should be written") { - env.write("simple.txt", data, "global-path-result.txt"); - CHECK( env_result.load_file("global-path-result.txt") == "Hello Jeff." ); - } + SECTION("Files should be written") { + env.write("simple.txt", data, "global-path-result.txt"); + CHECK( env_result.load_file("global-path-result.txt") == "Hello Jeff." ); + } } diff --git a/test/unit-renderer.cpp b/test/unit-renderer.cpp index b56cc45..6756c7c 100644 --- a/test/unit-renderer.cpp +++ b/test/unit-renderer.cpp @@ -6,123 +6,123 @@ using json = nlohmann::json; TEST_CASE("dot-to-pointer") { - std::string buffer; - CHECK( inja::convert_dot_to_json_pointer("test", buffer) == "/test" ); - CHECK( inja::convert_dot_to_json_pointer("guests.2", buffer) == "/guests/2" ); - CHECK( inja::convert_dot_to_json_pointer("person.names.surname", buffer) == "/person/names/surname" ); + std::string buffer; + CHECK( inja::convert_dot_to_json_pointer("test", buffer) == "/test" ); + CHECK( inja::convert_dot_to_json_pointer("guests.2", buffer) == "/guests/2" ); + CHECK( inja::convert_dot_to_json_pointer("person.names.surname", buffer) == "/person/names/surname" ); } TEST_CASE("types") { - inja::Environment env; - json data; - data["name"] = "Peter"; - data["city"] = "Brunswick"; - data["age"] = 29; - data["names"] = {"Jeff", "Seb"}; - data["brother"]["name"] = "Chris"; - data["brother"]["daughters"] = {"Maria", "Helen"}; - data["brother"]["daughter0"] = { { "name", "Maria" } }; - data["is_happy"] = true; - data["is_sad"] = false; - data["relatives"]["mother"] = "Maria"; - data["relatives"]["brother"] = "Chris"; - data["relatives"]["sister"] = "Jenny"; - data["vars"] = {2, 3, 4, 0, -1, -2, -3}; + inja::Environment env; + json data; + data["name"] = "Peter"; + data["city"] = "Brunswick"; + data["age"] = 29; + data["names"] = {"Jeff", "Seb"}; + data["brother"]["name"] = "Chris"; + data["brother"]["daughters"] = {"Maria", "Helen"}; + data["brother"]["daughter0"] = { { "name", "Maria" } }; + data["is_happy"] = true; + data["is_sad"] = false; + data["relatives"]["mother"] = "Maria"; + data["relatives"]["brother"] = "Chris"; + data["relatives"]["sister"] = "Jenny"; + data["vars"] = {2, 3, 4, 0, -1, -2, -3}; - SECTION("basic") { - CHECK( env.render("", data) == "" ); - CHECK( env.render("Hello World!", data) == "Hello World!" ); - } + SECTION("basic") { + CHECK( env.render("", data) == "" ); + CHECK( env.render("Hello World!", data) == "Hello World!" ); + } - SECTION("variables") { - CHECK( env.render("Hello {{ name }}!", data) == "Hello Peter!" ); - CHECK( env.render("{{ name }}", data) == "Peter" ); - 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("{{ \"{{ no_value }}\" }}", data) == "{{ no_value }}" ); + SECTION("variables") { + CHECK( env.render("Hello {{ name }}!", data) == "Hello Peter!" ); + CHECK( env.render("{{ name }}", data) == "Peter" ); + 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("{{ \"{{ no_value }}\" }}", data) == "{{ no_value }}" ); - 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") { - CHECK( env.render("Hello{# This is a comment #}!", data) == "Hello!" ); - CHECK( env.render("{# --- #Todo --- #}", data) == "" ); - } + SECTION("comments") { + CHECK( env.render("Hello{# This is a comment #}!", data) == "Hello!" ); + CHECK( env.render("{# --- #Todo --- #}", data) == "" ); + } - 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("{% 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!" ); + 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("{% 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 {} %}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] expected 'in', got 'ins'" ); - CHECK_THROWS_WITH( env.render("{% for name in empty_loop %}a{% endfor %}", data), "[inja.exception.render_error] variable 'empty_loop' not found" ); - // 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" ); - } + 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 empty_loop %}a{% endfor %}", data), "[inja.exception.render_error] variable 'empty_loop' not found" ); + // 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" ); + } - SECTION("nested loops") { - auto ldata = json::parse( + SECTION("nested loops") { + auto ldata = json::parse( R"DELIM( { "outer" : [ - { "inner" : [ - { "in2" : [ 1, 2 ] }, - { "in2" : []}, - { "in2" : []} - ] - }, - { "inner" : [] }, - { "inner" : [ - { "in2" : [ 3, 4 ] }, - { "in2" : [ 5, 6 ] } - ] - } - ] + { "inner" : [ + { "in2" : [ 1, 2 ] }, + { "in2" : []}, + { "in2" : []} + ] + }, + { "inner" : [] }, + { "inner" : [ + { "in2" : [ 3, 4 ] }, + { "in2" : [ 5, 6 ] } + ] + } + ] } )DELIM" - ); - CHECK(env.render(R"DELIM( + ); + CHECK(env.render(R"DELIM( {% for o in outer %}{% for i in o.inner %}{{loop.parent.index}}:{{loop.index}}::{{loop.parent.is_last}} {% for ii in i.in2%}{{ii}},{%endfor%} {%endfor%}{%endfor%} )DELIM", - ldata) == "\n0:0::false\n1,2,\n0:1::false\n\n0:2::false\n\n2:0::true\n3,4,\n2:1::true\n5,6,\n\n"); - } + ldata) == "\n0:0::false\n1,2,\n0:1::false\n\n0:2::false\n\n2:0::true\n3,4,\n2:1::true\n5,6,\n\n"); + } - SECTION("conditionals") { - CHECK( env.render("{% if is_happy %}Yeah!{% endif %}", data) == "Yeah!" ); - CHECK( env.render("{% if is_sad %}Yeah!{% endif %}", data) == "" ); - CHECK( env.render("{% if is_sad %}Yeah!{% else %}Nooo...{% endif %}", data) == "Nooo..." ); - CHECK( env.render("{% if age == 29 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); - CHECK( env.render("{% if age > 29 %}Right{% else %}Wrong{% endif %}", data) == "Wrong" ); - CHECK( env.render("{% if age <= 29 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); - CHECK( env.render("{% if age != 28 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); - CHECK( env.render("{% if age >= 30 %}Right{% else %}Wrong{% endif %}", data) == "Wrong" ); - CHECK( env.render("{% if age in [28, 29, 30] %}True{% endif %}", data) == "True" ); - CHECK( env.render("{% if age == 28 %}28{% else if age == 29 %}29{% endif %}", data) == "29" ); - 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) == "+" ); + SECTION("conditionals") { + CHECK( env.render("{% if is_happy %}Yeah!{% endif %}", data) == "Yeah!" ); + CHECK( env.render("{% if is_sad %}Yeah!{% endif %}", data) == "" ); + CHECK( env.render("{% if is_sad %}Yeah!{% else %}Nooo...{% endif %}", data) == "Nooo..." ); + CHECK( env.render("{% if age == 29 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); + CHECK( env.render("{% if age > 29 %}Right{% else %}Wrong{% endif %}", data) == "Wrong" ); + CHECK( env.render("{% if age <= 29 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); + CHECK( env.render("{% if age != 28 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); + CHECK( env.render("{% if age >= 30 %}Right{% else %}Wrong{% endif %}", data) == "Wrong" ); + CHECK( env.render("{% if age in [28, 29, 30] %}True{% endif %}", data) == "True" ); + CHECK( env.render("{% if age == 28 %}28{% else if age == 29 %}29{% endif %}", data) == "29" ); + 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] 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'" ); - } + 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 + SECTION("line statements") { + CHECK( env.render(R"(## if is_happy Yeah! ## endif)", data) == R"(Yeah! )" ); - CHECK( env.render(R"(## if is_happy + CHECK( env.render(R"(## if is_happy ## if is_happy Yeah! ## endif @@ -133,318 +133,318 @@ Yeah! TEST_CASE("functions") { - inja::Environment env; + inja::Environment env; - json data; - data["name"] = "Peter"; - data["city"] = "New York"; - data["names"] = {"Jeff", "Seb", "Peter", "Tom"}; - data["temperature"] = 25.6789; - data["brother"]["name"] = "Chris"; - data["brother"]["daughters"] = {"Maria", "Helen"}; - data["property"] = "name"; - data["age"] = 29; - data["i"] = 1; - data["is_happy"] = true; - data["is_sad"] = false; - data["vars"] = {2, 3, 4, 0, -1, -2, -3}; + json data; + data["name"] = "Peter"; + data["city"] = "New York"; + data["names"] = {"Jeff", "Seb", "Peter", "Tom"}; + data["temperature"] = 25.6789; + data["brother"]["name"] = "Chris"; + data["brother"]["daughters"] = {"Maria", "Helen"}; + data["property"] = "name"; + data["age"] = 29; + data["i"] = 1; + data["is_happy"] = true; + data["is_sad"] = false; + data["vars"] = {2, 3, 4, 0, -1, -2, -3}; - SECTION("upper") { - CHECK( env.render("{{ upper(name) }}", data) == "PETER" ); - CHECK( env.render("{{ upper( name ) }}", data) == "PETER" ); - CHECK( env.render("{{ upper(city) }}", data) == "NEW YORK" ); - CHECK( env.render("{{ upper(upper(name)) }}", data) == "PETER" ); - // CHECK_THROWS_WITH( env.render("{{ upper(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is number" ); - // CHECK_THROWS_WITH( env.render("{{ upper(true) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is boolean" ); - } + SECTION("upper") { + CHECK( env.render("{{ upper(name) }}", data) == "PETER" ); + CHECK( env.render("{{ upper( name ) }}", data) == "PETER" ); + CHECK( env.render("{{ upper(city) }}", data) == "NEW YORK" ); + CHECK( env.render("{{ upper(upper(name)) }}", data) == "PETER" ); + // CHECK_THROWS_WITH( env.render("{{ upper(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is number" ); + // CHECK_THROWS_WITH( env.render("{{ upper(true) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is boolean" ); + } - SECTION("lower") { - CHECK( env.render("{{ lower(name) }}", data) == "peter" ); - CHECK( env.render("{{ lower(city) }}", data) == "new york" ); - // CHECK_THROWS_WITH( env.render("{{ lower(5.45) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is number" ); - } + SECTION("lower") { + CHECK( env.render("{{ lower(name) }}", data) == "peter" ); + CHECK( env.render("{{ lower(city) }}", data) == "new york" ); + // CHECK_THROWS_WITH( env.render("{{ lower(5.45) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be string, but is number" ); + } - SECTION("range") { - CHECK( env.render("{{ range(2) }}", data) == "[0,1]" ); - CHECK( env.render("{{ range(4) }}", data) == "[0,1,2,3]" ); - // CHECK_THROWS_WITH( env.render("{{ range(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); - } + SECTION("range") { + CHECK( env.render("{{ range(2) }}", data) == "[0,1]" ); + CHECK( env.render("{{ range(4) }}", data) == "[0,1,2,3]" ); + // CHECK_THROWS_WITH( env.render("{{ range(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); + } - SECTION("length") { - CHECK( env.render("{{ length(names) }}", data) == "4" ); // Length of array - CHECK( env.render("{{ length(name) }}", data) == "5" ); // Length of string - // CHECK_THROWS_WITH( env.render("{{ length(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); - } + SECTION("length") { + CHECK( env.render("{{ length(names) }}", data) == "4" ); // Length of array + CHECK( env.render("{{ length(name) }}", data) == "5" ); // Length of string + // CHECK_THROWS_WITH( env.render("{{ length(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); + } - SECTION("sort") { - CHECK( env.render("{{ sort([3, 2, 1]) }}", data) == "[1,2,3]" ); - CHECK( env.render("{{ sort([\"bob\", \"charlie\", \"alice\"]) }}", data) == "[\"alice\",\"bob\",\"charlie\"]" ); - // CHECK_THROWS_WITH( env.render("{{ sort(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); - } + SECTION("sort") { + CHECK( env.render("{{ sort([3, 2, 1]) }}", data) == "[1,2,3]" ); + CHECK( env.render("{{ sort([\"bob\", \"charlie\", \"alice\"]) }}", data) == "[\"alice\",\"bob\",\"charlie\"]" ); + // CHECK_THROWS_WITH( env.render("{{ sort(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); + } - SECTION("at") { - CHECK( env.render("{{ at(names, 0) }}", data) == "Jeff" ); - CHECK( env.render("{{ at(names, i) }}", data) == "Seb" ); - } + SECTION("at") { + CHECK( env.render("{{ at(names, 0) }}", data) == "Jeff" ); + CHECK( env.render("{{ at(names, i) }}", data) == "Seb" ); + } - SECTION("first") { - CHECK( env.render("{{ first(names) }}", data) == "Jeff" ); - // CHECK_THROWS_WITH( env.render("{{ first(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); - } + SECTION("first") { + CHECK( env.render("{{ first(names) }}", data) == "Jeff" ); + // CHECK_THROWS_WITH( env.render("{{ first(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); + } - SECTION("last") { - CHECK( env.render("{{ last(names) }}", data) == "Tom" ); - // CHECK_THROWS_WITH( env.render("{{ last(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); - } + SECTION("last") { + CHECK( env.render("{{ last(names) }}", data) == "Tom" ); + // CHECK_THROWS_WITH( env.render("{{ last(5) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is number" ); + } - SECTION("round") { - CHECK( env.render("{{ round(4, 0) }}", data) == "4.0" ); - CHECK( env.render("{{ round(temperature, 2) }}", data) == "25.68" ); - // CHECK_THROWS_WITH( env.render("{{ round(name, 2) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); - } + SECTION("round") { + CHECK( env.render("{{ round(4, 0) }}", data) == "4.0" ); + CHECK( env.render("{{ round(temperature, 2) }}", data) == "25.68" ); + // CHECK_THROWS_WITH( env.render("{{ round(name, 2) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); + } - SECTION("divisibleBy") { - CHECK( env.render("{{ divisibleBy(50, 5) }}", data) == "true" ); - CHECK( env.render("{{ divisibleBy(12, 3) }}", data) == "true" ); - CHECK( env.render("{{ divisibleBy(11, 3) }}", data) == "false" ); - // CHECK_THROWS_WITH( env.render("{{ divisibleBy(name, 2) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); - } + SECTION("divisibleBy") { + CHECK( env.render("{{ divisibleBy(50, 5) }}", data) == "true" ); + CHECK( env.render("{{ divisibleBy(12, 3) }}", data) == "true" ); + CHECK( env.render("{{ divisibleBy(11, 3) }}", data) == "false" ); + // CHECK_THROWS_WITH( env.render("{{ divisibleBy(name, 2) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); + } - SECTION("odd") { - CHECK( env.render("{{ odd(11) }}", data) == "true" ); - CHECK( env.render("{{ odd(12) }}", data) == "false" ); - // CHECK_THROWS_WITH( env.render("{{ odd(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); - } + SECTION("odd") { + CHECK( env.render("{{ odd(11) }}", data) == "true" ); + CHECK( env.render("{{ odd(12) }}", data) == "false" ); + // CHECK_THROWS_WITH( env.render("{{ odd(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); + } - SECTION("even") { - CHECK( env.render("{{ even(11) }}", data) == "false" ); - CHECK( env.render("{{ even(12) }}", data) == "true" ); - // CHECK_THROWS_WITH( env.render("{{ even(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); - } + SECTION("even") { + CHECK( env.render("{{ even(11) }}", data) == "false" ); + CHECK( env.render("{{ even(12) }}", data) == "true" ); + // CHECK_THROWS_WITH( env.render("{{ even(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be number, but is string" ); + } - SECTION("max") { - CHECK( env.render("{{ max([1, 2, 3]) }}", data) == "3" ); - CHECK( env.render("{{ max([-5.2, 100.2, 2.4]) }}", data) == "100.2" ); - // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); - } + SECTION("max") { + CHECK( env.render("{{ max([1, 2, 3]) }}", data) == "3" ); + CHECK( env.render("{{ max([-5.2, 100.2, 2.4]) }}", data) == "100.2" ); + // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); + } - SECTION("min") { - CHECK( env.render("{{ min([1, 2, 3]) }}", data) == "1" ); - CHECK( env.render("{{ min([-5.2, 100.2, 2.4]) }}", data) == "-5.2" ); - // CHECK_THROWS_WITH( env.render("{{ min(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); - } + SECTION("min") { + CHECK( env.render("{{ min([1, 2, 3]) }}", data) == "1" ); + CHECK( env.render("{{ min([-5.2, 100.2, 2.4]) }}", data) == "-5.2" ); + // CHECK_THROWS_WITH( env.render("{{ min(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); + } - SECTION("float") { - CHECK( env.render("{{ float(\"2.2\") == 2.2 }}", data) == "true" ); - CHECK( env.render("{{ float(\"-1.25\") == -1.25 }}", data) == "true" ); - // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); - } + SECTION("float") { + CHECK( env.render("{{ float(\"2.2\") == 2.2 }}", data) == "true" ); + CHECK( env.render("{{ float(\"-1.25\") == -1.25 }}", data) == "true" ); + // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); + } - SECTION("int") { - CHECK( env.render("{{ int(\"2\") == 2 }}", data) == "true" ); - CHECK( env.render("{{ int(\"-1.25\") == -1 }}", data) == "true" ); - // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); - } + SECTION("int") { + CHECK( env.render("{{ int(\"2\") == 2 }}", data) == "true" ); + CHECK( env.render("{{ int(\"-1.25\") == -1 }}", data) == "true" ); + // CHECK_THROWS_WITH( env.render("{{ max(name) }}", data), "[inja.exception.json_error] [json.exception.type_error.302] type must be array, but is string" ); + } - SECTION("default") { - CHECK( env.render("{{ default(11, 0) }}", data) == "11" ); - 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( env.render("{{ default(surname, \"{{ surname }}\") }}", data) == "{{ surname }}" ); - CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable 'lastname' not found" ); - } + SECTION("default") { + CHECK( env.render("{{ default(11, 0) }}", data) == "11" ); + 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( env.render("{{ default(surname, \"{{ surname }}\") }}", data) == "{{ surname }}" ); + CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable 'lastname' not found" ); + } - SECTION("exists") { - CHECK( env.render("{{ exists(\"name\") }}", data) == "true" ); - CHECK( env.render("{{ exists(\"zipcode\") }}", data) == "false" ); - CHECK( env.render("{{ exists(name) }}", data) == "false" ); - CHECK( env.render("{{ exists(property) }}", data) == "true" ); - } + SECTION("exists") { + CHECK( env.render("{{ exists(\"name\") }}", data) == "true" ); + CHECK( env.render("{{ exists(\"zipcode\") }}", data) == "false" ); + CHECK( env.render("{{ exists(name) }}", data) == "false" ); + CHECK( env.render("{{ exists(property) }}", data) == "true" ); + } - SECTION("existsIn") { - CHECK( env.render("{{ existsIn(brother, \"name\") }}", data) == "true" ); - 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" ); - } + SECTION("existsIn") { + CHECK( env.render("{{ existsIn(brother, \"name\") }}", data) == "true" ); + 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" ); + } - SECTION("isType") { - CHECK( env.render("{{ isBoolean(is_happy) }}", data) == "true" ); - CHECK( env.render("{{ isBoolean(vars) }}", data) == "false" ); - CHECK( env.render("{{ isNumber(age) }}", data) == "true" ); - CHECK( env.render("{{ isNumber(name) }}", data) == "false" ); - CHECK( env.render("{{ isInteger(age) }}", data) == "true" ); - CHECK( env.render("{{ isInteger(is_happy) }}", data) == "false" ); - CHECK( env.render("{{ isFloat(temperature) }}", data) == "true" ); - CHECK( env.render("{{ isFloat(age) }}", data) == "false" ); - CHECK( env.render("{{ isObject(brother) }}", data) == "true" ); - CHECK( env.render("{{ isObject(vars) }}", data) == "false" ); - CHECK( env.render("{{ isArray(vars) }}", data) == "true" ); - CHECK( env.render("{{ isArray(name) }}", data) == "false" ); - CHECK( env.render("{{ isString(name) }}", data) == "true" ); - CHECK( env.render("{{ isString(names) }}", data) == "false" ); - } + SECTION("isType") { + CHECK( env.render("{{ isBoolean(is_happy) }}", data) == "true" ); + CHECK( env.render("{{ isBoolean(vars) }}", data) == "false" ); + CHECK( env.render("{{ isNumber(age) }}", data) == "true" ); + CHECK( env.render("{{ isNumber(name) }}", data) == "false" ); + CHECK( env.render("{{ isInteger(age) }}", data) == "true" ); + CHECK( env.render("{{ isInteger(is_happy) }}", data) == "false" ); + CHECK( env.render("{{ isFloat(temperature) }}", data) == "true" ); + CHECK( env.render("{{ isFloat(age) }}", data) == "false" ); + CHECK( env.render("{{ isObject(brother) }}", data) == "true" ); + CHECK( env.render("{{ isObject(vars) }}", data) == "false" ); + CHECK( env.render("{{ isArray(vars) }}", data) == "true" ); + CHECK( env.render("{{ isArray(name) }}", data) == "false" ); + CHECK( env.render("{{ isString(name) }}", data) == "true" ); + CHECK( env.render("{{ isString(names) }}", data) == "false" ); + } } TEST_CASE("callbacks") { - inja::Environment env; - json data; - data["age"] = 28; + inja::Environment env; + json data; + data["age"] = 28; - env.add_callback("double", 1, [](inja::Arguments& args) { - int number = args.at(0)->get(); - return 2 * number; - }); + env.add_callback("double", 1, [](inja::Arguments& args) { + int number = args.at(0)->get(); + return 2 * number; + }); - env.add_callback("half", 1, [](inja::Arguments args) { - int number = args.at(0)->get(); - return number / 2; - }); + env.add_callback("half", 1, [](inja::Arguments args) { + int number = args.at(0)->get(); + return number / 2; + }); - std::string greet = "Hello"; - env.add_callback("double-greetings", 0, [greet](inja::Arguments args) { - return greet + " " + greet + "!"; - }); + std::string greet = "Hello"; + env.add_callback("double-greetings", 0, [greet](inja::Arguments args) { + return greet + " " + greet + "!"; + }); - env.add_callback("multiply", 2, [](inja::Arguments args) { - double number1 = args.at(0)->get(); - auto number2 = args.at(1)->get(); - return number1 * number2; - }); + env.add_callback("multiply", 2, [](inja::Arguments args) { + double number1 = args.at(0)->get(); + auto number2 = args.at(1)->get(); + return number1 * number2; + }); - env.add_callback("multiply", 3, [](inja::Arguments args) { - double number1 = args.at(0)->get(); - double number2 = args.at(1)->get(); - double number3 = args.at(2)->get(); - return number1 * number2 * number3; - }); + env.add_callback("multiply", 3, [](inja::Arguments args) { + double number1 = args.at(0)->get(); + double number2 = args.at(1)->get(); + double number3 = args.at(2)->get(); + return number1 * number2 * number3; + }); - env.add_callback("multiply", 0, [](inja::Arguments args) { - return 1.0; - }); + env.add_callback("multiply", 0, [](inja::Arguments args) { + return 1.0; + }); - CHECK( env.render("{{ double(age) }}", data) == "56" ); - CHECK( env.render("{{ half(age) }}", data) == "14" ); - CHECK( env.render("{{ double-greetings }}", data) == "Hello Hello!" ); - CHECK( env.render("{{ double-greetings() }}", data) == "Hello Hello!" ); - CHECK( env.render("{{ multiply(4, 5) }}", data) == "20.0" ); - CHECK( env.render("{{ multiply(3, 4, 5) }}", data) == "60.0" ); - CHECK( env.render("{{ multiply }}", data) == "1.0" ); + CHECK( env.render("{{ double(age) }}", data) == "56" ); + CHECK( env.render("{{ half(age) }}", data) == "14" ); + CHECK( env.render("{{ double-greetings }}", data) == "Hello Hello!" ); + CHECK( env.render("{{ double-greetings() }}", data) == "Hello Hello!" ); + CHECK( env.render("{{ multiply(4, 5) }}", data) == "20.0" ); + CHECK( env.render("{{ multiply(3, 4, 5) }}", data) == "60.0" ); + CHECK( env.render("{{ multiply }}", data) == "1.0" ); } TEST_CASE("combinations") { - inja::Environment env; - json data; - data["name"] = "Peter"; - data["city"] = "Brunswick"; - data["age"] = 29; - data["names"] = {"Jeff", "Seb"}; - data["brother"]["name"] = "Chris"; - data["brother"]["daughters"] = {"Maria", "Helen"}; - data["brother"]["daughter0"] = { { "name", "Maria" } }; - data["is_happy"] = true; + inja::Environment env; + json data; + data["name"] = "Peter"; + data["city"] = "Brunswick"; + data["age"] = 29; + data["names"] = {"Jeff", "Seb"}; + data["brother"]["name"] = "Chris"; + data["brother"]["daughters"] = {"Maria", "Helen"}; + data["brother"]["daughter0"] = { { "name", "Maria" } }; + data["is_happy"] = true; - 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("{% 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" ); } TEST_CASE("templates") { - json data; - data["name"] = "Peter"; - data["city"] = "Brunswick"; - data["is_happy"] = true; + json data; + data["name"] = "Peter"; + data["city"] = "Brunswick"; + data["is_happy"] = true; - SECTION("reuse") { - inja::Environment env; - inja::Template temp = env.parse("{% if is_happy %}{{ name }}{% else %}{{ city }}{% endif %}"); + SECTION("reuse") { + inja::Environment env; + inja::Template temp = env.parse("{% if is_happy %}{{ name }}{% else %}{{ city }}{% endif %}"); - CHECK( env.render(temp, data) == "Peter" ); + CHECK( env.render(temp, data) == "Peter" ); - data["is_happy"] = false; + data["is_happy"] = false; - CHECK( env.render(temp, data) == "Brunswick" ); - } + CHECK( env.render(temp, data) == "Brunswick" ); + } - SECTION("include") { - inja::Environment env; - inja::Template t1 = env.parse("Hello {{ name }}"); - env.include_template("greeting", t1); + SECTION("include") { + 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(t2, data) == "Hello Peter!" ); - CHECK_THROWS_WITH( env.parse("{% include \"does-not-exist\" %}!"), "[inja.exception.file_error] failed accessing file at 'does-not-exist'" ); - } + inja::Template t2 = env.parse("{% include \"greeting\" %}!"); + CHECK( env.render(t2, data) == "Hello Peter!" ); + CHECK_THROWS_WITH( env.parse("{% include \"does-not-exist\" %}!"), "[inja.exception.file_error] failed accessing file at 'does-not-exist'" ); + } - SECTION("include-in-loop") { - json loop_data; - loop_data["cities"] = json::array({{{"name", "Munich"}}, {{"name", "New York"}}}); + SECTION("include-in-loop") { + json loop_data; + loop_data["cities"] = json::array({{{"name", "Munich"}}, {{"name", "New York"}}}); - inja::Environment env; - env.include_template("city.tpl", env.parse("{{ loop.index }}:{{ city.name }};")); + inja::Environment env; + env.include_template("city.tpl", env.parse("{{ loop.index }}:{{ city.name }};")); - CHECK( env.render("{% for city in cities %}{% include \"city.tpl\" %}{% endfor %}", loop_data) == "0:Munich;1:New York;" ); - } + CHECK( env.render("{% for city in cities %}{% include \"city.tpl\" %}{% endfor %}", loop_data) == "0:Munich;1:New York;" ); + } } TEST_CASE("other-syntax") { - json data; - data["name"] = "Peter"; - data["city"] = "Brunswick"; - data["age"] = 29; - data["names"] = {"Jeff", "Seb"}; - data["brother"]["name"] = "Chris"; - data["brother"]["daughters"] = {"Maria", "Helen"}; - data["brother"]["daughter0"] = { { "name", "Maria" } }; - data["is_happy"] = true; + json data; + data["name"] = "Peter"; + data["city"] = "Brunswick"; + data["age"] = 29; + data["names"] = {"Jeff", "Seb"}; + data["brother"]["name"] = "Chris"; + data["brother"]["daughters"] = {"Maria", "Helen"}; + data["brother"]["daughter0"] = { { "name", "Maria" } }; + data["is_happy"] = true; - SECTION("variables") { - inja::Environment env; - env.set_element_notation(inja::ElementNotation::Pointer); + SECTION("variables") { + 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("{{ 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_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; + SECTION("other expression syntax") { + inja::Environment env; - CHECK( env.render("Hello {{ name }}!", data) == "Hello Peter!" ); + 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!" ); - } + CHECK( env.render("Hello {{ name }}!", data) == "Hello {{ name }}!" ); + CHECK( env.render("Hello (& name &)!", data) == "Hello Peter!" ); + } - SECTION("other comment syntax") { - inja::Environment env; - env.set_comment("(&", "&)"); + SECTION("other comment syntax") { + inja::Environment env; + env.set_comment("(&", "&)"); - CHECK( env.render("Hello {# Test #}", data) == "Hello {# Test #}" ); - CHECK( env.render("Hello (& Test &)", data) == "Hello " ); - } + CHECK( env.render("Hello {# Test #}", data) == "Hello {# Test #}" ); + CHECK( env.render("Hello (& Test &)", data) == "Hello " ); + } - SECTION("multiple changes") { - inja::Environment env; - env.set_line_statement("$$"); - env.set_expression("<%", "%>"); + SECTION("multiple changes") { + inja::Environment env; + env.set_line_statement("$$"); + env.set_expression("<%", "%>"); - std::string string_template = R"DELIM(Hello <%name%> + std::string string_template = R"DELIM(Hello <%name%> $$ if name == "Peter" - You really are <%name%> + You really are <%name%> $$ endif )DELIM"; - CHECK( env.render(string_template, data) == "Hello Peter\n You really are Peter\n"); - } + CHECK( env.render(string_template, data) == "Hello Peter\n You really are Peter\n"); + } }