array-test.c++ (14366B)
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 "array.h" 23 #include "debug.h" 24 #include <string> 25 #include <list> 26 #include <kj/compat/gtest.h> 27 28 namespace kj { 29 namespace { 30 31 struct TestObject { 32 TestObject() { 33 index = count; 34 KJ_ASSERT(index != throwAt); 35 ++count; 36 } 37 TestObject(const TestObject& other) { 38 KJ_ASSERT(other.index != throwAt); 39 index = -1; 40 copiedCount++; 41 } 42 ~TestObject() noexcept(false) { 43 if (index == -1) { 44 --copiedCount; 45 } else { 46 --count; 47 EXPECT_EQ(index, count); 48 KJ_ASSERT(count != throwAt); 49 } 50 } 51 52 int index; 53 54 static int count; 55 static int copiedCount; 56 static int throwAt; 57 }; 58 59 int TestObject::count = 0; 60 int TestObject::copiedCount = 0; 61 int TestObject::throwAt = -1; 62 63 struct TestNoexceptObject { 64 TestNoexceptObject() noexcept { 65 index = count; 66 ++count; 67 } 68 TestNoexceptObject(const TestNoexceptObject& other) noexcept { 69 index = -1; 70 copiedCount++; 71 } 72 ~TestNoexceptObject() noexcept { 73 if (index == -1) { 74 --copiedCount; 75 } else { 76 --count; 77 EXPECT_EQ(index, count); 78 } 79 } 80 81 int index; 82 83 static int count; 84 static int copiedCount; 85 }; 86 87 int TestNoexceptObject::count = 0; 88 int TestNoexceptObject::copiedCount = 0; 89 90 TEST(Array, TrivialConstructor) { 91 // char* ptr; 92 { 93 Array<char> chars = heapArray<char>(32); 94 // ptr = chars.begin(); 95 chars[0] = 12; 96 chars[1] = 34; 97 } 98 99 { 100 Array<char> chars = heapArray<char>(32); 101 102 // TODO(test): The following doesn't work in opt mode -- I guess some allocators zero the 103 // memory? Is there some other way we can test this? Maybe override malloc()? 104 // // Somewhat hacky: We can't guarantee that the new array is allocated in the same place, but 105 // // any reasonable allocator is highly likely to do so. If it does, then we expect that the 106 // // memory has not been initialized. 107 // if (chars.begin() == ptr) { 108 // EXPECT_NE(chars[0], 0); 109 // EXPECT_NE(chars[1], 0); 110 // } 111 } 112 } 113 114 TEST(Array, ComplexConstructor) { 115 TestObject::count = 0; 116 TestObject::throwAt = -1; 117 118 { 119 Array<TestObject> array = heapArray<TestObject>(32); 120 EXPECT_EQ(32, TestObject::count); 121 } 122 EXPECT_EQ(0, TestObject::count); 123 } 124 125 #if !KJ_NO_EXCEPTIONS 126 TEST(Array, ThrowingConstructor) { 127 TestObject::count = 0; 128 TestObject::throwAt = 16; 129 130 // If a constructor throws, the previous elements should still be destroyed. 131 EXPECT_ANY_THROW(heapArray<TestObject>(32)); 132 EXPECT_EQ(0, TestObject::count); 133 } 134 135 TEST(Array, ThrowingDestructor) { 136 TestObject::count = 0; 137 TestObject::throwAt = -1; 138 139 Array<TestObject> array = heapArray<TestObject>(32); 140 EXPECT_EQ(32, TestObject::count); 141 142 // If a destructor throws, all elements should still be destroyed. 143 TestObject::throwAt = 16; 144 EXPECT_ANY_THROW(array = nullptr); 145 EXPECT_EQ(0, TestObject::count); 146 } 147 #endif // !KJ_NO_EXCEPTIONS 148 149 TEST(Array, AraryBuilder) { 150 TestObject::count = 0; 151 TestObject::throwAt = -1; 152 153 Array<TestObject> array; 154 155 { 156 ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(32); 157 158 for (int i = 0; i < 32; i++) { 159 EXPECT_EQ(i, TestObject::count); 160 builder.add(); 161 } 162 163 EXPECT_EQ(32, TestObject::count); 164 array = builder.finish(); 165 EXPECT_EQ(32, TestObject::count); 166 } 167 168 EXPECT_EQ(32, TestObject::count); 169 array = nullptr; 170 EXPECT_EQ(0, TestObject::count); 171 } 172 173 TEST(Array, AraryBuilderAddAll) { 174 { 175 // Trivial case. 176 char text[] = "foo"; 177 ArrayBuilder<char> builder = heapArrayBuilder<char>(5); 178 builder.add('<'); 179 builder.addAll(text, text + 3); 180 builder.add('>'); 181 auto array = builder.finish(); 182 EXPECT_EQ("<foo>", std::string(array.begin(), array.end())); 183 } 184 185 { 186 // Trivial case, const. 187 const char* text = "foo"; 188 ArrayBuilder<char> builder = heapArrayBuilder<char>(5); 189 builder.add('<'); 190 builder.addAll(text, text + 3); 191 builder.add('>'); 192 auto array = builder.finish(); 193 EXPECT_EQ("<foo>", std::string(array.begin(), array.end())); 194 } 195 196 { 197 // Trivial case, non-pointer iterator. 198 std::list<char> text = {'f', 'o', 'o'}; 199 ArrayBuilder<char> builder = heapArrayBuilder<char>(5); 200 builder.add('<'); 201 builder.addAll(text); 202 builder.add('>'); 203 auto array = builder.finish(); 204 EXPECT_EQ("<foo>", std::string(array.begin(), array.end())); 205 } 206 207 { 208 // Complex case. 209 std::string strs[] = {"foo", "bar", "baz"}; 210 ArrayBuilder<std::string> builder = heapArrayBuilder<std::string>(5); 211 builder.add("qux"); 212 builder.addAll(strs, strs + 3); 213 builder.add("quux"); 214 auto array = builder.finish(); 215 EXPECT_EQ("qux", array[0]); 216 EXPECT_EQ("foo", array[1]); 217 EXPECT_EQ("bar", array[2]); 218 EXPECT_EQ("baz", array[3]); 219 EXPECT_EQ("quux", array[4]); 220 } 221 222 { 223 // Complex case, noexcept. 224 TestNoexceptObject::count = 0; 225 TestNoexceptObject::copiedCount = 0; 226 TestNoexceptObject objs[3]; 227 EXPECT_EQ(3, TestNoexceptObject::count); 228 EXPECT_EQ(0, TestNoexceptObject::copiedCount); 229 ArrayBuilder<TestNoexceptObject> builder = heapArrayBuilder<TestNoexceptObject>(3); 230 EXPECT_EQ(3, TestNoexceptObject::count); 231 EXPECT_EQ(0, TestNoexceptObject::copiedCount); 232 builder.addAll(objs, objs + 3); 233 EXPECT_EQ(3, TestNoexceptObject::count); 234 EXPECT_EQ(3, TestNoexceptObject::copiedCount); 235 auto array = builder.finish(); 236 EXPECT_EQ(3, TestNoexceptObject::count); 237 EXPECT_EQ(3, TestNoexceptObject::copiedCount); 238 } 239 EXPECT_EQ(0, TestNoexceptObject::count); 240 EXPECT_EQ(0, TestNoexceptObject::copiedCount); 241 242 { 243 // Complex case, exceptions possible. 244 TestObject::count = 0; 245 TestObject::copiedCount = 0; 246 TestObject::throwAt = -1; 247 TestObject objs[3]; 248 EXPECT_EQ(3, TestObject::count); 249 EXPECT_EQ(0, TestObject::copiedCount); 250 ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(3); 251 EXPECT_EQ(3, TestObject::count); 252 EXPECT_EQ(0, TestObject::copiedCount); 253 builder.addAll(objs, objs + 3); 254 EXPECT_EQ(3, TestObject::count); 255 EXPECT_EQ(3, TestObject::copiedCount); 256 auto array = builder.finish(); 257 EXPECT_EQ(3, TestObject::count); 258 EXPECT_EQ(3, TestObject::copiedCount); 259 } 260 EXPECT_EQ(0, TestObject::count); 261 EXPECT_EQ(0, TestObject::copiedCount); 262 263 #if !KJ_NO_EXCEPTIONS 264 { 265 // Complex case, exceptions occur. 266 TestObject::count = 0; 267 TestObject::copiedCount = 0; 268 TestObject::throwAt = -1; 269 TestObject objs[3]; 270 EXPECT_EQ(3, TestObject::count); 271 EXPECT_EQ(0, TestObject::copiedCount); 272 273 TestObject::throwAt = 1; 274 275 ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(3); 276 EXPECT_EQ(3, TestObject::count); 277 EXPECT_EQ(0, TestObject::copiedCount); 278 279 EXPECT_ANY_THROW(builder.addAll(objs, objs + 3)); 280 TestObject::throwAt = -1; 281 282 EXPECT_EQ(3, TestObject::count); 283 EXPECT_EQ(0, TestObject::copiedCount); 284 } 285 EXPECT_EQ(0, TestObject::count); 286 EXPECT_EQ(0, TestObject::copiedCount); 287 #endif // !KJ_NO_EXCEPTIONS 288 } 289 290 TEST(Array, HeapCopy) { 291 { 292 Array<char> copy = heapArray("foo", 3); 293 EXPECT_EQ(3u, copy.size()); 294 EXPECT_EQ("foo", std::string(copy.begin(), 3)); 295 } 296 { 297 Array<char> copy = heapArray(ArrayPtr<const char>("bar", 3)); 298 EXPECT_EQ(3u, copy.size()); 299 EXPECT_EQ("bar", std::string(copy.begin(), 3)); 300 } 301 { 302 const char* ptr = "baz"; 303 Array<char> copy = heapArray<char>(ptr, ptr + 3); 304 EXPECT_EQ(3u, copy.size()); 305 EXPECT_EQ("baz", std::string(copy.begin(), 3)); 306 } 307 } 308 309 TEST(Array, OwnConst) { 310 ArrayBuilder<int> builder = heapArrayBuilder<int>(2); 311 int x[2] = {123, 234}; 312 builder.addAll(x, x + 2); 313 314 Array<int> i = builder.finish(); //heapArray<int>({123, 234}); 315 ASSERT_EQ(2u, i.size()); 316 EXPECT_EQ(123, i[0]); 317 EXPECT_EQ(234, i[1]); 318 319 Array<const int> ci = mv(i); 320 ASSERT_EQ(2u, ci.size()); 321 EXPECT_EQ(123, ci[0]); 322 EXPECT_EQ(234, ci[1]); 323 324 Array<const int> ci2 = heapArray<const int>({345, 456}); 325 ASSERT_EQ(2u, ci2.size()); 326 EXPECT_EQ(345, ci2[0]); 327 EXPECT_EQ(456, ci2[1]); 328 } 329 330 TEST(Array, Map) { 331 StringPtr foo = "abcd"; 332 Array<char> bar = KJ_MAP(c, foo) -> char { return c + 1; }; 333 EXPECT_STREQ("bcde", str(bar).cStr()); 334 } 335 336 TEST(Array, MapRawArray) { 337 uint foo[4] = {1, 2, 3, 4}; 338 Array<uint> bar = KJ_MAP(i, foo) -> uint { return i * i; }; 339 ASSERT_EQ(4, bar.size()); 340 EXPECT_EQ(1, bar[0]); 341 EXPECT_EQ(4, bar[1]); 342 EXPECT_EQ(9, bar[2]); 343 EXPECT_EQ(16, bar[3]); 344 } 345 346 TEST(Array, ReleaseAsBytesOrChars) { 347 { 348 Array<char> chars = kj::heapArray<char>("foo", 3); 349 Array<byte> bytes = chars.releaseAsBytes(); 350 EXPECT_TRUE(chars == nullptr); 351 ASSERT_EQ(3, bytes.size()); 352 EXPECT_EQ('f', bytes[0]); 353 EXPECT_EQ('o', bytes[1]); 354 EXPECT_EQ('o', bytes[2]); 355 356 chars = bytes.releaseAsChars(); 357 EXPECT_TRUE(bytes == nullptr); 358 ASSERT_EQ(3, chars.size()); 359 EXPECT_EQ('f', chars[0]); 360 EXPECT_EQ('o', chars[1]); 361 EXPECT_EQ('o', chars[2]); 362 } 363 { 364 Array<const char> chars = kj::heapArray<char>("foo", 3); 365 Array<const byte> bytes = chars.releaseAsBytes(); 366 EXPECT_TRUE(chars == nullptr); 367 ASSERT_EQ(3, bytes.size()); 368 EXPECT_EQ('f', bytes[0]); 369 EXPECT_EQ('o', bytes[1]); 370 EXPECT_EQ('o', bytes[2]); 371 372 chars = bytes.releaseAsChars(); 373 EXPECT_TRUE(bytes == nullptr); 374 ASSERT_EQ(3, chars.size()); 375 EXPECT_EQ('f', chars[0]); 376 EXPECT_EQ('o', chars[1]); 377 EXPECT_EQ('o', chars[2]); 378 } 379 } 380 381 #if __cplusplus > 201402L 382 KJ_TEST("kj::arr()") { 383 kj::Array<kj::String> array = kj::arr(kj::str("foo"), kj::str(123)); 384 KJ_EXPECT(array == kj::ArrayPtr<const kj::StringPtr>({"foo", "123"})); 385 } 386 387 struct ImmovableInt { 388 ImmovableInt(int i): i(i) {} 389 KJ_DISALLOW_COPY(ImmovableInt); 390 int i; 391 }; 392 393 KJ_TEST("kj::arrOf()") { 394 kj::Array<ImmovableInt> array = kj::arrOf<ImmovableInt>(123, 456, 789); 395 KJ_ASSERT(array.size() == 3); 396 KJ_EXPECT(array[0].i == 123); 397 KJ_EXPECT(array[1].i == 456); 398 KJ_EXPECT(array[2].i == 789); 399 } 400 #endif 401 402 struct DestructionOrderRecorder { 403 DestructionOrderRecorder(uint& counter, uint& recordTo) 404 : counter(counter), recordTo(recordTo) {} 405 ~DestructionOrderRecorder() { 406 recordTo = ++counter; 407 } 408 409 uint& counter; 410 uint& recordTo; 411 }; 412 413 TEST(Array, Attach) { 414 uint counter = 0; 415 uint destroyed1 = 0; 416 uint destroyed2 = 0; 417 uint destroyed3 = 0; 418 419 auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1); 420 auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2); 421 auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3); 422 423 auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1); 424 builder.add(kj::mv(obj1)); 425 auto arr = builder.finish(); 426 auto ptr = arr.begin(); 427 428 Array<Own<DestructionOrderRecorder>> combined = arr.attach(kj::mv(obj2), kj::mv(obj3)); 429 430 KJ_EXPECT(combined.begin() == ptr); 431 432 KJ_EXPECT(obj1.get() == nullptr); 433 KJ_EXPECT(obj2.get() == nullptr); 434 KJ_EXPECT(obj3.get() == nullptr); 435 KJ_EXPECT(destroyed1 == 0); 436 KJ_EXPECT(destroyed2 == 0); 437 KJ_EXPECT(destroyed3 == 0); 438 439 combined = nullptr; 440 441 KJ_EXPECT(destroyed1 == 1, destroyed1); 442 KJ_EXPECT(destroyed2 == 2, destroyed2); 443 KJ_EXPECT(destroyed3 == 3, destroyed3); 444 } 445 446 TEST(Array, AttachNested) { 447 uint counter = 0; 448 uint destroyed1 = 0; 449 uint destroyed2 = 0; 450 uint destroyed3 = 0; 451 452 auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1); 453 auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2); 454 auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3); 455 456 auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1); 457 builder.add(kj::mv(obj1)); 458 auto arr = builder.finish(); 459 auto ptr = arr.begin(); 460 461 Array<Own<DestructionOrderRecorder>> combined = arr.attach(kj::mv(obj2)).attach(kj::mv(obj3)); 462 463 KJ_EXPECT(combined.begin() == ptr); 464 KJ_EXPECT(combined.size() == 1); 465 466 KJ_EXPECT(obj1.get() == nullptr); 467 KJ_EXPECT(obj2.get() == nullptr); 468 KJ_EXPECT(obj3.get() == nullptr); 469 KJ_EXPECT(destroyed1 == 0); 470 KJ_EXPECT(destroyed2 == 0); 471 KJ_EXPECT(destroyed3 == 0); 472 473 combined = nullptr; 474 475 KJ_EXPECT(destroyed1 == 1, destroyed1); 476 KJ_EXPECT(destroyed2 == 2, destroyed2); 477 KJ_EXPECT(destroyed3 == 3, destroyed3); 478 } 479 480 TEST(Array, AttachFromArrayPtr) { 481 uint counter = 0; 482 uint destroyed1 = 0; 483 uint destroyed2 = 0; 484 uint destroyed3 = 0; 485 486 auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1); 487 auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2); 488 auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3); 489 490 auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1); 491 builder.add(kj::mv(obj1)); 492 auto arr = builder.finish(); 493 auto ptr = arr.begin(); 494 495 Array<Own<DestructionOrderRecorder>> combined = 496 arr.asPtr().attach(kj::mv(obj2)).attach(kj::mv(obj3)); 497 KJ_EXPECT(arr != nullptr); 498 499 KJ_EXPECT(combined.begin() == ptr); 500 501 KJ_EXPECT(obj1.get() == nullptr); 502 KJ_EXPECT(obj2.get() == nullptr); 503 KJ_EXPECT(obj3.get() == nullptr); 504 KJ_EXPECT(destroyed1 == 0); 505 KJ_EXPECT(destroyed2 == 0); 506 KJ_EXPECT(destroyed3 == 0); 507 508 combined = nullptr; 509 510 KJ_EXPECT(destroyed2 == 1, destroyed2); 511 KJ_EXPECT(destroyed3 == 2, destroyed3); 512 513 arr = nullptr; 514 515 KJ_EXPECT(destroyed1 == 3, destroyed1); 516 } 517 518 } // namespace 519 } // namespace kj