ToStringVariant.tests.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright Catch2 Authors
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // https://www.boost.org/LICENSE_1_0.txt)
  5. // SPDX-License-Identifier: BSL-1.0
  6. #define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
  7. #include <catch2/catch_test_macros.hpp>
  8. #if defined(CATCH_CONFIG_CPP17_VARIANT)
  9. #include <string>
  10. #include <variant>
  11. // We need 2 types with non-trivial copies/moves
  12. struct MyType1 {
  13. MyType1() = default;
  14. [[noreturn]] MyType1(MyType1 const&) { throw 1; }
  15. MyType1& operator=(MyType1 const&) { throw 3; }
  16. };
  17. struct MyType2 {
  18. MyType2() = default;
  19. [[noreturn]] MyType2(MyType2 const&) { throw 2; }
  20. MyType2& operator=(MyType2 const&) { throw 4; }
  21. };
  22. TEST_CASE( "variant<std::monostate>", "[toString][variant][approvals]")
  23. {
  24. using type = std::variant<std::monostate>;
  25. CHECK( "{ }" == ::Catch::Detail::stringify(type{}) );
  26. type value {};
  27. CHECK( "{ }" == ::Catch::Detail::stringify(value) );
  28. CHECK( "{ }" == ::Catch::Detail::stringify(std::get<0>(value)) );
  29. }
  30. TEST_CASE( "variant<int>", "[toString][variant][approvals]")
  31. {
  32. using type = std::variant<int>;
  33. CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
  34. }
  35. TEST_CASE( "variant<float, int>", "[toString][variant][approvals]")
  36. {
  37. using type = std::variant<float, int>;
  38. CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
  39. CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
  40. }
  41. TEST_CASE( "variant -- valueless-by-exception", "[toString][variant][approvals]" ) {
  42. using type = std::variant<MyType1, MyType2>;
  43. type value;
  44. REQUIRE_THROWS_AS(value.emplace<MyType2>(MyType2{}), int);
  45. REQUIRE(value.valueless_by_exception());
  46. CHECK("{valueless variant}" == ::Catch::Detail::stringify(value));
  47. }
  48. TEST_CASE( "variant<string, int>", "[toString][variant][approvals]")
  49. {
  50. using type = std::variant<std::string, int>;
  51. CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
  52. CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
  53. }
  54. TEST_CASE( "variant<variant<float, int>, string>", "[toString][variant][approvals]")
  55. {
  56. using inner = std::variant<MyType1, float, int>;
  57. using type = std::variant<inner, std::string>;
  58. CHECK( "0.5f" == ::Catch::Detail::stringify(type{0.5f}) );
  59. CHECK( "0" == ::Catch::Detail::stringify(type{0}) );
  60. CHECK( "\"foo\"" == ::Catch::Detail::stringify(type{"foo"}) );
  61. SECTION("valueless nested variant") {
  62. type value = inner{0.5f};
  63. REQUIRE( std::holds_alternative<inner>(value) );
  64. REQUIRE( std::holds_alternative<float>(std::get<inner>(value)) );
  65. REQUIRE_THROWS_AS( std::get<0>(value).emplace<MyType1>(MyType1{}), int );
  66. // outer variant is still valid and contains inner
  67. REQUIRE( std::holds_alternative<inner>(value) );
  68. // inner variant is valueless
  69. REQUIRE( std::get<inner>(value).valueless_by_exception() );
  70. CHECK( "{valueless variant}" == ::Catch::Detail::stringify(value) );
  71. }
  72. }
  73. TEST_CASE( "variant<nullptr,int,const char *>", "[toString][variant][approvals]" )
  74. {
  75. using type = std::variant<std::nullptr_t,int,const char *>;
  76. CHECK( "nullptr" == ::Catch::Detail::stringify(type{nullptr}) );
  77. CHECK( "42" == ::Catch::Detail::stringify(type{42}) );
  78. CHECK( "\"Catch me\"" == ::Catch::Detail::stringify(type{"Catch me"}) );
  79. }
  80. #endif // CATCH_INTERNAL_CONFIG_CPP17_VARIANT