Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3209)

Unified Diff: base/memory/scoped_ptr_unittest.cc

Issue 11149006: Extend scoped_ptr to be closer to unique_ptr. Support custom deleters, and deleting arrays. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/memory/scoped_ptr.h ('k') | base/memory/scoped_ptr_unittest.nc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/memory/scoped_ptr_unittest.cc
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 3da6f15273181070fa51cc25107708def2fffa1f..59b3e1cf5371b9ec8eb3aaba08b1430d945d3b14 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -34,6 +37,47 @@ class ConDecLogger : public ConDecLoggerParent {
DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
};
+struct CountingDeleter {
+ explicit CountingDeleter(int* count) : count_(count) {}
+ inline void operator()(double* ptr) const {
+ (*count_)++;
+ }
+ int* count_;
+};
+
+// Used to test assignment of convertible deleters.
+struct CountingDeleterChild : public CountingDeleter {
+ explicit CountingDeleterChild(int* count) : CountingDeleter(count) {}
+};
+
+class OverloadedNewAndDelete {
+ public:
+ void* operator new(size_t size) {
+ g_new_count++;
+ return malloc(size);
+ }
+
+ void operator delete(void* ptr) {
+ g_delete_count++;
+ free(ptr);
+ }
+
+ static void ResetCounters() {
+ g_new_count = 0;
+ g_delete_count = 0;
+ }
+
+ static int new_count() { return g_new_count; }
+ static int delete_count() { return g_delete_count; }
+
+ private:
+ static int g_new_count;
+ static int g_delete_count;
+};
+
+int OverloadedNewAndDelete::g_new_count = 0;
+int OverloadedNewAndDelete::g_delete_count = 0;
+
scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
return logger.Pass();
}
@@ -57,6 +101,10 @@ scoped_ptr<ConDecLoggerParent> UpcastUsingPassAs(
TEST(ScopedPtrTest, ScopedPtr) {
int constructed = 0;
+ // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
+ COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
+ scoped_ptr_larger_than_raw_ptr);
+
{
scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
EXPECT_EQ(1, constructed);
@@ -185,6 +233,149 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
+
+ // Test assignment to a scoped_ptr deleter of parent type.
+ {
+ // Custom deleters never touch these value.
+ double dummy_value, dummy_value2;
+ int deletes = 0;
+ int alternate_deletes = 0;
+ scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+ CountingDeleter(&deletes));
+ scoped_ptr<double, CountingDeleterChild> scoper_child(
+ &dummy_value2, CountingDeleterChild(&alternate_deletes));
+
+ EXPECT_TRUE(scoper);
+ EXPECT_TRUE(scoper_child);
+ EXPECT_EQ(0, deletes);
+ EXPECT_EQ(0, alternate_deletes);
+
+ // Test this compiles and correctly overwrites the deleter state.
+ scoper = scoper_child.Pass();
+ EXPECT_TRUE(scoper);
+ EXPECT_FALSE(scoper_child);
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(0, alternate_deletes);
+
+ scoper.reset();
+ EXPECT_FALSE(scoper);
+ EXPECT_FALSE(scoper_child);
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(1, alternate_deletes);
+
+ scoper_child.reset(&dummy_value);
+ EXPECT_TRUE(scoper_child);
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(1, alternate_deletes);
+ scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+ EXPECT_TRUE(scoper_construct);
+ EXPECT_FALSE(scoper_child);
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(1, alternate_deletes);
+
+ scoper_construct.reset();
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(2, alternate_deletes);
+ }
+}
+
+TEST(ScopedPtrTest, ScopedPtrWithArray) {
+ static const int kNumLoggers = 12;
+
+ int constructed = 0;
+
+ {
+ scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]);
+ EXPECT_TRUE(scoper);
+ EXPECT_EQ(&scoper[0], scoper.get());
+ for (int i = 0; i < kNumLoggers; ++i) {
+ scoper[i].SetPtr(&constructed);
+ }
+ EXPECT_EQ(12, constructed);
+
+ EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+ EXPECT_EQ(10, scoper[2].SomeMeth(10));
+ }
+ EXPECT_EQ(0, constructed);
+
+ // Test reset() and release()
+ {
+ scoped_ptr<ConDecLogger[]> scoper;
+ EXPECT_FALSE(scoper.get());
+ EXPECT_FALSE(scoper.release());
+ EXPECT_FALSE(scoper.get());
+ scoper.reset();
+ EXPECT_FALSE(scoper.get());
+
+ scoper.reset(new ConDecLogger[kNumLoggers]);
+ for (int i = 0; i < kNumLoggers; ++i) {
+ scoper[i].SetPtr(&constructed);
+ }
+ EXPECT_EQ(12, constructed);
+ scoper.reset();
+ EXPECT_EQ(0, constructed);
+
+ scoper.reset(new ConDecLogger[kNumLoggers]);
+ for (int i = 0; i < kNumLoggers; ++i) {
+ scoper[i].SetPtr(&constructed);
+ }
+ EXPECT_EQ(12, constructed);
+ ConDecLogger* ptr = scoper.release();
+ EXPECT_EQ(12, constructed);
+ delete[] ptr;
+ EXPECT_EQ(0, constructed);
+ }
+ EXPECT_EQ(0, constructed);
+
+ // Test swap(), ==, !=, and type-safe Boolean.
+ {
+ scoped_ptr<ConDecLogger[]> scoper1;
+ scoped_ptr<ConDecLogger[]> scoper2;
+ EXPECT_TRUE(scoper1 == scoper2.get());
+ EXPECT_FALSE(scoper1 != scoper2.get());
+
+ ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+ for (int i = 0; i < kNumLoggers; ++i) {
+ loggers[i].SetPtr(&constructed);
+ }
+ scoper1.reset(loggers);
+ EXPECT_TRUE(scoper1);
+ EXPECT_EQ(loggers, scoper1.get());
+ EXPECT_FALSE(scoper2);
+ EXPECT_FALSE(scoper2.get());
+ EXPECT_FALSE(scoper1 == scoper2.get());
+ EXPECT_TRUE(scoper1 != scoper2.get());
+
+ scoper2.swap(scoper1);
+ EXPECT_EQ(loggers, scoper2.get());
+ EXPECT_FALSE(scoper1.get());
+ EXPECT_FALSE(scoper1 == scoper2.get());
+ EXPECT_TRUE(scoper1 != scoper2.get());
+ }
+ EXPECT_EQ(0, constructed);
+
+ {
+ ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+ scoped_ptr<ConDecLogger[]> scoper(loggers);
+ EXPECT_TRUE(scoper);
+ for (int i = 0; i < kNumLoggers; ++i) {
+ scoper[i].SetPtr(&constructed);
+ }
+ EXPECT_EQ(kNumLoggers, constructed);
+
+ // Test Pass() with constructor;
+ scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+ EXPECT_EQ(kNumLoggers, constructed);
+
+ // Test Pass() with assignment;
+ scoped_ptr<ConDecLogger[]> scoper3;
+ scoper3 = scoper2.Pass();
+ EXPECT_EQ(kNumLoggers, constructed);
+ EXPECT_FALSE(scoper);
+ EXPECT_FALSE(scoper2);
+ EXPECT_TRUE(scoper3);
+ }
+ EXPECT_EQ(0, constructed);
}
TEST(ScopedPtrTest, ScopedArray) {
@@ -235,7 +426,7 @@ TEST(ScopedPtrTest, ScopedArray) {
}
EXPECT_EQ(0, constructed);
- // Test swap(), == and !=
+ // Test swap(), ==, !=, and type-safe Boolean.
{
scoped_array<ConDecLogger> scoper1;
scoped_array<ConDecLogger> scoper2;
@@ -247,7 +438,9 @@ TEST(ScopedPtrTest, ScopedArray) {
loggers[i].SetPtr(&constructed);
}
scoper1.reset(loggers);
+ EXPECT_TRUE(scoper1);
EXPECT_EQ(loggers, scoper1.get());
+ EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
EXPECT_FALSE(scoper1 == scoper2.get());
EXPECT_TRUE(scoper1 != scoper2.get());
@@ -356,4 +549,134 @@ TEST(ScopedPtrTest, PassAs) {
EXPECT_EQ(0, constructed);
}
+TEST(ScopedPtrTest, CustomDeleter) {
+ double dummy_value; // Custom deleter never touches this value.
+ int deletes = 0;
+ int alternate_deletes = 0;
+
+ // Normal delete support.
+ {
+ deletes = 0;
+ scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+ CountingDeleter(&deletes));
+ EXPECT_EQ(0, deletes);
+ EXPECT_TRUE(scoper.get());
+ }
+ EXPECT_EQ(1, deletes);
+
+ // Test reset() and release().
+ deletes = 0;
+ {
+ scoped_ptr<double, CountingDeleter> scoper(NULL,
+ CountingDeleter(&deletes));
+ EXPECT_FALSE(scoper.get());
+ EXPECT_FALSE(scoper.release());
+ EXPECT_FALSE(scoper.get());
+ scoper.reset();
+ EXPECT_FALSE(scoper.get());
+ EXPECT_EQ(0, deletes);
+
+ scoper.reset(&dummy_value);
+ scoper.reset();
+ EXPECT_EQ(1, deletes);
+
+ scoper.reset(&dummy_value);
+ EXPECT_EQ(&dummy_value, scoper.release());
+ }
+ EXPECT_EQ(1, deletes);
+
+ // Test get_deleter().
+ deletes = 0;
+ alternate_deletes = 0;
+ {
+ scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+ CountingDeleter(&deletes));
+ // Call deleter manually.
+ EXPECT_EQ(0, deletes);
+ scoper.get_deleter()(&dummy_value);
+ EXPECT_EQ(1, deletes);
+
+ // Deleter is still there after reset.
+ scoper.reset();
+ EXPECT_EQ(2, deletes);
+ scoper.get_deleter()(&dummy_value);
+ EXPECT_EQ(3, deletes);
+
+ // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
+ scoper.get_deleter() = CountingDeleter(&alternate_deletes);
+ scoper.reset(&dummy_value);
+ EXPECT_EQ(0, alternate_deletes);
+
+ }
+ EXPECT_EQ(3, deletes);
+ EXPECT_EQ(1, alternate_deletes);
+
+ // Test operator= deleter support.
+ deletes = 0;
+ alternate_deletes = 0;
+ {
+ double dummy_value2;
+ scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+ CountingDeleter(&deletes));
+ scoped_ptr<double, CountingDeleter> scoper2(
+ &dummy_value2,
+ CountingDeleter(&alternate_deletes));
+ EXPECT_EQ(0, deletes);
+ EXPECT_EQ(0, alternate_deletes);
+
+ // Pass the second deleter through a constructor and an operator=. Then
+ // reinitialize the empty scopers to ensure that each one is deleting
+ // properly.
+ scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
+ scoper = scoper3.Pass();
+ EXPECT_EQ(1, deletes);
+
+ scoper2.reset(&dummy_value2);
+ scoper3.reset(&dummy_value2);
+ EXPECT_EQ(0, alternate_deletes);
+
+ }
+ EXPECT_EQ(1, deletes);
+ EXPECT_EQ(3, alternate_deletes);
+
+ // Test swap(), ==, !=, and type-safe Boolean.
+ {
+ scoped_ptr<double, CountingDeleter> scoper1(NULL,
+ CountingDeleter(&deletes));
+ scoped_ptr<double, CountingDeleter> scoper2(NULL,
+ CountingDeleter(&deletes));
+ EXPECT_TRUE(scoper1 == scoper2.get());
+ EXPECT_FALSE(scoper1 != scoper2.get());
+
+ scoper1.reset(&dummy_value);
+ EXPECT_TRUE(scoper1);
+ EXPECT_EQ(&dummy_value, scoper1.get());
+ EXPECT_FALSE(scoper2);
+ EXPECT_FALSE(scoper2.get());
+ EXPECT_FALSE(scoper1 == scoper2.get());
+ EXPECT_TRUE(scoper1 != scoper2.get());
+
+ scoper2.swap(scoper1);
+ EXPECT_EQ(&dummy_value, scoper2.get());
+ EXPECT_FALSE(scoper1.get());
+ EXPECT_FALSE(scoper1 == scoper2.get());
+ EXPECT_TRUE(scoper1 != scoper2.get());
+ }
+}
+
+// Sanity check test for overloaded new and delete operators. Does not do full
+// coverage of reset/release/Pass() operations as that is redundant with the
+// above.
+TEST(ScopedPtrTest, OverloadedNewAndDelete) {
+ {
+ OverloadedNewAndDelete::ResetCounters();
+ scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
+ EXPECT_TRUE(scoper.get());
+
+ scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+ }
+ EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
+ EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
+}
+
// TODO scoped_ptr_malloc
« no previous file with comments | « base/memory/scoped_ptr.h ('k') | base/memory/scoped_ptr_unittest.nc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698