From bd4eb1349a0ce69e00525e3c8c11fc20a4a25d7f Mon Sep 17 00:00:00 2001 From: Daniel Sipka Date: Fri, 10 Apr 2015 09:52:50 +0200 Subject: [PATCH] file to header preprocessor for unit tests --- CMakeLists.txt | 38 ++++++++++++++--- src/render_context.cpp | 14 +++---- test/data/ampersand_escape.h | 4 +- test/data/apostrophe.h | 4 +- test/data/array_of_strings.h | 4 +- test/data/backslashes.h | 4 +- test/filetoheader.cpp | 79 ++++++++++++++++++++++++++++++++++++ test/main.cpp | 20 ++++----- 8 files changed, 136 insertions(+), 31 deletions(-) create mode 100644 test/filetoheader.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b01784..841cdcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,41 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) project(mstch) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall") -find_package(Boost 1.54 REQUIRED) -include_directories(src include vendor/include ${Boost_INCLUDE_DIR}) +find_package(Boost 1.54 COMPONENTS program_options REQUIRED) +include_directories(${CMAKE_BINARY_DIR} src include vendor/include ${Boost_INCLUDE_DIR}) set(SRC src/mstch.cpp - test/main.cpp) + src/utils.cpp + src/token.cpp + src/render_context.cpp + src/state/in_section.cpp + src/state/in_inverted_section.cpp + src/state/outside_section.cpp + src/visitor/is_node_empty.cpp + src/visitor/render_node.cpp + src/visitor/render_section.cpp + src/visitor/to_json.cpp) -add_executable(mstch ${SRC} include/types.h src/utils.h src/utils.cpp src/token.cpp src/token.h src/render_context.cpp src/render_context.h src/state/render_state.h src/state/in_section.cpp src/state/in_section.h src/state/in_inverted_section.cpp src/state/in_inverted_section.h src/state/outside_section.cpp src/state/outside_section.h src/visitor/is_node_empty.cpp src/visitor/is_node_empty.h src/visitor/render_node.cpp src/visitor/render_node.h src/visitor/render_section.cpp src/visitor/render_section.h src/visitor/to_json.cpp src/visitor/to_json.h) +add_library(mstch STATIC ${SRC}) + +add_executable(mstch_test test/main.cpp) +target_link_libraries(mstch_test mstch) + +add_executable(filetoheader test/filetoheader.cpp) +target_link_libraries(filetoheader ${Boost_PROGRAM_OPTIONS_LIBRARY}) + +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/test_data.h + COMMAND ${CMAKE_BINARY_DIR}/filetoheader --output ${CMAKE_BINARY_DIR}/test_data.h --namespace mstchtest + -Dampersand_escape.h -Sampersand_escape.mustache -Sampersand_escape.txt + -Dapostrophe.h -Sapostrophe.mustache -Sapostrophe.txt + -Darray_of_strings.h -Sarray_of_strings.mustache -Sarray_of_strings.txt + -Dbackslashes.h -Sbackslashes.mustache -Sbackslashes.txt + DEPENDS ${CMAKE_BINARY_DIR}/filetoheader + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test/data/) +set_source_files_properties(${CMAKE_BINARY_DIR}/test_data.h PROPERTIES GENERATED TRUE) +add_custom_target(test_data_h DEPENDS ${CMAKE_BINARY_DIR}/test_data.h) +add_dependencies(mstch test_data_h) diff --git a/src/render_context.cpp b/src/render_context.cpp index 71e7b3d..40bd9fd 100644 --- a/src/render_context.cpp +++ b/src/render_context.cpp @@ -9,30 +9,30 @@ using namespace mstch; const mstch::node render_context::null_node; render_context::render_context(const mstch::object &object, const std::map& partials): - objects{object}, partials(partials), + objects{object}, state(new state::outside_section) { } render_context::render_context(const mstch::object& object, const render_context& context): - objects(context.objects), - partials(context.partials), - state(new state::outside_section) + partials(context.partials), + objects(context.objects), + state(new state::outside_section) { objects.push_front(object); } const mstch::node& render_context::find_node(const std::string &token, const std::deque ¤t_objects) { - /*if(token != "." && token.find('.') != std::string::npos) { + if(token != "." && token.find('.') != std::string::npos) { return find_node(token.substr(token.rfind('.') + 1), {boost::get(find_node(token.substr(0, token.rfind('.')), current_objects))}); - } else {*/ + } else { for (auto& object: current_objects) if (object.count(token) != 0) return object.at(token); return null_node; - //} + } } const mstch::node& render_context::get_node(const std::string& token) { diff --git a/test/data/ampersand_escape.h b/test/data/ampersand_escape.h index 1d7414f..f7453df 100644 --- a/test/data/ampersand_escape.h +++ b/test/data/ampersand_escape.h @@ -1,3 +1,3 @@ -auto data = mstch::object{ +mstch::object{ {"message", std::string{"Some "}} -}; +} \ No newline at end of file diff --git a/test/data/apostrophe.h b/test/data/apostrophe.h index 14417be..31812fa 100644 --- a/test/data/apostrophe.h +++ b/test/data/apostrophe.h @@ -1,4 +1,4 @@ -auto data = mstch::object{ +mstch::object{ {"apos", std::string{"'"}}, {"control", std::string{"X"}} -}; +} \ No newline at end of file diff --git a/test/data/array_of_strings.h b/test/data/array_of_strings.h index 0882fc0..c2c5ab6 100644 --- a/test/data/array_of_strings.h +++ b/test/data/array_of_strings.h @@ -1,3 +1,3 @@ -auto data = mstch::object{ +mstch::object{ {"array_of_strings", mstch::array{std::string{"hello"}, std::string{"world"}}} -}; +} \ No newline at end of file diff --git a/test/data/backslashes.h b/test/data/backslashes.h index 1ec1514..abddb88 100644 --- a/test/data/backslashes.h +++ b/test/data/backslashes.h @@ -1,3 +1,3 @@ -auto data = mstch::object{ +mstch::object{ {"value", std::string{"\\abc"}} -}; +} \ No newline at end of file diff --git a/test/filetoheader.cpp b/test/filetoheader.cpp new file mode 100644 index 0000000..9fc02f5 --- /dev/null +++ b/test/filetoheader.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include +#include +#include +#include + +void wrap_data(std::istream& input, std::ostream& output, const std::string& variable_name) { + output << "const auto " << variable_name << " = "; + std::string line; + while (std::getline(input, line)) { + output << line; + if(!input.eof()) output << std::endl; + } + output << ";" << std::endl; +} + +void wrap_string(std::istream& input, std::ostream& output, const std::string& variable_name) { + output << "const std::string " << variable_name << "{" << std::endl;; + std::string line; + while (std::getline(input, line)) { + boost::replace_all(line, "\\", "\\\\"); + boost::replace_all(line, "\"", "\\\""); + output << " \"" << line << "\\n\""; + if(!input.eof()) output << std::endl; + } + output << "};" << std::endl; +} + +int main(int argc, char* argv[]) { + namespace po = boost::program_options; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "show help") + ("output", po::value(), "output file") + ("namespace", po::value(), "namespace to use") + ("input-string,S", po::value>(), "files to parse as strings") + ("input-data,D", po::value>(), "files to parse as data"); + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << std::endl; + return 1; + } + + if (!vm.count("output")) { + std::cout << "Output file not set" << std::endl; + return 1; + } + + std::ofstream output(vm["output"].as(), std::ios::out); + + if(vm.count("namespace")) + output << "namespace " << vm["namespace"].as() << " {" << std::endl; + + for(auto& string_filename: vm["input-string"].as>()) { + std::ifstream input(string_filename, std::ios::in); + wrap_string(input, output, boost::replace_all_copy(string_filename, ".", "_")); + input.close(); + } + + for(auto& data_filename: vm["input-data"].as>()) { + std::ifstream input(data_filename, std::ios::in); + wrap_data(input, output, boost::replace_all_copy(data_filename, ".", "_")); + input.close(); + } + + if(vm.count("namespace")) + output << "}" << std::endl; + + output.close(); + + return 0; +} diff --git a/test/main.cpp b/test/main.cpp index fa6ff14..60a3053 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -3,16 +3,14 @@ #include -#include -#include -#include +#include "test_data.h" -std::string file_to_string(const std::string& filename) { - std::ifstream t(filename); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - return str; -} +#define MSTCH_TEST(x,y) TEST_CASE(x) { REQUIRE(y ## _txt == mstch::render(y ## _mustache, y ## _h)); } + +MSTCH_TEST("Ampersand escape", mstchtest::ampersand_escape) +MSTCH_TEST("Apostrophe", mstchtest::apostrophe) +MSTCH_TEST("Array of strings", mstchtest::array_of_strings) +MSTCH_TEST("Backslashes", mstchtest::backslashes) /*TEST_CASE("Ampersand escape") { #include "data/ampersand_escape.h" @@ -119,12 +117,12 @@ TEST_CASE("Falsy") { REQUIRE(exp == mstch::render(tpl, data)); }*/ -TEST_CASE("Falsy array") { +/*TEST_CASE("Falsy array") { #include "data/falsy_array.h" auto tpl = file_to_string("data/falsy_array.mustache"); auto exp = file_to_string("data/falsy_array.txt"); REQUIRE(exp == mstch::render(tpl, data)); -} +}*/ /*TEST_CASE("Grandparent context") { #include "data/grandparent_context.h"