diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 4 | ||||
| -rw-r--r-- | test/include/conversion_suite.hpp | 11 | ||||
| -rw-r--r-- | test/include/kawaii.hpp | 5 | ||||
| -rw-r--r-- | test/src/conversion_suite.cpp | 201 | ||||
| -rw-r--r-- | test/src/driver.cpp | 6 |
6 files changed, 221 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 070fdb6..9977012 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ if(BUILD_TESTING) "${PROJECT_SOURCE_DIR}/test/src/driver.cpp" "${PROJECT_SOURCE_DIR}/test/src/derivation_clause_suite.cpp" + "${PROJECT_SOURCE_DIR}/test/src/conversion_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/new_type_constructor_suite.cpp" ) diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 68a22dd..67e29c3 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -39,7 +39,7 @@ namespace nt /** * Retrieve the base type value contained in this @p new_type */ - auto constexpr decay() const noexcept -> BaseType + auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v<BaseType>) -> BaseType { return m_value; } @@ -75,7 +75,7 @@ namespace nt /** * Retrieve the base type value contained in this @p new_type */ - auto constexpr decay() const noexcept -> BaseType + auto constexpr decay() const noexcept(std::is_nothrow_copy_constructible_v<BaseType>) -> BaseType { return m_value; } diff --git a/test/include/conversion_suite.hpp b/test/include/conversion_suite.hpp new file mode 100644 index 0000000..8b9c337 --- /dev/null +++ b/test/include/conversion_suite.hpp @@ -0,0 +1,11 @@ +#ifndef NEWTYPE_TEST_CONVERSION_SUITE_HPP +#define NEWTYPE_TEST_CONVERSION_SUITE_HPP + +#include <cute/cute_suite.h> + +#include <string> +#include <utility> + +auto conversion_suite() -> std::pair<cute::suite, std::string>; + +#endif
\ No newline at end of file diff --git a/test/include/kawaii.hpp b/test/include/kawaii.hpp index 787f38a..69da012 100644 --- a/test/include/kawaii.hpp +++ b/test/include/kawaii.hpp @@ -17,7 +17,7 @@ namespace nt::test namespace impl { auto constexpr prepositions = std::array{"a", "an", "and", "as", "at", "by", "for", "in", "of", "on", "or", "the", "to"}; - + auto constexpr keywords = std::array{"noexcept"}; auto constexpr type_names = std::array{"new_type", "derivation_clause"}; auto inline replace_template_argument_syntax(std::string const & name) -> std::string @@ -103,8 +103,9 @@ namespace nt::test while (stream >> word && word != "[") { auto is_preposition = std::find(cbegin(prepositions), cend(prepositions), word) != cend(prepositions); + auto is_keyword = std::find(cbegin(keywords), cend(keywords), word) != cend(keywords); auto is_type_name = std::find(cbegin(type_names), cend(type_names), word) != cend(type_names); - if ((!is_preposition || buffer.empty()) && !is_type_name) + if ((!(is_preposition || is_keyword) || buffer.empty()) && !is_type_name) { word.front() = std::toupper(word.front()); } diff --git a/test/src/conversion_suite.cpp b/test/src/conversion_suite.cpp new file mode 100644 index 0000000..b60a611 --- /dev/null +++ b/test/src/conversion_suite.cpp @@ -0,0 +1,201 @@ +#include "conversion_suite.hpp" + +#include "kawaii.hpp" +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/new_type.hpp" + +#include <cute/cute.h> + +#include <algorithm> +#include <iterator> +#include <limits> +#include <random> +#include <string> +#include <type_traits> +#include <vector> + +inline namespace traits_extensions +{ + + template<typename To, typename From, typename = void> + struct is_implicitly_convertible : std::false_type + { + }; + + template<typename To, typename From> + struct is_implicitly_convertible<To, From, std::void_t<decltype(std::declval<To &>() = std::declval<From &>())>> : std::true_type + { + }; + + template<typename To, typename From> + auto constexpr is_implicitly_convertible_v = is_implicitly_convertible<To, From>::value; + +} // namespace traits_extensions + +inline namespace ddt_support +{ + + template<typename T> + struct datum + { + T value; + cute::test_failure failure; + }; + + template<typename ValueType> + auto generate_test_set(std::size_t size) -> std::vector<datum<ValueType>> + { + auto device = std::random_device{}; + auto generator = std::mt19937{device()}; + auto distribution = [&] { + auto min = std::numeric_limits<ValueType>::min(); + auto max = std::numeric_limits<ValueType>::max(); + if constexpr (std::is_floating_point_v<ValueType>) + { + return std::uniform_real_distribution<ValueType>(min, max); + } + else + { + return std::uniform_int_distribution<ValueType>(min, max); + } + }(); + + auto data = std::vector<datum<ValueType>>{}; + generate_n(std::back_inserter(data), size, [&] { + auto point = distribution(generator); + return datum<ValueType>{point, DDT()}; + }); + return data; + } + +} // namespace ddt_support + +inline namespace implicit_conversion_tests +{ + + template<typename T> + auto a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type() -> void + { + using type_alias = nt::new_type<T, struct conversion_test_1_tag>; + ASSERT(!(is_implicitly_convertible_v<T, type_alias>)); + } + + template<typename T> + auto a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type() -> void + { + using type_alias = nt::new_type<T, struct conversion_test_2_tag, deriving(nt::ImplicitConversion)>; + ASSERT((is_implicitly_convertible_v<T, type_alias>)); + } + +} // namespace implicit_conversion_tests + +inline namespace decay_tests +{ + + template<typename T> + auto decay_on_a_new__type_has_a_return_type_equal_to_the_base_type() -> void + { + using type_alias = nt::new_type<T, struct conversion_test_3_tag>; + ASSERT((std::is_same_v<T, decltype(std::declval<type_alias &>().decay())>)); + } + + template<typename T> + auto decay_on_a_new__type_returns_the_underlying_value() -> void + { + using type_alias = nt::new_type<T, struct conversion_test_4_tag>; + auto data = generate_test_set<T>(2 << 16); + for_each(begin(data), end(data), [](auto & test) { ASSERT_EQUAL_DDT(test.value, type_alias{test.value}.decay(), test.failure); }); + } + +} // namespace decay_tests + +inline namespace decay_noexcept_tests +{ + + auto decay_on_a_new__type_is_noexcept_if_the_base_type_can_be_copied_without_throwing() -> void + { + static_assert(std::is_nothrow_copy_constructible_v<int>, "Sanity check"); + using type_alias = nt::new_type<int, struct conversion_test_5_tag>; + ASSERT(noexcept(type_alias{}.decay())); + } + + auto decay_on_a_new__type_is_not_noexcept_if_the_base_type_can_be_not_copied_without_throwing() -> void + { + struct strange_type + { + strange_type() = default; + strange_type(strange_type const &) noexcept(false) + { + } + }; + + static_assert(!std::is_nothrow_copy_constructible_v<strange_type>, "Sanity check"); + using type_alias = nt::new_type<strange_type, struct conversion_test_6_tag>; + ASSERT(!noexcept(type_alias{}.decay())); + } + +} // namespace decay_noexcept_tests + +inline namespace conversion_operator_noexcept_tests +{ + + auto new__type_conversion_operator_is_noexcept_if_the_base_type_can_be_copied_without_throwing() -> void + { + static_assert(std::is_nothrow_copy_constructible_v<int>, "Sanity check"); + using type_alias = nt::new_type<int, struct conversion_test_5_tag>; + ASSERT(noexcept(static_cast<int>(type_alias{}))); + } + + auto new__type_conversion_operator_is_not_noexcept_if_the_base_type_can_not_be_copied_without_throwing() -> void + { + struct strange_type + { + strange_type() = default; + strange_type(strange_type const &) noexcept(false) + { + } + }; + + static_assert(!std::is_nothrow_copy_constructible_v<strange_type>, "Sanity check"); + using type_alias = nt::new_type<strange_type, struct conversion_test_5_tag>; + ASSERT(!noexcept(static_cast<strange_type>(type_alias{}))); + } + +} // namespace conversion_operator_noexcept_tests + +auto conversion_suite() -> std::pair<cute::suite, std::string> +{ + return {{ + /// Implicit Conversion Tests + KAWAII(a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type<bool>), + KAWAII(a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type<char>), + KAWAII(a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type<int>), + KAWAII(a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type<double>), + KAWAII(a_new__type_without_deriving_implicit_conversion_is_not_implicitly_convertible_to_the_base_type<std::string>), + KAWAII(a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type<bool>), + KAWAII(a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type<char>), + KAWAII(a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type<int>), + KAWAII(a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type<double>), + KAWAII(a_new__type_with_deriving_implicit_conversion_is_implicitly_convertible_to_the_base_type<std::string>), + + /// Decay Tests + KAWAII(decay_on_a_new__type_has_a_return_type_equal_to_the_base_type<bool>), + KAWAII(decay_on_a_new__type_has_a_return_type_equal_to_the_base_type<char>), + KAWAII(decay_on_a_new__type_has_a_return_type_equal_to_the_base_type<int>), + KAWAII(decay_on_a_new__type_has_a_return_type_equal_to_the_base_type<double>), + KAWAII(decay_on_a_new__type_has_a_return_type_equal_to_the_base_type<std::string>), + KAWAII(decay_on_a_new__type_returns_the_underlying_value<char>), + KAWAII(decay_on_a_new__type_returns_the_underlying_value<int>), + KAWAII(decay_on_a_new__type_returns_the_underlying_value<double>), + + /// Decay noexcept Tests + KAWAII(decay_on_a_new__type_is_noexcept_if_the_base_type_can_be_copied_without_throwing), + KAWAII(decay_on_a_new__type_is_not_noexcept_if_the_base_type_can_be_not_copied_without_throwing), + + /// Conversion Operator noexcept Tests + KAWAII(new__type_conversion_operator_is_noexcept_if_the_base_type_can_be_copied_without_throwing), + KAWAII(new__type_conversion_operator_is_not_noexcept_if_the_base_type_can_not_be_copied_without_throwing), + }, + "Conversion Tests"}; +}
\ No newline at end of file diff --git a/test/src/driver.cpp b/test/src/driver.cpp index 22e1ab9..6c1ae7d 100644 --- a/test/src/driver.cpp +++ b/test/src/driver.cpp @@ -1,3 +1,4 @@ +#include "conversion_suite.hpp" #include "derivation_clause_suite.hpp" #include "new_type_constructor_suite.hpp" @@ -27,9 +28,7 @@ auto get_test_selectors(suite_list const & suites) -> std::vector<std::string> for_each(cbegin(suites), cend(suites), [&](auto descriptor) { auto const & [suite, name] = descriptor; - transform(cbegin(suite), cend(suite), std::back_inserter(selectors), [&, name = name](auto test) { - return name + "#" + test.name(); - }); + transform(cbegin(suite), cend(suite), std::back_inserter(selectors), [&, name = name](auto test) { return name + "#" + test.name(); }); }); return selectors; @@ -51,6 +50,7 @@ int main(int argc, char ** argv) auto suites = std::vector{ derivation_clause_suite(), new_type_constructor_suite(), + conversion_suite(), }; auto selectors = get_test_selectors(suites); |
