nonowning_string.cpp (8135B)
1 #include "libshit/nonowning_string.hpp" 2 3 #include "libshit/doctest.hpp" 4 5 namespace Libshit 6 { 7 using namespace std::string_literals; 8 TEST_SUITE_BEGIN("Libshit::NonowningString"); 9 10 template <typename T> 11 constexpr static bool IsSV = std::is_same_v<T, StringView>; 12 template <typename T> 13 constexpr static bool IsNS = std::is_same_v<T, NonowningString>; 14 15 TEST_CASE_TEMPLATE("NonowningString", T, StringView, NonowningString) 16 { 17 static_assert(T::ZERO_TERMINATED == IsNS<T>); 18 19 SUBCASE("construct") 20 { 21 T{}; // default 22 T{nullptr}; // not braindead 23 T{static_cast<const char*>(nullptr)}; // not capnp level braindead 24 T{"foo"}; // string literal 25 char buf[] = "123"; 26 T{buf}; // zero terminated 27 T{buf, 3}; 28 if constexpr (IsSV<T>) T{buf, 1}; 29 T{buf, buf+3}; 30 T{"abcd"s}; 31 } 32 SUBCASE("operations") 33 { 34 char buf[8] = "foobar"; 35 if (IsSV<T>) buf[6]= 'E'; 36 T t{buf, 6}; 37 38 SUBCASE("iterators") 39 { 40 CHECK(&*t.begin() == buf); 41 CHECK(&*t.cbegin() == buf); 42 CHECK(&*t.end() == buf+6); 43 CHECK(&*t.cend() == buf+6); 44 CHECK(*t.rbegin() == 'r'); 45 CHECK(*t.crbegin() == 'r'); 46 CHECK(*--t.rend() == 'f'); 47 CHECK(*--t.crend() == 'f'); 48 } 49 50 SUBCASE("index") 51 { 52 CHECK(&t[0] == buf); 53 CHECK(&t[3] == buf+3); 54 static_assert(std::is_same_v<decltype(t[0]), const char&>); 55 CHECK(&t.at(0) == buf); 56 CHECK(&t.at(4) == buf+4); 57 CHECK_THROWS(t.at(6)); 58 static_assert(std::is_same_v<decltype(t.at(0)), const char&>); 59 } 60 61 SUBCASE("access") 62 { 63 CHECK(&t.front() == buf); 64 CHECK(&t.back() == buf+5); 65 static_assert(std::is_same_v<decltype(t.front()), const char&>); 66 static_assert(std::is_same_v<decltype(t.back()), const char&>); 67 68 CHECK(t.data() == buf); 69 static_assert(std::is_same_v<decltype(t.data()), const char*>); 70 if constexpr (IsNS<T>) 71 { 72 CHECK(t.c_str() == buf); 73 static_assert(std::is_same_v<decltype(t.c_str()), const char*>); 74 } 75 } 76 77 SUBCASE("length") 78 { 79 CHECK(t.size() == 6); CHECK(t.length() == 6); 80 CHECK(!t.empty()); 81 82 T empty; 83 CHECK(empty.size() == 0); CHECK(empty.length() == 0); 84 CHECK(empty.empty()); 85 } 86 87 SUBCASE("remove") 88 { 89 T t_pr{t}; t_pr.remove_prefix(2); 90 CHECK(t_pr == T{buf+2, buf+6}); 91 if constexpr (IsSV<T>) 92 { 93 T t_sf{t}; t_sf.remove_suffix(3); 94 CHECK(t_sf == T{buf, 3}); 95 } 96 97 t.swap(t_pr); 98 CHECK(t == T{buf+2, buf+6}); 99 CHECK(t_pr == T{buf, buf+6}); 100 } 101 102 SUBCASE("copy") 103 { 104 char dst[10] = {'0','1','2','3','4','5','6','7','8','9'}; 105 REQUIRE(t.copy(dst, 4, 1) == 4); 106 CHECK(StringView{dst, 10} == "ooba456789"); 107 REQUIRE(t.copy(dst, 777, 1) == 5); 108 CHECK(StringView{dst, 10} == "oobar56789"); 109 110 CHECK_THROWS(t.copy(dst, 2, 10)); 111 } 112 113 SUBCASE("substr") 114 { 115 auto s = t.substr(1, 3); 116 CHECK(s == StringView{buf+1, 3}); 117 s = t.substr(1, 99); 118 CHECK(s == StringView{buf+1, buf+6}); 119 } 120 121 SUBCASE("compare") 122 { 123 CHECK(t.compare(t) == 0); 124 char less[] = "abcx"; 125 StringView sv_less{less}; 126 NonowningString ns_less{less}; 127 CHECK(t.compare(sv_less) > 0); 128 CHECK(t.compare(ns_less) > 0); 129 CHECK(ns_less.compare(t) < 0); 130 CHECK(sv_less.compare(t) < 0); 131 132 CHECK(t.compare(3, 3, t) < 0); 133 CHECK(t.compare(0, 3, t, 3, 0) > 0); 134 CHECK(sv_less.compare(3,1, t) > 0); 135 CHECK(ns_less.compare(3,1, t) > 0); 136 137 // c_str 138 CHECK(t.compare("foobar") == 0); 139 CHECK(t.compare("foo") > 0); 140 CHECK(t.compare(1,3, "oob") == 0); 141 CHECK(t.compare(0,3, "fooxxx", 3) == 0); 142 } 143 144 SUBCASE("starts/ends_with") 145 { 146 CHECK(t.starts_with(StringView{"foo"})); 147 CHECK(!t.starts_with(StringView{"fob"})); 148 CHECK(t.starts_with(NonowningString{"foo"})); 149 CHECK(!t.starts_with(NonowningString{"fob"})); 150 CHECK(t.starts_with('f')); 151 CHECK(!t.starts_with('r')); 152 CHECK(t.starts_with("foo")); 153 CHECK(!t.starts_with("fob")); 154 155 CHECK(t.ends_with(StringView{"bar"})); 156 CHECK(!t.ends_with(StringView{"gar"})); 157 CHECK(t.ends_with(NonowningString{"bar"})); 158 CHECK(!t.ends_with(NonowningString{"gar"})); 159 CHECK(t.ends_with('r')); 160 CHECK(!t.ends_with('f')); 161 CHECK(t.ends_with("bar")); 162 CHECK(!t.ends_with("gar")); 163 } 164 165 SUBCASE("find") 166 { 167 CHECK(t.find("") == 0); 168 CHECK(t.find(T{"foo"}) == 0); 169 CHECK(t.find(T{"foo"}, 1) == T::npos); 170 CHECK(t.find("foo") == 0); 171 CHECK(t.find("oo") == 1); 172 CHECK(t.find("oo", 1) == 1); 173 CHECK(t.find("oo", 2) == T::npos); 174 CHECK(t.find("o") == 1); 175 CHECK(t.find("o", 1) == 1); 176 CHECK(t.find("o", 2) == 2); 177 CHECK(t.find("o", 3) == T::npos); 178 CHECK(t.find('o') == 1); 179 CHECK(t.find('o', 1) == 1); 180 CHECK(t.find('o', 2) == 2); 181 CHECK(t.find('o', 3) == T::npos); 182 CHECK(t.find('r') == 5); 183 CHECK(t.find("obx", 0, 2) == 2); 184 CHECK(t.find("foobar") == 0); 185 CHECK(t.find("bar") == 3); 186 CHECK(t.substr(0, 3).find("foob") == T::npos); 187 188 CHECK(t.rfind("o") == 2); 189 CHECK(t.rfind("o", 2) == 2); 190 CHECK(t.rfind("o", 1) == 1); 191 CHECK(t.rfind("o", 0) == T::npos); 192 CHECK(t.rfind('o') == 2); 193 CHECK(t.rfind('o', 2) == 2); 194 CHECK(t.rfind('o', 1) == 1); 195 CHECK(t.rfind('o', 0) == T::npos); 196 CHECK(t.rfind("foobar") == 0); 197 CHECK(t.rfind("bar") == 3); 198 CHECK(t.substr(0, 3).rfind("foob") == T::npos); 199 200 CHECK(t.find_first_of("") == T::npos); 201 CHECK(t.find_first_of("af") == 0); 202 CHECK(t.find_first_of("af", 1) == 4); 203 CHECK(t.find_first_of("af", 5) == T::npos); 204 CHECK(t.find_first_of("r") == 5); 205 CHECK(t.find_first_of('r') == 5); 206 CHECK(t.find_first_of("xyzr") == 5); 207 CHECK(t.substr(0, 3).find_first_of("b") == T::npos); 208 CHECK(t.find_last_of("") == T::npos); 209 CHECK(t.find_last_of('r') == 5); 210 CHECK(t.find_last_of("r") == 5); 211 CHECK(t.find_last_of('f') == 0); 212 CHECK(t.find_last_of("f") == 0); 213 CHECK(t.find_last_of("af") == 4); 214 CHECK(t.find_last_of("af", 3) == 0); 215 216 CHECK(t.find_first_not_of('f') == 1); 217 CHECK(t.find_first_not_of("f") == 1); 218 CHECK(t.find_first_not_of("of") == 3); 219 CHECK(t.find_first_not_of("aofrb") == T::npos); 220 CHECK(t.find_first_not_of("x", 5) == 5); 221 CHECK(t.find_first_not_of("r", 5) == T::npos); 222 CHECK(t.find_first_not_of("fbar") == 1); 223 CHECK(t.find_last_not_of('f') == 5); 224 CHECK(t.find_last_not_of("f") == 5); 225 CHECK(t.find_last_not_of('r') == 4); 226 CHECK(t.find_last_not_of("r") == 4); 227 CHECK(t.find_last_not_of("ar") == 3); 228 CHECK(t.find_last_not_of("aofrb") == T::npos); 229 CHECK(t.find_last_not_of("x", 0) == 0); 230 CHECK(t.find_last_not_of("f", 0) == T::npos); 231 CHECK(t.find_last_not_of("fbar") == 2); 232 } 233 234 SUBCASE("compare") 235 { 236 CHECK(t == t); CHECK(!(t != t)); CHECK(!(t < t)); CHECK(!(t > t)); 237 CHECK(t <= t); CHECK(t >= t); 238 239 T t2{"foobar", 6}; 240 CHECK(t == t2); CHECK(!(t != t2)); CHECK(!(t < t2)); CHECK(!(t > t2)); 241 CHECK(t <= t2); CHECK(t >= t2); 242 243 T t3{"abc"}; 244 CHECK(!(t == t3)); CHECK(t != t3); CHECK(!(t < t3)); CHECK(t > t3); 245 CHECK(!(t <= t3)); CHECK(t >= t3); 246 247 std::string s{"abc"}; 248 CHECK(!(t == s)); CHECK(t != s); CHECK(!(t < s)); CHECK(t > s); 249 CHECK(!(t <= s)); CHECK(t >= s); 250 } 251 252 SUBCASE("string plus") 253 { 254 std::string str = "abc"; 255 str += t; 256 CHECK(str == "abcfoobar"); 257 } 258 } 259 } 260 261 TEST_SUITE_END(); 262 }