2017-11-13 15:38:52 +00:00
#include "internal/catch_stringref.h"
2017-06-29 11:18:14 +01:00
#include "catch.hpp"
2017-06-29 11:43:20 +01:00
#include <cstring>
2017-06-29 11:18:14 +01:00
namespace Catch {
// Implementation of test accessors
struct StringRefTestAccess {
static auto isOwned ( StringRef const & stringRef ) -> bool {
return stringRef . isOwned ();
}
static auto isSubstring ( StringRef const & stringRef ) -> bool {
return stringRef . isSubstring ();
}
};
2018-07-02 11:13:07 +02:00
namespace {
2017-06-29 11:18:14 +01:00
auto isOwned ( StringRef const & stringRef ) -> bool {
return StringRefTestAccess :: isOwned ( stringRef );
}
auto isSubstring ( StringRef const & stringRef ) -> bool {
return StringRefTestAccess :: isSubstring ( stringRef );
}
2018-07-02 11:13:07 +02:00
} // end anonymous namespace
2017-06-29 11:18:14 +01:00
} // namespace Catch
2018-02-08 13:10:12 +01:00
TEST_CASE ( "StringRef" , "[Strings][StringRef]" ) {
2017-06-29 11:18:14 +01:00
using Catch :: StringRef ;
2018-07-02 11:13:07 +02:00
using Catch :: isOwned ; using Catch :: isSubstring ;
2017-08-14 09:04:14 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "Empty string" ) {
StringRef empty ;
REQUIRE ( empty . empty () );
REQUIRE ( empty . size () == 0 );
REQUIRE ( std :: strcmp ( empty . c_str (), "" ) == 0 );
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "From string literal" ) {
StringRef s = "hello" ;
REQUIRE ( s . empty () == false );
REQUIRE ( s . size () == 5 );
REQUIRE ( isSubstring ( s ) == false );
2018-02-08 13:10:12 +01:00
2018-02-28 22:05:01 +01:00
auto rawChars = s . currentData ();
2017-06-29 11:18:14 +01:00
REQUIRE ( std :: strcmp ( rawChars , "hello" ) == 0 );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "c_str() does not cause copy" ) {
REQUIRE ( isOwned ( s ) == false );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
REQUIRE ( s . c_str () == rawChars );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
REQUIRE ( isOwned ( s ) == false );
}
}
SECTION ( "From sub-string" ) {
StringRef original = StringRef ( "original string" ). substr ( 0 , 8 );
REQUIRE ( original == "original" );
REQUIRE ( isSubstring ( original ) );
REQUIRE ( isOwned ( original ) == false );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
original . c_str (); // Forces it to take ownership
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
REQUIRE ( isOwned ( original ) );
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "Substrings" ) {
StringRef s = "hello world!" ;
StringRef ss = s . substr ( 0 , 5 );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "zero-based substring" ) {
REQUIRE ( ss . empty () == false );
REQUIRE ( ss . size () == 5 );
REQUIRE ( std :: strcmp ( ss . c_str (), "hello" ) == 0 );
REQUIRE ( ss == "hello" );
}
SECTION ( "c_str() causes copy" ) {
REQUIRE ( isSubstring ( ss ) );
REQUIRE ( isOwned ( ss ) == false );
2018-02-08 13:10:12 +01:00
2018-02-28 22:05:01 +01:00
auto rawChars = ss . currentData ();
REQUIRE ( rawChars == s . currentData () ); // same pointer value
2017-06-29 11:18:14 +01:00
REQUIRE ( ss . c_str () != rawChars );
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
REQUIRE ( isOwned ( ss ) );
2018-02-08 13:10:12 +01:00
2019-05-18 17:54:06 +01:00
SECTION ( "Self-assignment after substring" ) {
2019-05-20 23:56:55 +01:00
ss = *& ss ; // the *& are there to suppress warnings (see: "Improvements to Clang's diagnostics" in https://rev.ng/gitlab/revng-bar-2019/clang/raw/master/docs/ReleaseNotes.rst)
2019-05-21 00:04:19 +01:00
REQUIRE ( isOwned ( ss ) == false );
REQUIRE ( ss == "hello" );
REQUIRE ( rawChars == ss . currentData () ); // same pointer value
2019-05-18 17:54:06 +01:00
}
2017-06-29 11:18:14 +01:00
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "non-zero-based substring" ) {
ss = s . substr ( 6 , 6 );
REQUIRE ( ss . size () == 6 );
REQUIRE ( std :: strcmp ( ss . c_str (), "world!" ) == 0 );
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "Pointer values of full refs should match" ) {
StringRef s2 = s ;
REQUIRE ( s . c_str () == s2 . c_str () );
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "Pointer values of substring refs should not match" ) {
REQUIRE ( s . c_str () != ss . c_str () );
}
}
2018-02-08 13:10:12 +01:00
2017-06-29 11:18:14 +01:00
SECTION ( "Comparisons" ) {
REQUIRE ( StringRef ( "hello" ) == StringRef ( "hello" ) );
REQUIRE ( StringRef ( "hello" ) != StringRef ( "cello" ) );
}
2017-08-14 08:39:14 +01:00
SECTION ( "from std::string" ) {
std :: string stdStr = "a standard string" ;
SECTION ( "implicitly constructed" ) {
StringRef sr = stdStr ;
REQUIRE ( sr == "a standard string" );
REQUIRE ( sr . size () == stdStr . size () );
}
SECTION ( "explicitly constructed" ) {
StringRef sr ( stdStr );
REQUIRE ( sr == "a standard string" );
REQUIRE ( sr . size () == stdStr . size () );
}
SECTION ( "assigned" ) {
StringRef sr ;
sr = stdStr ;
REQUIRE ( sr == "a standard string" );
REQUIRE ( sr . size () == stdStr . size () );
}
}
SECTION ( "to std::string" ) {
StringRef sr = "a stringref" ;
SECTION ( "implicitly constructed" ) {
std :: string stdStr = sr ;
REQUIRE ( stdStr == "a stringref" );
REQUIRE ( stdStr . size () == sr . size () );
}
SECTION ( "explicitly constructed" ) {
std :: string stdStr ( sr );
REQUIRE ( stdStr == "a stringref" );
REQUIRE ( stdStr . size () == sr . size () );
}
SECTION ( "assigned" ) {
std :: string stdStr ;
stdStr = sr ;
REQUIRE ( stdStr == "a stringref" );
REQUIRE ( stdStr . size () == sr . size () );
}
}
2018-02-08 13:10:12 +01:00
SECTION ( "Counting utf-8 codepoints" ) {
StringRef ascii = "just a plain old boring ascii string..." ;
REQUIRE ( ascii . numberOfCharacters () == ascii . size ());
StringRef simpleu8 = u8 "Trocha češtiny nikoho nezabila" ;
REQUIRE ( simpleu8 . numberOfCharacters () == 30 );
StringRef emojis = u8 "Here be 👾" ;
REQUIRE ( emojis . numberOfCharacters () == 9 );
}
2017-06-29 11:18:14 +01:00
}
2017-11-13 16:03:27 +00:00
2018-02-08 13:10:12 +01:00
TEST_CASE ( "replaceInPlace" , "[Strings][StringManip]" ) {
2017-11-13 16:03:27 +00:00
std :: string letters = "abcdefcg" ;
SECTION ( "replace single char" ) {
CHECK ( Catch :: replaceInPlace ( letters , "b" , "z" ) );
CHECK ( letters == "azcdefcg" );
}
SECTION ( "replace two chars" ) {
CHECK ( Catch :: replaceInPlace ( letters , "c" , "z" ) );
CHECK ( letters == "abzdefzg" );
}
SECTION ( "replace first char" ) {
CHECK ( Catch :: replaceInPlace ( letters , "a" , "z" ) );
CHECK ( letters == "zbcdefcg" );
}
SECTION ( "replace last char" ) {
CHECK ( Catch :: replaceInPlace ( letters , "g" , "z" ) );
CHECK ( letters == "abcdefcz" );
}
SECTION ( "replace all chars" ) {
CHECK ( Catch :: replaceInPlace ( letters , letters , "replaced" ) );
CHECK ( letters == "replaced" );
}
SECTION ( "replace no chars" ) {
CHECK_FALSE ( Catch :: replaceInPlace ( letters , "x" , "z" ) );
CHECK ( letters == letters );
}
SECTION ( "escape '" ) {
std :: string s = "didn't" ;
CHECK ( Catch :: replaceInPlace ( s , "'" , "|'" ) );
CHECK ( s == "didn|'t" );
}
}
2019-04-04 15:55:46 +01:00
TEST_CASE ( "splitString" , "[Strings]" ) {
using namespace Catch :: Matchers ;
2019-04-21 20:03:44 +03:00
using Catch :: splitStringRef ;
using Catch :: StringRef ;
2019-04-04 15:55:46 +01:00
2019-04-21 20:03:44 +03:00
CHECK_THAT ( splitStringRef ( "" , ',' ), Equals ( std :: vector < StringRef > () ) );
CHECK_THAT ( splitStringRef ( "abc" , ',' ), Equals ( std :: vector < StringRef > { "abc" } ) );
CHECK_THAT ( splitStringRef ( "abc,def" , ',' ), Equals ( std :: vector < StringRef > { "abc" , "def" } ) );
2019-04-04 15:55:46 +01:00
}