• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "internal/catch_stringref.h"
2 
3 #include "catch.hpp"
4 
5 #include <cstring>
6 
7 namespace Catch {
8 
9     // Implementation of test accessors
10     struct StringRefTestAccess {
isOwnedCatch::StringRefTestAccess11         static auto isOwned( StringRef const& stringRef ) -> bool {
12             return stringRef.isOwned();
13         }
isSubstringCatch::StringRefTestAccess14         static auto isSubstring( StringRef const& stringRef ) -> bool {
15             return stringRef.isSubstring();
16         }
17     };
18 
19 
20     namespace {
isOwned(StringRef const & stringRef)21     auto isOwned( StringRef const& stringRef ) -> bool {
22         return StringRefTestAccess::isOwned( stringRef );
23     }
isSubstring(StringRef const & stringRef)24     auto isSubstring( StringRef const& stringRef ) -> bool {
25         return StringRefTestAccess::isSubstring( stringRef );
26     }
27     } // end anonymous namespace
28 
29 } // namespace Catch
30 
31 TEST_CASE( "StringRef", "[Strings][StringRef]" ) {
32 
33     using Catch::StringRef;
34     using Catch::isOwned; using Catch::isSubstring;
35 
36     SECTION( "Empty string" ) {
37         StringRef empty;
38         REQUIRE( empty.empty() );
39         REQUIRE( empty.size() == 0 );
40         REQUIRE( std::strcmp( empty.c_str(), "" ) == 0 );
41     }
42 
43     SECTION( "From string literal" ) {
44         StringRef s = "hello";
45         REQUIRE( s.empty() == false );
46         REQUIRE( s.size() == 5 );
47         REQUIRE( isSubstring( s ) == false );
48 
49         auto rawChars = s.currentData();
50         REQUIRE( std::strcmp( rawChars, "hello" ) == 0 );
51 
52         SECTION( "c_str() does not cause copy" ) {
53             REQUIRE( isOwned( s ) == false );
54 
55             REQUIRE( s.c_str() == rawChars );
56 
57             REQUIRE( isOwned( s ) == false );
58         }
59     }
60     SECTION( "From sub-string" ) {
61         StringRef original = StringRef( "original string" ).substr(0, 8);
62         REQUIRE( original == "original" );
63         REQUIRE( isSubstring( original ) );
64         REQUIRE( isOwned( original ) == false );
65 
66         original.c_str(); // Forces it to take ownership
67 
68         REQUIRE( isSubstring( original ) == false );
69         REQUIRE( isOwned( original ) );
70     }
71 
72 
73     SECTION( "Substrings" ) {
74         StringRef s = "hello world!";
75         StringRef ss = s.substr(0, 5);
76 
77         SECTION( "zero-based substring" ) {
78             REQUIRE( ss.empty() == false );
79             REQUIRE( ss.size() == 5 );
80             REQUIRE( std::strcmp( ss.c_str(), "hello" ) == 0 );
81             REQUIRE( ss == "hello" );
82         }
83         SECTION( "c_str() causes copy" ) {
84             REQUIRE( isSubstring( ss ) );
85             REQUIRE( isOwned( ss ) == false );
86 
87             auto rawChars = ss.currentData();
88             REQUIRE( rawChars == s.currentData() ); // same pointer value
89             REQUIRE( ss.c_str() != rawChars );
90 
91             REQUIRE( isSubstring( ss ) == false );
92             REQUIRE( isOwned( ss ) );
93 
94             REQUIRE( ss.currentData() != s.currentData() ); // different pointer value
95         }
96 
97         SECTION( "non-zero-based substring") {
98             ss = s.substr( 6, 6 );
99             REQUIRE( ss.size() == 6 );
100             REQUIRE( std::strcmp( ss.c_str(), "world!" ) == 0 );
101         }
102 
103         SECTION( "Pointer values of full refs should match" ) {
104             StringRef s2 = s;
105             REQUIRE( s.c_str() == s2.c_str() );
106         }
107 
108         SECTION( "Pointer values of substring refs should not match" ) {
109             REQUIRE( s.c_str() != ss.c_str() );
110         }
111     }
112 
113     SECTION( "Comparisons" ) {
114         REQUIRE( StringRef("hello") == StringRef("hello") );
115         REQUIRE( StringRef("hello") != StringRef("cello") );
116     }
117 
118     SECTION( "from std::string" ) {
119         std::string stdStr = "a standard string";
120 
121         SECTION( "implicitly constructed" ) {
122             StringRef sr = stdStr;
123             REQUIRE( sr == "a standard string" );
124             REQUIRE( sr.size() == stdStr.size() );
125         }
126         SECTION( "explicitly constructed" ) {
127             StringRef sr( stdStr );
128             REQUIRE( sr == "a standard string" );
129             REQUIRE( sr.size() == stdStr.size() );
130         }
131         SECTION( "assigned" ) {
132             StringRef sr;
133             sr = stdStr;
134             REQUIRE( sr == "a standard string" );
135             REQUIRE( sr.size() == stdStr.size() );
136         }
137     }
138 
139     SECTION( "to std::string" ) {
140         StringRef sr = "a stringref";
141 
142         SECTION( "implicitly constructed" ) {
143             std::string stdStr = sr;
144             REQUIRE( stdStr == "a stringref" );
145             REQUIRE( stdStr.size() == sr.size() );
146         }
147         SECTION( "explicitly constructed" ) {
148             std::string stdStr( sr );
149             REQUIRE( stdStr == "a stringref" );
150             REQUIRE( stdStr.size() == sr.size() );
151         }
152         SECTION( "assigned" ) {
153             std::string stdStr;
154             stdStr = sr;
155             REQUIRE( stdStr == "a stringref" );
156             REQUIRE( stdStr.size() == sr.size() );
157         }
158     }
159 
160     SECTION( "Counting utf-8 codepoints" ) {
161         StringRef ascii = "just a plain old boring ascii string...";
162         REQUIRE(ascii.numberOfCharacters() == ascii.size());
163 
164         StringRef simpleu8 = u8"Trocha češtiny nikoho nezabila";
165         REQUIRE(simpleu8.numberOfCharacters() == 30);
166 
167         StringRef emojis = u8"Here be ��";
168         REQUIRE(emojis.numberOfCharacters() == 9);
169     }
170 
171 }
172 
173 TEST_CASE( "replaceInPlace", "[Strings][StringManip]" ) {
174     std::string letters = "abcdefcg";
175     SECTION( "replace single char" ) {
176         CHECK( Catch::replaceInPlace( letters, "b", "z" ) );
177         CHECK( letters == "azcdefcg" );
178     }
179     SECTION( "replace two chars" ) {
180         CHECK( Catch::replaceInPlace( letters, "c", "z" ) );
181         CHECK( letters == "abzdefzg" );
182     }
183     SECTION( "replace first char" ) {
184         CHECK( Catch::replaceInPlace( letters, "a", "z" ) );
185         CHECK( letters == "zbcdefcg" );
186     }
187     SECTION( "replace last char" ) {
188         CHECK( Catch::replaceInPlace( letters, "g", "z" ) );
189         CHECK( letters == "abcdefcz" );
190     }
191     SECTION( "replace all chars" ) {
192         CHECK( Catch::replaceInPlace( letters, letters, "replaced" ) );
193         CHECK( letters == "replaced" );
194     }
195     SECTION( "replace no chars" ) {
196         CHECK_FALSE( Catch::replaceInPlace( letters, "x", "z" ) );
197         CHECK( letters == letters );
198     }
199     SECTION( "escape '" ) {
200         std::string s = "didn't";
201         CHECK( Catch::replaceInPlace( s, "'", "|'" ) );
202         CHECK( s == "didn|'t" );
203     }
204 }
205