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