string-test.c++ (12137B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "string.h" 23 #include <kj/compat/gtest.h> 24 #include <string> 25 #include "vector.h" 26 #include <locale.h> 27 28 namespace kj { 29 namespace _ { // private 30 namespace { 31 32 TEST(String, Str) { 33 EXPECT_EQ("foobar", str("foo", "bar")); 34 EXPECT_EQ("1 2 3 4", str(1, " ", 2u, " ", 3l, " ", 4ll)); 35 EXPECT_EQ("1.5 foo 1e15 bar -3", str(1.5f, " foo ", 1e15, " bar ", -3)); 36 EXPECT_EQ("foo", str('f', 'o', 'o')); 37 EXPECT_EQ("123 234 -123 e7", 38 str((int8_t)123, " ", (uint8_t)234, " ", (int8_t)-123, " ", hex((uint8_t)0xe7))); 39 EXPECT_EQ("-128 -32768 -2147483648 -9223372036854775808", 40 str((signed char)-128, ' ', (signed short)-32768, ' ', 41 ((int)-2147483647) - 1, ' ', ((long long)-9223372036854775807ll) - 1)) 42 EXPECT_EQ("ff ffff ffffffff ffffffffffffffff", 43 str(hex((uint8_t)0xff), ' ', hex((uint16_t)0xffff), ' ', hex((uint32_t)0xffffffffu), ' ', 44 hex((uint64_t)0xffffffffffffffffull))); 45 46 char buf[3] = {'f', 'o', 'o'}; 47 ArrayPtr<char> a = buf; 48 ArrayPtr<const char> ca = a; 49 Vector<char> v; 50 v.addAll(a); 51 FixedArray<char, 3> f; 52 memcpy(f.begin(), buf, 3); 53 54 EXPECT_EQ("foo", str(a)); 55 EXPECT_EQ("foo", str(ca)); 56 EXPECT_EQ("foo", str(v)); 57 EXPECT_EQ("foo", str(f)); 58 EXPECT_EQ("foo", str(mv(a))); 59 EXPECT_EQ("foo", str(mv(ca))); 60 EXPECT_EQ("foo", str(mv(v))); 61 EXPECT_EQ("foo", str(mv(f))); 62 } 63 64 TEST(String, Nullptr) { 65 EXPECT_EQ(String(nullptr), ""); 66 EXPECT_EQ(StringPtr(String(nullptr)).size(), 0u); 67 EXPECT_EQ(StringPtr(String(nullptr))[0], '\0'); 68 } 69 70 TEST(String, StartsEndsWith) { 71 EXPECT_TRUE(StringPtr("foobar").startsWith("foo")); 72 EXPECT_FALSE(StringPtr("foobar").startsWith("bar")); 73 EXPECT_FALSE(StringPtr("foobar").endsWith("foo")); 74 EXPECT_TRUE(StringPtr("foobar").endsWith("bar")); 75 76 EXPECT_FALSE(StringPtr("fo").startsWith("foo")); 77 EXPECT_FALSE(StringPtr("fo").endsWith("foo")); 78 79 EXPECT_TRUE(StringPtr("foobar").startsWith("")); 80 EXPECT_TRUE(StringPtr("foobar").endsWith("")); 81 } 82 83 TEST(String, parseAs) { 84 EXPECT_EQ(StringPtr("0").parseAs<double>(), 0.0); 85 EXPECT_EQ(StringPtr("0.0").parseAs<double>(), 0.0); 86 EXPECT_EQ(StringPtr("1").parseAs<double>(), 1.0); 87 EXPECT_EQ(StringPtr("1.0").parseAs<double>(), 1.0); 88 EXPECT_EQ(StringPtr("1e100").parseAs<double>(), 1e100); 89 EXPECT_EQ(StringPtr("inf").parseAs<double>(), inf()); 90 EXPECT_EQ(StringPtr("infinity").parseAs<double>(), inf()); 91 EXPECT_EQ(StringPtr("INF").parseAs<double>(), inf()); 92 EXPECT_EQ(StringPtr("INFINITY").parseAs<double>(), inf()); 93 EXPECT_EQ(StringPtr("1e100000").parseAs<double>(), inf()); 94 EXPECT_EQ(StringPtr("-inf").parseAs<double>(), -inf()); 95 EXPECT_EQ(StringPtr("-infinity").parseAs<double>(), -inf()); 96 EXPECT_EQ(StringPtr("-INF").parseAs<double>(), -inf()); 97 EXPECT_EQ(StringPtr("-INFINITY").parseAs<double>(), -inf()); 98 EXPECT_EQ(StringPtr("-1e100000").parseAs<double>(), -inf()); 99 EXPECT_TRUE(isNaN(StringPtr("nan").parseAs<double>())); 100 EXPECT_TRUE(isNaN(StringPtr("NAN").parseAs<double>())); 101 EXPECT_TRUE(isNaN(StringPtr("NaN").parseAs<double>())); 102 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<double>()); 103 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<double>()); 104 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<double>()); 105 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<double>()); 106 107 EXPECT_EQ(StringPtr("1").parseAs<float>(), 1.0); 108 109 EXPECT_EQ(StringPtr("1").parseAs<int64_t>(), 1); 110 EXPECT_EQ(StringPtr("9223372036854775807").parseAs<int64_t>(), 9223372036854775807LL); 111 EXPECT_EQ(StringPtr("-9223372036854775808").parseAs<int64_t>(), -9223372036854775808ULL); 112 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("9223372036854775808").parseAs<int64_t>()); 113 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-9223372036854775809").parseAs<int64_t>()); 114 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<int64_t>()); 115 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<int64_t>()); 116 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<int64_t>()); 117 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<int64_t>()); 118 EXPECT_EQ(StringPtr("010").parseAs<int64_t>(), 10); 119 EXPECT_EQ(StringPtr("0010").parseAs<int64_t>(), 10); 120 EXPECT_EQ(StringPtr("0x10").parseAs<int64_t>(), 16); 121 EXPECT_EQ(StringPtr("0X10").parseAs<int64_t>(), 16); 122 EXPECT_EQ(StringPtr("-010").parseAs<int64_t>(), -10); 123 EXPECT_EQ(StringPtr("-0x10").parseAs<int64_t>(), -16); 124 EXPECT_EQ(StringPtr("-0X10").parseAs<int64_t>(), -16); 125 126 EXPECT_EQ(StringPtr("1").parseAs<uint64_t>(), 1); 127 EXPECT_EQ(StringPtr("0").parseAs<uint64_t>(), 0); 128 EXPECT_EQ(StringPtr("18446744073709551615").parseAs<uint64_t>(), 18446744073709551615ULL); 129 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint64_t>()); 130 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("18446744073709551616").parseAs<uint64_t>()); 131 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("").parseAs<uint64_t>()); 132 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("a").parseAs<uint64_t>()); 133 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("1a").parseAs<uint64_t>()); 134 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("not contain valid", StringPtr("+-1").parseAs<uint64_t>()); 135 136 EXPECT_EQ(StringPtr("1").parseAs<int32_t>(), 1); 137 EXPECT_EQ(StringPtr("2147483647").parseAs<int32_t>(), 2147483647); 138 EXPECT_EQ(StringPtr("-2147483648").parseAs<int32_t>(), -2147483648); 139 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("2147483648").parseAs<int32_t>()); 140 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-2147483649").parseAs<int32_t>()); 141 142 EXPECT_EQ(StringPtr("1").parseAs<uint32_t>(), 1); 143 EXPECT_EQ(StringPtr("0").parseAs<uint32_t>(), 0U); 144 EXPECT_EQ(StringPtr("4294967295").parseAs<uint32_t>(), 4294967295U); 145 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("-1").parseAs<uint32_t>()); 146 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("out-of-range", StringPtr("4294967296").parseAs<uint32_t>()); 147 148 EXPECT_EQ(StringPtr("1").parseAs<int16_t>(), 1); 149 EXPECT_EQ(StringPtr("1").parseAs<uint16_t>(), 1); 150 EXPECT_EQ(StringPtr("1").parseAs<int8_t>(), 1); 151 EXPECT_EQ(StringPtr("1").parseAs<uint8_t>(), 1); 152 EXPECT_EQ(StringPtr("1").parseAs<char>(), 1); 153 EXPECT_EQ(StringPtr("1").parseAs<signed char>(), 1); 154 EXPECT_EQ(StringPtr("1").parseAs<unsigned char>(), 1); 155 EXPECT_EQ(StringPtr("1").parseAs<short>(), 1); 156 EXPECT_EQ(StringPtr("1").parseAs<unsigned short>(), 1); 157 EXPECT_EQ(StringPtr("1").parseAs<int>(), 1); 158 EXPECT_EQ(StringPtr("1").parseAs<unsigned>(), 1); 159 EXPECT_EQ(StringPtr("1").parseAs<long>(), 1); 160 EXPECT_EQ(StringPtr("1").parseAs<unsigned long>(), 1); 161 EXPECT_EQ(StringPtr("1").parseAs<long long>(), 1); 162 EXPECT_EQ(StringPtr("1").parseAs<unsigned long long>(), 1); 163 164 EXPECT_EQ(heapString("1").parseAs<int>(), 1); 165 } 166 167 #if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 168 TEST(String, StlInterop) { 169 std::string foo = "foo"; 170 StringPtr ptr = foo; 171 EXPECT_EQ("foo", ptr); 172 173 std::string bar = ptr; 174 EXPECT_EQ("foo", bar); 175 176 EXPECT_EQ("foo", kj::str(foo)); 177 EXPECT_EQ("foo", kj::heapString(foo)); 178 } 179 180 struct Stringable { 181 kj::StringPtr toString() { return "foo"; } 182 }; 183 184 TEST(String, ToString) { 185 EXPECT_EQ("foo", kj::str(Stringable())); 186 } 187 #endif 188 189 KJ_TEST("string literals with _kj suffix") { 190 static constexpr StringPtr FOO = "foo"_kj; 191 KJ_EXPECT(FOO == "foo", FOO); 192 KJ_EXPECT(FOO[3] == 0); 193 194 KJ_EXPECT("foo\0bar"_kj == StringPtr("foo\0bar", 7)); 195 196 static constexpr ArrayPtr<const char> ARR = "foo"_kj; 197 KJ_EXPECT(ARR.size() == 3); 198 KJ_EXPECT(kj::str(ARR) == "foo"); 199 } 200 201 KJ_TEST("kj::delimited() and kj::strPreallocated()") { 202 int rawArray[] = {1, 23, 456, 78}; 203 ArrayPtr<int> array = rawArray; 204 KJ_EXPECT(str(delimited(array, "::")) == "1::23::456::78"); 205 206 { 207 char buffer[256]; 208 KJ_EXPECT(strPreallocated(buffer, delimited(array, "::"), 'x') 209 == "1::23::456::78x"); 210 KJ_EXPECT(strPreallocated(buffer, "foo", 123, true) == "foo123true"); 211 } 212 213 { 214 char buffer[5]; 215 KJ_EXPECT(strPreallocated(buffer, delimited(array, "::"), 'x') == "1::2"); 216 KJ_EXPECT(strPreallocated(buffer, "foo", 123, true) == "foo1"); 217 } 218 } 219 220 KJ_TEST("parsing 'nan' returns canonical NaN value") { 221 // There are many representations of NaN. We would prefer that parsing "NaN" produces exactly the 222 // same bits that kj::nan() returns. 223 { 224 double parsedNan = StringPtr("NaN").parseAs<double>(); 225 double canonicalNan = kj::nan(); 226 KJ_EXPECT(memcmp(&parsedNan, &canonicalNan, sizeof(parsedNan)) == 0); 227 } 228 { 229 float parsedNan = StringPtr("NaN").parseAs<float>(); 230 float canonicalNan = kj::nan(); 231 KJ_EXPECT(memcmp(&parsedNan, &canonicalNan, sizeof(parsedNan)) == 0); 232 } 233 } 234 235 KJ_TEST("stringify array-of-array") { 236 int arr1[] = {1, 23}; 237 int arr2[] = {456, 7890}; 238 ArrayPtr<int> arr3[] = {arr1, arr2}; 239 ArrayPtr<ArrayPtr<int>> array = arr3; 240 241 KJ_EXPECT(str(array) == "1, 23, 456, 7890"); 242 } 243 244 KJ_TEST("ArrayPtr == StringPtr") { 245 StringPtr s = "foo"_kj; 246 ArrayPtr<const char> a = s; 247 248 KJ_EXPECT(a == s); 249 #if __cplusplus >= 202000L 250 KJ_EXPECT(s == a); 251 #endif 252 } 253 254 KJ_TEST("String == String") { 255 String a = kj::str("foo"); 256 String b = kj::str("foo"); 257 String c = kj::str("bar"); 258 259 // We're trying to trigger the -Wambiguous-reversed-operator warning in Clang, but it seems 260 // magic asserts inadvertently squelch it. So, we use an alternate macro with no magic. 261 #define KJ_EXPECT_NOMAGIC(cond) \ 262 if (cond) {} else { KJ_FAIL_ASSERT("expected " #cond); } 263 264 KJ_EXPECT_NOMAGIC(a == a); 265 KJ_EXPECT_NOMAGIC(a == b); 266 KJ_EXPECT_NOMAGIC(a != c); 267 } 268 269 KJ_TEST("float stringification and parsing is not locale-dependent") { 270 // Remember the old locale, set it back when we're done. 271 char* oldLocaleCstr = setlocale(LC_NUMERIC, nullptr); 272 KJ_ASSERT(oldLocaleCstr != nullptr); 273 auto oldLocale = kj::str(oldLocaleCstr); 274 KJ_DEFER(setlocale(LC_NUMERIC, oldLocale.cStr())); 275 276 // Set the locale to "C". 277 KJ_ASSERT(setlocale(LC_NUMERIC, "C") != nullptr); 278 279 KJ_ASSERT(kj::str(1.5) == "1.5"); 280 KJ_ASSERT(kj::str(1.5f) == "1.5"); 281 KJ_EXPECT("1.5"_kj.parseAs<float>() == 1.5); 282 KJ_EXPECT("1.5"_kj.parseAs<double>() == 1.5); 283 284 if (setlocale(LC_NUMERIC, "es_ES") == nullptr && 285 setlocale(LC_NUMERIC, "es_ES.utf8") == nullptr && 286 setlocale(LC_NUMERIC, "es_ES.UTF-8") == nullptr) { 287 // Some systems may not have the desired locale available. 288 KJ_LOG(WARNING, "Couldn't set locale to es_ES. Skipping this test."); 289 } else { 290 KJ_EXPECT(kj::str(1.5) == "1.5"); 291 KJ_EXPECT(kj::str(1.5f) == "1.5"); 292 KJ_EXPECT("1.5"_kj.parseAs<float>() == 1.5); 293 KJ_EXPECT("1.5"_kj.parseAs<double>() == 1.5); 294 } 295 } 296 } // namespace 297 } // namespace _ (private) 298 } // namespace kj