From 5ff3a54a35b11b15de35a61c9c666428a521f9f8 Mon Sep 17 00:00:00 2001 From: badair Date: Wed, 18 May 2016 00:32:03 -0500 Subject: [PATCH] adding tests --- .gitignore | 31 +--------- CMakeLists.txt | 78 ++++++++++++++++++++++++ test/CMakeLists.txt | 30 ++++++++++ test/test_1.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++ test/test_2.cpp | 131 +++++++++++++++++++++++++++++++++++++++++ test/test_3.cpp | 81 +++++++++++++++++++++++++ test/test_4.cpp | 62 ++++++++++++++++++++ 7 files changed, 525 insertions(+), 28 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 test/CMakeLists.txt create mode 100644 test/test_1.cpp create mode 100644 test/test_2.cpp create mode 100644 test/test_3.cpp create mode 100644 test/test_4.cpp diff --git a/.gitignore b/.gitignore index b8bd026..ac3302c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,3 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +build*/ +*.user +/test/Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..68cf36c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,78 @@ + +# Copyright Louis Dionne 2015 +# Modified Work Copyright Barrett Adair 2015 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +cmake_minimum_required(VERSION 3.0) +project(bind_parser CXX) +enable_testing() + +if(BUILD_CXX_STD) +else() + # Defaults to C++14 if not set: + set(BUILD_CXX_STD 14) +endif() + +set (CMAKE_CXX_STANDARD ${bind_parser_CXX_STD}) + +# Setting up CMake options and compiler flags (more flags can be set on a per-target basis or in subdirectories) + +include(CheckCXXCompilerFlag) +macro(bind_parser_append_flag testname flag) + check_cxx_compiler_flag(${flag} ${testname}) + if (${testname}) + add_compile_options(${flag}) + endif() +endmacro() + +bind_parser_append_flag(bind_parser_HAS_WERROR -Werror) +bind_parser_append_flag(bind_parser_HAS_WX -WX) +bind_parser_append_flag(bind_parser_HAS_QUNUSED_ARGUMENTS -Qunused-arguments) +bind_parser_append_flag(bind_parser_HAS_WNO_UNUSED_LOCAL_TYPEDEFS -Wno-unused-local-typedefs) +bind_parser_append_flag(bind_parser_HAS_WWRITE_STRINGS -Wwrite-strings) + +if(MSVC AND NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + #disable warning about symbol truncation. Doesn't matter, affected types are not linked + bind_parser_append_flag(bind_parser_HAS_WD4503 -wd4503) + bind_parser_append_flag(bind_parser_HAS_W3 -W3) +else() + bind_parser_append_flag(bind_parser_HAS_W -W) + bind_parser_append_flag(bind_parser_HAS_WALL -Wall) + bind_parser_append_flag(bind_parser_HAS_WEXTRA -Wextra) +endif() + +if(NOT MSVC) + bind_parser_append_flag(bind_parser_HAS_FTEMPLATE_BACKTRACE_LIMIT -ftemplate-backtrace-limit=0) + bind_parser_append_flag(bind_parser_HAS_PEDANTIC -pedantic) + bind_parser_append_flag(bind_parser_HAS_STDCXX1Y -std=c++1y) +endif() + +############################################################################## +# bind_parser_target_name_for( [ext]) +# Returns the target name associated to a source file. If the path of the +# source file relative from the root of bind_parser is `path/to/source/file.ext`, +# the target name associated to it will be `path.to.source.file`. +# +# The extension of the file should be specified as a last argument. If no +# extension is specified, the `.cpp` extension is assumed. +############################################################################## + +function(bind_parser_target_name_for out file) + file(RELATIVE_PATH _relative ${bind_parser_SOURCE_DIR} ${file}) + string(REPLACE ".cpp" "" _name ${_relative}) + string(REGEX REPLACE "/" "." _name ${_name}) + set(${out} "${_name}" PARENT_SCOPE) +endfunction() + + +############################################################################## +# Setup the `check` target to build and then run all the tests and examples. +############################################################################## + +add_custom_target(check + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Build and then run all the tests and examples.") + +add_subdirectory(test) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..94567b0 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,30 @@ + +# Copyright Louis Dionne 2015 +# Modified Work Copyright Barrett Adair 2015 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +add_custom_target(tests COMMENT "Build all the unit tests.") + +############################################################################## +# bind_parser_add_unit_test( ...) +# +# Equivalent to `bind_parser_add_test`, except the test is also added as a +# dependency of the `tests` target. +############################################################################## + +include_directories(${bind_parser_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +file(GLOB_RECURSE UNIT_TESTS "*.cpp") + +foreach(_file IN LISTS UNIT_TESTS) + bind_parser_target_name_for(_target "${_file}") + add_executable(${_target} EXCLUDE_FROM_ALL "${_file}") + add_dependencies(tests ${_target}) + add_test(${_target} ${CMAKE_CURRENT_BINARY_DIR}/${_target}) +endforeach() + +add_dependencies(check tests) + + diff --git a/test/test_1.cpp b/test/test_1.cpp new file mode 100644 index 0000000..bc7279d --- /dev/null +++ b/test/test_1.cpp @@ -0,0 +1,140 @@ +/* + +Copyright Barrett Adair 2016 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +*/ + +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bind_parser.hpp" + +using namespace std::placeholders; + +struct Letter { + virtual operator const char*() const volatile = 0; +}; + +#define DEFINE_TEST_LETTER(L) \ +struct L : Letter { operator const char*() const volatile override { return #L; } } + +DEFINE_TEST_LETTER(A); +DEFINE_TEST_LETTER(B); +DEFINE_TEST_LETTER(C); +DEFINE_TEST_LETTER(D); +DEFINE_TEST_LETTER(E); +DEFINE_TEST_LETTER(F); +DEFINE_TEST_LETTER(G); + +auto letters( + const Letter& l1, + const Letter& l2, + const Letter& l3, + const Letter& l4, + const Letter& l5, + const Letter& l6, + const Letter& l7 + ) { + std::stringstream ss{}; + ss << l1 << l2 << l3 << l4 << l5 << l6 << l7; + return ss.str(); +} + +auto ordered_letters(A a, B b, C c, D d, E e, F f, G g) { + std::stringstream ss{}; + ss << a << b << c << d << e << f << g; + return ss.str(); +} + +template +constexpr auto +apply_helper(F&& f, Tuple&& t, std::index_sequence) { + return std::forward(f)(std::get(std::forward(t))...); +} + +template +constexpr auto +apply(F&& f, Tuple&& t) { + return apply_helper( + std::forward(f), + std::forward(t), + std::make_index_sequence< + std::tuple_size>::value>{} + ); +} + +int main() { + + auto a = A{}; + auto b = B{}; + auto c = C{}; + auto d = D{}; + auto e = E{}; + auto f = F{}; + auto g = G{}; + + assert(letters(a, b, c, d, e, f, g) == "ABCDEFG"); + assert(ordered_letters(a, b, c, d, e, f, g) == "ABCDEFG"); + + { + auto expr = bind_parser::bind(&ordered_letters, _1, _2, _3, _4, _5, _6, _7); + auto test = std::bind(&ordered_letters, _1, _2, _3, _4, _5, _6, _7); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + assert(apply(expr, expected_args{}) == "ABCDEFG"); + assert(apply(test, expected_args{}) == "ABCDEFG"); + } { + auto expr = bind_parser::bind(&ordered_letters, a, b, c, _1, _2, _3, _4); + auto test = std::bind(&ordered_letters, a, b, c, _1, _2, _3, _4); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + assert(apply(test, expected_args{}) == "ABCDEFG"); + assert(apply(test, expected_args{}) == "ABCDEFG"); + } { + auto expr = bind_parser::bind(&ordered_letters, _7, _6, _5, _4, _3, _2, _1); + auto test = std::bind(&ordered_letters, _7, _6, _5, _4, _3, _2, _1); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + assert(apply(expr, expected_args{}) == "ABCDEFG"); + assert(apply(test, expected_args{}) == "ABCDEFG"); + } { + auto expr = bind_parser::bind(&ordered_letters, a, b, c, _4, _3, _2, _1); + auto test = std::bind(&ordered_letters, a, b, c, _4, _3, _2, _1); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + assert(apply(expr, expected_args{}) == "ABCDEFG"); + assert(apply(test, expected_args{}) == "ABCDEFG"); + } { + auto expr = bind_parser::bind(&ordered_letters, _4, _3, _2, _1, e, f, g); + auto test = std::bind(&ordered_letters, _4, _3, _2, _1, e, f, g); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); + assert(apply(expr, expected_args{}) == "ABCDEFG"); + assert(apply(test, expected_args{}) == "ABCDEFG"); + } { + auto expr = bind_parser::bind(&letters, _1, _1, _3, _3, _2, a, b); + using args = bind_parser::args; + using expected_args = std::tuple; + static_assert(std::is_same::value, ""); + } +} diff --git a/test/test_2.cpp b/test/test_2.cpp new file mode 100644 index 0000000..2b67da4 --- /dev/null +++ b/test/test_2.cpp @@ -0,0 +1,131 @@ +/* + +Copyright Barrett Adair 2016 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +*/ + +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bind_parser.hpp" + +using namespace std::placeholders; + +struct Letter { + virtual operator const char*() const volatile = 0; +}; + +#define DEFINE_TEST_LETTER(L) \ +struct L : Letter { operator const char*() const volatile override { return #L; } } + +DEFINE_TEST_LETTER(A); +DEFINE_TEST_LETTER(B); +DEFINE_TEST_LETTER(C); +DEFINE_TEST_LETTER(D); +DEFINE_TEST_LETTER(E); +DEFINE_TEST_LETTER(F); +DEFINE_TEST_LETTER(G); + +// functions `ordered_letters`, `BEEF_returns_D`, `BEEF_returns_G`, +// and `BEEF_returns_B` are used to set up a complex bind expression +// with bind_parser::bind + +auto ordered_letters(A a, B b, C c, D d, E e, F f, G g) { + std::stringstream ss{}; + ss << a << b << c << d << e << f << g; + return ss.str(); +} + +auto BEEF_returns_D(B, E, E, F) { + return D{}; +} + +auto BEEF_returns_G(B, E, E, F) { + return G{}; +} + +auto BEEF_returns_B(B, E, E, F) { + return B{}; +} + +template +constexpr auto +apply_helper(F&& f, Tuple&& t, std::index_sequence) { + return std::forward(f)(std::get(std::forward(t))...); +} + +//used to apply the expected_args tuple to std::bind +template +constexpr auto +apply(F&& f, Tuple&& t) { + return apply_helper( + std::forward(f), + std::forward(t), + std::make_index_sequence< + std::tuple_size>::value>{} + ); +} + +const auto a = A{}; +const auto b = B{}; +const auto c = C{}; +const auto d = D{}; +const auto e = E{}; +const auto f = F{}; +const auto g = G{}; + +// This macro lets us create a complex bind expression +// with both `std::bind` and `bind_parser::bind` +#define BIND_WITH(bind_name) \ + bind_name(&ordered_letters, \ + _1, \ + _2, \ + _3, \ + bind_name(&BEEF_returns_D, \ + _2, \ + e, \ + _4, \ + _7 \ + ), \ + _5, \ + _6, \ + bind_name(&BEEF_returns_G, \ + bind_name(&BEEF_returns_B, \ + b, \ + _10, \ + e, \ + f \ + ), \ + _9, \ + e, \ + _8 \ + ) \ + ) \ +/**/ + +int main() { + + assert(ordered_letters(a, b, c, d, e, f, g) == "ABCDEFG"); + + auto parser_bind = BIND_WITH(bind_parser::bind); + auto std_bind = BIND_WITH(std::bind); + + // these are the argument types as we expect due to the arrangement + // of the bind expression's placeholders + using expected_args = std::tuple; + using args = bind_parser::args; + + static_assert(std::is_same::value, ""); + assert(apply(parser_bind, expected_args{}) == "ABCDEFG"); + assert(apply(std_bind, expected_args{}) == "ABCDEFG"); +} diff --git a/test/test_3.cpp b/test/test_3.cpp new file mode 100644 index 0000000..491c471 --- /dev/null +++ b/test/test_3.cpp @@ -0,0 +1,81 @@ +/*<- + +Copyright Barrett Adair 2016 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +->*/ + +/* In this test, the last _1 placeholder in the bind +expression forces all other _1 slots to accept ScaryMonster, +because ScaryMonster is the narrowest of all _1 parameters. */ + +#undef NDEBUG + +#include +#include +#include +#include + +#include "bind_parser.hpp" + +struct Vampire {}; +struct Robot {}; +struct Animal {}; +struct Dog : Animal {}; +struct Poodle : Dog {}; +struct ScaryMonster : Vampire, Robot, Poodle {}; + +auto vampire_to_robot(Vampire) { + return Robot{}; +} + +auto robot_to_dog = [](Robot){ + return Dog{}; +}; + +struct converter { + auto dog_to_vampire(Dog) { + return Vampire{}; + } +}; + +int take_all(Vampire, Robot, Animal, Dog, Poodle, ScaryMonster) { + return 0; +} + +using namespace std::placeholders; + +int main() { + + auto b = + bind_parser::bind(&take_all, + bind_parser::bind(&converter::dog_to_vampire, + converter{}, + bind_parser::bind(robot_to_dog, + bind_parser::bind(&vampire_to_robot, _1) + ) + ), + bind_parser::bind(&vampire_to_robot, _3), + Animal{}, + _1, + _2, + _1 + ); + + { + using args = bind_parser::args; + using expect = std::tuple; + static_assert(std::is_same::value, ""); + } + + { + using type = bind_parser::function_type; + using expect = int(ScaryMonster, Poodle, Vampire); + static_assert(std::is_same::value, ""); + } + + assert(b(ScaryMonster{}, Poodle{}, Vampire{}) == 0); + + return 0; +} diff --git a/test/test_4.cpp b/test/test_4.cpp new file mode 100644 index 0000000..c4bef8e --- /dev/null +++ b/test/test_4.cpp @@ -0,0 +1,62 @@ +/*<- + +Copyright Barrett Adair 2016 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +->*/ + +#undef NDEBUG + + +#include +#include +#include +#include + +#include "bind_parser.hpp" + +struct Vampire {}; +struct Robot {}; +struct Animal {}; +struct Dog : Animal {}; +struct Poodle : Dog {}; +struct ScaryMonster : Poodle, Robot, Vampire {}; + +auto take_vampire(const Vampire&) { return 0; } +auto take_robot(const Robot&) { return 0; } +auto take_dog(const Dog&) { return 0; } +auto take_scary_monster(const ScaryMonster&) { return 0; } + +int f(int, int, int, int) { return 0; } + +using namespace std::placeholders; + +int main() { + + ScaryMonster monster{}; + + auto b = bind_parser::bind( + &f, + bind_parser::bind(&take_vampire, _1), + bind_parser::bind(&take_robot, _1), + bind_parser::bind(&take_dog, _1), + bind_parser::bind(&take_scary_monster, _1) + ); + + { + using args = bind_parser::args; + using expect = std::tuple; + static_assert(std::is_same::value, ""); + } + + { + using type = bind_parser::function_type; + using expect = int(const ScaryMonster&); + static_assert(std::is_same::value, ""); + } + + assert(b(monster) == 0); + + return 0; +}