1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/memory/scoped_ptr.h" 6 7 #include "base/basictypes.h" 8 #include "base/bind.h" 9 #include "base/callback.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace { 13 14 // Used to test depth subtyping. 15 class ConDecLoggerParent { 16 public: 17 virtual ~ConDecLoggerParent() {} 18 19 virtual void SetPtr(int* ptr) = 0; 20 21 virtual int SomeMeth(int x) const = 0; 22 }; 23 24 class ConDecLogger : public ConDecLoggerParent { 25 public: 26 ConDecLogger() : ptr_(NULL) { } 27 explicit ConDecLogger(int* ptr) { SetPtr(ptr); } 28 virtual ~ConDecLogger() { --*ptr_; } 29 30 virtual void SetPtr(int* ptr) OVERRIDE { ptr_ = ptr; ++*ptr_; } 31 32 virtual int SomeMeth(int x) const OVERRIDE { return x; } 33 34 private: 35 int* ptr_; 36 37 DISALLOW_COPY_AND_ASSIGN(ConDecLogger); 38 }; 39 40 struct CountingDeleter { 41 explicit CountingDeleter(int* count) : count_(count) {} 42 inline void operator()(double* ptr) const { 43 (*count_)++; 44 } 45 int* count_; 46 }; 47 48 // Used to test assignment of convertible deleters. 49 struct CountingDeleterChild : public CountingDeleter { 50 explicit CountingDeleterChild(int* count) : CountingDeleter(count) {} 51 }; 52 53 class OverloadedNewAndDelete { 54 public: 55 void* operator new(size_t size) { 56 g_new_count++; 57 return malloc(size); 58 } 59 60 void operator delete(void* ptr) { 61 g_delete_count++; 62 free(ptr); 63 } 64 65 static void ResetCounters() { 66 g_new_count = 0; 67 g_delete_count = 0; 68 } 69 70 static int new_count() { return g_new_count; } 71 static int delete_count() { return g_delete_count; } 72 73 private: 74 static int g_new_count; 75 static int g_delete_count; 76 }; 77 78 int OverloadedNewAndDelete::g_new_count = 0; 79 int OverloadedNewAndDelete::g_delete_count = 0; 80 81 scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) { 82 return logger.Pass(); 83 } 84 85 void GrabAndDrop(scoped_ptr<ConDecLogger> logger) { 86 } 87 88 // Do not delete this function! It's existence is to test that you can 89 // return a temporarily constructed version of the scoper. 90 scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) { 91 return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed)); 92 } 93 94 scoped_ptr<ConDecLoggerParent> UpcastUsingPassAs( 95 scoped_ptr<ConDecLogger> object) { 96 return object.PassAs<ConDecLoggerParent>(); 97 } 98 99 } // namespace 100 101 TEST(ScopedPtrTest, ScopedPtr) { 102 int constructed = 0; 103 104 // Ensure size of scoped_ptr<> doesn't increase unexpectedly. 105 COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>), 106 scoped_ptr_larger_than_raw_ptr); 107 108 { 109 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 110 EXPECT_EQ(1, constructed); 111 EXPECT_TRUE(scoper.get()); 112 113 EXPECT_EQ(10, scoper->SomeMeth(10)); 114 EXPECT_EQ(10, scoper.get()->SomeMeth(10)); 115 EXPECT_EQ(10, (*scoper).SomeMeth(10)); 116 } 117 EXPECT_EQ(0, constructed); 118 119 // Test reset() and release() 120 { 121 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 122 EXPECT_EQ(1, constructed); 123 EXPECT_TRUE(scoper.get()); 124 125 scoper.reset(new ConDecLogger(&constructed)); 126 EXPECT_EQ(1, constructed); 127 EXPECT_TRUE(scoper.get()); 128 129 scoper.reset(); 130 EXPECT_EQ(0, constructed); 131 EXPECT_FALSE(scoper.get()); 132 133 scoper.reset(new ConDecLogger(&constructed)); 134 EXPECT_EQ(1, constructed); 135 EXPECT_TRUE(scoper.get()); 136 137 ConDecLogger* take = scoper.release(); 138 EXPECT_EQ(1, constructed); 139 EXPECT_FALSE(scoper.get()); 140 delete take; 141 EXPECT_EQ(0, constructed); 142 143 scoper.reset(new ConDecLogger(&constructed)); 144 EXPECT_EQ(1, constructed); 145 EXPECT_TRUE(scoper.get()); 146 } 147 EXPECT_EQ(0, constructed); 148 149 // Test swap(), == and != 150 { 151 scoped_ptr<ConDecLogger> scoper1; 152 scoped_ptr<ConDecLogger> scoper2; 153 EXPECT_TRUE(scoper1 == scoper2.get()); 154 EXPECT_FALSE(scoper1 != scoper2.get()); 155 156 ConDecLogger* logger = new ConDecLogger(&constructed); 157 scoper1.reset(logger); 158 EXPECT_EQ(logger, scoper1.get()); 159 EXPECT_FALSE(scoper2.get()); 160 EXPECT_FALSE(scoper1 == scoper2.get()); 161 EXPECT_TRUE(scoper1 != scoper2.get()); 162 163 scoper2.swap(scoper1); 164 EXPECT_EQ(logger, scoper2.get()); 165 EXPECT_FALSE(scoper1.get()); 166 EXPECT_FALSE(scoper1 == scoper2.get()); 167 EXPECT_TRUE(scoper1 != scoper2.get()); 168 } 169 EXPECT_EQ(0, constructed); 170 } 171 172 TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) { 173 int constructed = 0; 174 175 // Test construction from a scoped_ptr to a derived class. 176 { 177 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 178 EXPECT_EQ(1, constructed); 179 EXPECT_TRUE(scoper.get()); 180 181 scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass()); 182 EXPECT_EQ(1, constructed); 183 EXPECT_TRUE(scoper_parent.get()); 184 EXPECT_FALSE(scoper.get()); 185 186 EXPECT_EQ(10, scoper_parent->SomeMeth(10)); 187 EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10)); 188 EXPECT_EQ(10, (*scoper_parent).SomeMeth(10)); 189 } 190 EXPECT_EQ(0, constructed); 191 192 // Test assignment from a scoped_ptr to a derived class. 193 { 194 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 195 EXPECT_EQ(1, constructed); 196 EXPECT_TRUE(scoper.get()); 197 198 scoped_ptr<ConDecLoggerParent> scoper_parent; 199 scoper_parent = scoper.Pass(); 200 EXPECT_EQ(1, constructed); 201 EXPECT_TRUE(scoper_parent.get()); 202 EXPECT_FALSE(scoper.get()); 203 } 204 EXPECT_EQ(0, constructed); 205 206 // Test construction of a scoped_ptr with an additional const annotation. 207 { 208 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 209 EXPECT_EQ(1, constructed); 210 EXPECT_TRUE(scoper.get()); 211 212 scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass()); 213 EXPECT_EQ(1, constructed); 214 EXPECT_TRUE(scoper_const.get()); 215 EXPECT_FALSE(scoper.get()); 216 217 EXPECT_EQ(10, scoper_const->SomeMeth(10)); 218 EXPECT_EQ(10, scoper_const.get()->SomeMeth(10)); 219 EXPECT_EQ(10, (*scoper_const).SomeMeth(10)); 220 } 221 EXPECT_EQ(0, constructed); 222 223 // Test assignment to a scoped_ptr with an additional const annotation. 224 { 225 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 226 EXPECT_EQ(1, constructed); 227 EXPECT_TRUE(scoper.get()); 228 229 scoped_ptr<const ConDecLogger> scoper_const; 230 scoper_const = scoper.Pass(); 231 EXPECT_EQ(1, constructed); 232 EXPECT_TRUE(scoper_const.get()); 233 EXPECT_FALSE(scoper.get()); 234 } 235 EXPECT_EQ(0, constructed); 236 237 // Test assignment to a scoped_ptr deleter of parent type. 238 { 239 // Custom deleters never touch these value. 240 double dummy_value, dummy_value2; 241 int deletes = 0; 242 int alternate_deletes = 0; 243 scoped_ptr<double, CountingDeleter> scoper(&dummy_value, 244 CountingDeleter(&deletes)); 245 scoped_ptr<double, CountingDeleterChild> scoper_child( 246 &dummy_value2, CountingDeleterChild(&alternate_deletes)); 247 248 EXPECT_TRUE(scoper); 249 EXPECT_TRUE(scoper_child); 250 EXPECT_EQ(0, deletes); 251 EXPECT_EQ(0, alternate_deletes); 252 253 // Test this compiles and correctly overwrites the deleter state. 254 scoper = scoper_child.Pass(); 255 EXPECT_TRUE(scoper); 256 EXPECT_FALSE(scoper_child); 257 EXPECT_EQ(1, deletes); 258 EXPECT_EQ(0, alternate_deletes); 259 260 scoper.reset(); 261 EXPECT_FALSE(scoper); 262 EXPECT_FALSE(scoper_child); 263 EXPECT_EQ(1, deletes); 264 EXPECT_EQ(1, alternate_deletes); 265 266 scoper_child.reset(&dummy_value); 267 EXPECT_TRUE(scoper_child); 268 EXPECT_EQ(1, deletes); 269 EXPECT_EQ(1, alternate_deletes); 270 scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass()); 271 EXPECT_TRUE(scoper_construct); 272 EXPECT_FALSE(scoper_child); 273 EXPECT_EQ(1, deletes); 274 EXPECT_EQ(1, alternate_deletes); 275 276 scoper_construct.reset(); 277 EXPECT_EQ(1, deletes); 278 EXPECT_EQ(2, alternate_deletes); 279 } 280 } 281 282 TEST(ScopedPtrTest, ScopedPtrWithArray) { 283 static const int kNumLoggers = 12; 284 285 int constructed = 0; 286 287 { 288 scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]); 289 EXPECT_TRUE(scoper); 290 EXPECT_EQ(&scoper[0], scoper.get()); 291 for (int i = 0; i < kNumLoggers; ++i) { 292 scoper[i].SetPtr(&constructed); 293 } 294 EXPECT_EQ(12, constructed); 295 296 EXPECT_EQ(10, scoper.get()->SomeMeth(10)); 297 EXPECT_EQ(10, scoper[2].SomeMeth(10)); 298 } 299 EXPECT_EQ(0, constructed); 300 301 // Test reset() and release() 302 { 303 scoped_ptr<ConDecLogger[]> scoper; 304 EXPECT_FALSE(scoper.get()); 305 EXPECT_FALSE(scoper.release()); 306 EXPECT_FALSE(scoper.get()); 307 scoper.reset(); 308 EXPECT_FALSE(scoper.get()); 309 310 scoper.reset(new ConDecLogger[kNumLoggers]); 311 for (int i = 0; i < kNumLoggers; ++i) { 312 scoper[i].SetPtr(&constructed); 313 } 314 EXPECT_EQ(12, constructed); 315 scoper.reset(); 316 EXPECT_EQ(0, constructed); 317 318 scoper.reset(new ConDecLogger[kNumLoggers]); 319 for (int i = 0; i < kNumLoggers; ++i) { 320 scoper[i].SetPtr(&constructed); 321 } 322 EXPECT_EQ(12, constructed); 323 ConDecLogger* ptr = scoper.release(); 324 EXPECT_EQ(12, constructed); 325 delete[] ptr; 326 EXPECT_EQ(0, constructed); 327 } 328 EXPECT_EQ(0, constructed); 329 330 // Test swap(), ==, !=, and type-safe Boolean. 331 { 332 scoped_ptr<ConDecLogger[]> scoper1; 333 scoped_ptr<ConDecLogger[]> scoper2; 334 EXPECT_TRUE(scoper1 == scoper2.get()); 335 EXPECT_FALSE(scoper1 != scoper2.get()); 336 337 ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; 338 for (int i = 0; i < kNumLoggers; ++i) { 339 loggers[i].SetPtr(&constructed); 340 } 341 scoper1.reset(loggers); 342 EXPECT_TRUE(scoper1); 343 EXPECT_EQ(loggers, scoper1.get()); 344 EXPECT_FALSE(scoper2); 345 EXPECT_FALSE(scoper2.get()); 346 EXPECT_FALSE(scoper1 == scoper2.get()); 347 EXPECT_TRUE(scoper1 != scoper2.get()); 348 349 scoper2.swap(scoper1); 350 EXPECT_EQ(loggers, scoper2.get()); 351 EXPECT_FALSE(scoper1.get()); 352 EXPECT_FALSE(scoper1 == scoper2.get()); 353 EXPECT_TRUE(scoper1 != scoper2.get()); 354 } 355 EXPECT_EQ(0, constructed); 356 357 { 358 ConDecLogger* loggers = new ConDecLogger[kNumLoggers]; 359 scoped_ptr<ConDecLogger[]> scoper(loggers); 360 EXPECT_TRUE(scoper); 361 for (int i = 0; i < kNumLoggers; ++i) { 362 scoper[i].SetPtr(&constructed); 363 } 364 EXPECT_EQ(kNumLoggers, constructed); 365 366 // Test Pass() with constructor; 367 scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass()); 368 EXPECT_EQ(kNumLoggers, constructed); 369 370 // Test Pass() with assignment; 371 scoped_ptr<ConDecLogger[]> scoper3; 372 scoper3 = scoper2.Pass(); 373 EXPECT_EQ(kNumLoggers, constructed); 374 EXPECT_FALSE(scoper); 375 EXPECT_FALSE(scoper2); 376 EXPECT_TRUE(scoper3); 377 } 378 EXPECT_EQ(0, constructed); 379 } 380 381 TEST(ScopedPtrTest, PassBehavior) { 382 int constructed = 0; 383 { 384 ConDecLogger* logger = new ConDecLogger(&constructed); 385 scoped_ptr<ConDecLogger> scoper(logger); 386 EXPECT_EQ(1, constructed); 387 388 // Test Pass() with constructor; 389 scoped_ptr<ConDecLogger> scoper2(scoper.Pass()); 390 EXPECT_EQ(1, constructed); 391 392 // Test Pass() with assignment; 393 scoped_ptr<ConDecLogger> scoper3; 394 scoper3 = scoper2.Pass(); 395 EXPECT_EQ(1, constructed); 396 EXPECT_FALSE(scoper.get()); 397 EXPECT_FALSE(scoper2.get()); 398 EXPECT_TRUE(scoper3.get()); 399 } 400 401 // Test uncaught Pass() does not leak. 402 { 403 ConDecLogger* logger = new ConDecLogger(&constructed); 404 scoped_ptr<ConDecLogger> scoper(logger); 405 EXPECT_EQ(1, constructed); 406 407 // Should auto-destruct logger by end of scope. 408 scoper.Pass(); 409 EXPECT_FALSE(scoper.get()); 410 } 411 EXPECT_EQ(0, constructed); 412 413 // Test that passing to function which does nothing does not leak. 414 { 415 ConDecLogger* logger = new ConDecLogger(&constructed); 416 scoped_ptr<ConDecLogger> scoper(logger); 417 EXPECT_EQ(1, constructed); 418 419 // Should auto-destruct logger by end of scope. 420 GrabAndDrop(scoper.Pass()); 421 EXPECT_FALSE(scoper.get()); 422 } 423 EXPECT_EQ(0, constructed); 424 } 425 426 TEST(ScopedPtrTest, ReturnTypeBehavior) { 427 int constructed = 0; 428 429 // Test that we can return a scoped_ptr. 430 { 431 ConDecLogger* logger = new ConDecLogger(&constructed); 432 scoped_ptr<ConDecLogger> scoper(logger); 433 EXPECT_EQ(1, constructed); 434 435 PassThru(scoper.Pass()); 436 EXPECT_FALSE(scoper.get()); 437 } 438 EXPECT_EQ(0, constructed); 439 440 // Test uncaught return type not leak. 441 { 442 ConDecLogger* logger = new ConDecLogger(&constructed); 443 scoped_ptr<ConDecLogger> scoper(logger); 444 EXPECT_EQ(1, constructed); 445 446 // Should auto-destruct logger by end of scope. 447 PassThru(scoper.Pass()); 448 EXPECT_FALSE(scoper.get()); 449 } 450 EXPECT_EQ(0, constructed); 451 452 // Call TestReturnOfType() so the compiler doesn't warn for an unused 453 // function. 454 { 455 TestReturnOfType(&constructed); 456 } 457 EXPECT_EQ(0, constructed); 458 } 459 460 TEST(ScopedPtrTest, PassAs) { 461 int constructed = 0; 462 { 463 scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); 464 EXPECT_EQ(1, constructed); 465 EXPECT_TRUE(scoper.get()); 466 467 scoped_ptr<ConDecLoggerParent> scoper_parent; 468 scoper_parent = UpcastUsingPassAs(scoper.Pass()); 469 EXPECT_EQ(1, constructed); 470 EXPECT_TRUE(scoper_parent.get()); 471 EXPECT_FALSE(scoper.get()); 472 } 473 EXPECT_EQ(0, constructed); 474 } 475 476 TEST(ScopedPtrTest, CustomDeleter) { 477 double dummy_value; // Custom deleter never touches this value. 478 int deletes = 0; 479 int alternate_deletes = 0; 480 481 // Normal delete support. 482 { 483 deletes = 0; 484 scoped_ptr<double, CountingDeleter> scoper(&dummy_value, 485 CountingDeleter(&deletes)); 486 EXPECT_EQ(0, deletes); 487 EXPECT_TRUE(scoper.get()); 488 } 489 EXPECT_EQ(1, deletes); 490 491 // Test reset() and release(). 492 deletes = 0; 493 { 494 scoped_ptr<double, CountingDeleter> scoper(NULL, 495 CountingDeleter(&deletes)); 496 EXPECT_FALSE(scoper.get()); 497 EXPECT_FALSE(scoper.release()); 498 EXPECT_FALSE(scoper.get()); 499 scoper.reset(); 500 EXPECT_FALSE(scoper.get()); 501 EXPECT_EQ(0, deletes); 502 503 scoper.reset(&dummy_value); 504 scoper.reset(); 505 EXPECT_EQ(1, deletes); 506 507 scoper.reset(&dummy_value); 508 EXPECT_EQ(&dummy_value, scoper.release()); 509 } 510 EXPECT_EQ(1, deletes); 511 512 // Test get_deleter(). 513 deletes = 0; 514 alternate_deletes = 0; 515 { 516 scoped_ptr<double, CountingDeleter> scoper(&dummy_value, 517 CountingDeleter(&deletes)); 518 // Call deleter manually. 519 EXPECT_EQ(0, deletes); 520 scoper.get_deleter()(&dummy_value); 521 EXPECT_EQ(1, deletes); 522 523 // Deleter is still there after reset. 524 scoper.reset(); 525 EXPECT_EQ(2, deletes); 526 scoper.get_deleter()(&dummy_value); 527 EXPECT_EQ(3, deletes); 528 529 // Deleter can be assigned into (matches C++11 unique_ptr<> spec). 530 scoper.get_deleter() = CountingDeleter(&alternate_deletes); 531 scoper.reset(&dummy_value); 532 EXPECT_EQ(0, alternate_deletes); 533 534 } 535 EXPECT_EQ(3, deletes); 536 EXPECT_EQ(1, alternate_deletes); 537 538 // Test operator= deleter support. 539 deletes = 0; 540 alternate_deletes = 0; 541 { 542 double dummy_value2; 543 scoped_ptr<double, CountingDeleter> scoper(&dummy_value, 544 CountingDeleter(&deletes)); 545 scoped_ptr<double, CountingDeleter> scoper2( 546 &dummy_value2, 547 CountingDeleter(&alternate_deletes)); 548 EXPECT_EQ(0, deletes); 549 EXPECT_EQ(0, alternate_deletes); 550 551 // Pass the second deleter through a constructor and an operator=. Then 552 // reinitialize the empty scopers to ensure that each one is deleting 553 // properly. 554 scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass()); 555 scoper = scoper3.Pass(); 556 EXPECT_EQ(1, deletes); 557 558 scoper2.reset(&dummy_value2); 559 scoper3.reset(&dummy_value2); 560 EXPECT_EQ(0, alternate_deletes); 561 562 } 563 EXPECT_EQ(1, deletes); 564 EXPECT_EQ(3, alternate_deletes); 565 566 // Test swap(), ==, !=, and type-safe Boolean. 567 { 568 scoped_ptr<double, CountingDeleter> scoper1(NULL, 569 CountingDeleter(&deletes)); 570 scoped_ptr<double, CountingDeleter> scoper2(NULL, 571 CountingDeleter(&deletes)); 572 EXPECT_TRUE(scoper1 == scoper2.get()); 573 EXPECT_FALSE(scoper1 != scoper2.get()); 574 575 scoper1.reset(&dummy_value); 576 EXPECT_TRUE(scoper1); 577 EXPECT_EQ(&dummy_value, scoper1.get()); 578 EXPECT_FALSE(scoper2); 579 EXPECT_FALSE(scoper2.get()); 580 EXPECT_FALSE(scoper1 == scoper2.get()); 581 EXPECT_TRUE(scoper1 != scoper2.get()); 582 583 scoper2.swap(scoper1); 584 EXPECT_EQ(&dummy_value, scoper2.get()); 585 EXPECT_FALSE(scoper1.get()); 586 EXPECT_FALSE(scoper1 == scoper2.get()); 587 EXPECT_TRUE(scoper1 != scoper2.get()); 588 } 589 } 590 591 // Sanity check test for overloaded new and delete operators. Does not do full 592 // coverage of reset/release/Pass() operations as that is redundant with the 593 // above. 594 TEST(ScopedPtrTest, OverloadedNewAndDelete) { 595 { 596 OverloadedNewAndDelete::ResetCounters(); 597 scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete()); 598 EXPECT_TRUE(scoper.get()); 599 600 scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass()); 601 } 602 EXPECT_EQ(1, OverloadedNewAndDelete::delete_count()); 603 EXPECT_EQ(1, OverloadedNewAndDelete::new_count()); 604 } 605 606 // TODO scoped_ptr_malloc 607