1 /*
2  *  Created by Martin on 17/02/2017.
3  *
4  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
5  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  */
7 
8 #define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
9 #include "catch.hpp"
10 
11 #include <map>
12 #include <set>
13 
14 TEST_CASE( "Character pretty printing" ){
15     SECTION("Specifically escaped"){
16         char tab = '\t';
17         char newline = '\n';
18         char carr_return = '\r';
19         char form_feed = '\f';
20         CHECK(tab == '\t');
21         CHECK(newline == '\n');
22         CHECK(carr_return == '\r');
23         CHECK(form_feed == '\f');
24     }
25     SECTION("General chars"){
26         char space = ' ';
27         CHECK(space == ' ');
28         char chars[] = {'a', 'z', 'A', 'Z'};
29         for (int i = 0; i < 4; ++i){
30             char c = chars[i];
31             REQUIRE(c == chars[i]);
32         }
33     }
34     SECTION("Low ASCII"){
35         char null_terminator = '\0';
36         CHECK(null_terminator == '\0');
37         for (int i = 2; i < 6; ++i){
38             char c = static_cast<char>(i);
39             REQUIRE(c == i);
40         }
41     }
42 }
43 
44 
45 TEST_CASE( "Capture and info messages" ) {
46     SECTION("Capture should stringify like assertions") {
47         int i = 2;
48         CAPTURE(i);
49         REQUIRE(true);
50     }
51     SECTION("Info should NOT stringify the way assertions do") {
52         int i = 3;
53         INFO(i);
54         REQUIRE(true);
55     }
56 }
57 
58 TEST_CASE( "std::map is convertible string", "[toString]" ) {
59 
60     SECTION( "empty" ) {
61         std::map<std::string, int> emptyMap;
62 
63         REQUIRE( Catch::Detail::stringify( emptyMap ) == "{  }" );
64     }
65 
66     SECTION( "single item" ) {
67         std::map<std::string, int> map = { { "one", 1 } };
68 
69         REQUIRE( Catch::Detail::stringify( map ) == "{ { \"one\", 1 } }" );
70     }
71 
72     SECTION( "several items" ) {
73         std::map<std::string, int> map = {
74                 { "abc", 1 },
75                 { "def", 2 },
76                 { "ghi", 3 }
77             };
78 
79         REQUIRE( Catch::Detail::stringify( map ) == "{ { \"abc\", 1 }, { \"def\", 2 }, { \"ghi\", 3 } }" );
80     }
81 }
82 
83 TEST_CASE( "std::set is convertible string", "[toString]" ) {
84 
85     SECTION( "empty" ) {
86         std::set<std::string> emptySet;
87 
88         REQUIRE( Catch::Detail::stringify( emptySet ) == "{  }" );
89     }
90 
91     SECTION( "single item" ) {
92         std::set<std::string> set = { "one" };
93 
94         REQUIRE( Catch::Detail::stringify( set ) == "{ \"one\" }" );
95     }
96 
97     SECTION( "several items" ) {
98         std::set<std::string> set = { "abc", "def", "ghi" };
99 
100         REQUIRE( Catch::Detail::stringify( set ) == "{ \"abc\", \"def\", \"ghi\" }" );
101     }
102 }
103 
104 TEST_CASE("Static arrays are convertible to string", "[toString]") {
105     SECTION("Single item") {
106         int singular[1] = { 1 };
107         REQUIRE(Catch::Detail::stringify(singular) == "{ 1 }");
108     }
109     SECTION("Multiple") {
110         int arr[3] = { 3, 2, 1 };
111         REQUIRE(Catch::Detail::stringify(arr) == "{ 3, 2, 1 }");
112     }
113     SECTION("Non-trivial inner items") {
114         std::vector<std::string> arr[2] = { {"1:1", "1:2", "1:3"}, {"2:1", "2:2"} };
115         REQUIRE(Catch::Detail::stringify(arr) == R"({ { "1:1", "1:2", "1:3" }, { "2:1", "2:2" } })");
116     }
117 }
118 
119 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
120 
121 TEST_CASE("String views are stringified like other strings", "[toString][approvals]") {
122     std::string_view view{"abc"};
123     CHECK(Catch::Detail::stringify(view) == R"("abc")");
124 
125     std::string_view arr[] { view };
126     CHECK(Catch::Detail::stringify(arr) == R"({ "abc" })");
127 }
128 
129 #endif
130 
131 namespace {
132 
133 struct WhatException : std::exception {
what__anon7252e3e80111::WhatException134     char const* what() const noexcept override {
135         return "This exception has overriden what() method";
136     }
137     ~WhatException() override;
138 };
139 
140 struct OperatorException : std::exception {
141     ~OperatorException() override;
142 };
143 
operator <<(std::ostream & out,OperatorException const &)144 std::ostream& operator<<(std::ostream& out, OperatorException const&) {
145     out << "OperatorException";
146     return out;
147 }
148 
149 struct StringMakerException : std::exception {
150     ~StringMakerException() override;
151 };
152 
153 } // end anonymous namespace
154 
155 namespace Catch {
156 template <>
157 struct StringMaker<StringMakerException> {
convertCatch::StringMaker158     static std::string convert(StringMakerException const&) {
159         return "StringMakerException";
160     }
161 };
162 }
163 
164 // Avoid -Wweak-tables
165 WhatException::~WhatException() = default;
166 OperatorException::~OperatorException() = default;
167 StringMakerException::~StringMakerException() = default;
168 
169 
170 
171 
172 TEST_CASE("Exception as a value (e.g. in REQUIRE_THROWS_MATCHES) can be stringified", "[toString][exception]") {
173     REQUIRE(::Catch::Detail::stringify(WhatException{}) == "This exception has overriden what() method");
174     REQUIRE(::Catch::Detail::stringify(OperatorException{}) == "OperatorException");
175     REQUIRE(::Catch::Detail::stringify(StringMakerException{}) == "StringMakerException");
176 }
177