Index: third_party/base/nonstd_unique_ptr_unittest.cpp |
diff --git a/third_party/base/nonstd_unique_ptr_unittest.cpp b/third_party/base/nonstd_unique_ptr_unittest.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4a94241d1e80089b233c249366039f6f0494a0bd |
--- /dev/null |
+++ b/third_party/base/nonstd_unique_ptr_unittest.cpp |
@@ -0,0 +1,361 @@ |
+// Copyright 2015 PDFium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <sstream> |
+ |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "macros.h" |
+#include "nonstd_unique_ptr.h" |
+ |
+using nonstd::unique_ptr; |
+ |
+namespace { |
+ |
+// Used to test depth subtyping. |
+class ConDecLoggerParent { |
+ public: |
+ virtual ~ConDecLoggerParent() {} |
+ |
+ virtual void SetPtr(int* ptr) = 0; |
+ |
+ virtual int SomeMeth(int x) const = 0; |
+}; |
+ |
+class ConDecLogger : public ConDecLoggerParent { |
Tom Sepez
2015/09/22 17:36:20
Actually, I want to steal this file to test nonstd
Lei Zhang
2015/09/23 00:38:56
All yours.
|
+ public: |
+ ConDecLogger() : ptr_(nullptr) {} |
+ explicit ConDecLogger(int* ptr) { SetPtr(ptr); } |
+ ~ConDecLogger() override { --*ptr_; } |
Jeffrey Yasskin
2015/09/19 00:00:48
Is "Dec" an abbreviation for "Destruction"?
Lei Zhang
2015/09/23 00:38:56
Tom renamed this in his CL.
|
+ |
+ void SetPtr(int* ptr) override { |
+ ptr_ = ptr; |
+ ++*ptr_; |
+ } |
+ |
+ int SomeMeth(int x) const override { return x; } |
+ |
+ private: |
+ int* ptr_; |
+ |
+ // Disallow evil constructors. |
+ ConDecLogger(const ConDecLogger&) = delete; |
+ void operator=(const ConDecLogger&) = delete; |
+}; |
+ |
+struct CountingDeleter { |
+ explicit CountingDeleter(int* count) : count_(count) {} |
+ inline void operator()(double* ptr) const { (*count_)++; } |
+ int* count_; |
+}; |
+ |
+// Do not delete this function! It's existence is to test that you can |
+// return a temporarily constructed version of the scoper. |
+unique_ptr<ConDecLogger> TestReturnOfType(int* constructed) { |
+ return unique_ptr<ConDecLogger>(new ConDecLogger(constructed)); |
+} |
+ |
+} // namespace |
+ |
+TEST(UniquePtrTest, UniquePtr) { |
+ int constructed = 0; |
+ |
+ // Ensure size of unique_ptr<> doesn't increase unexpectedly. |
+ static_assert(sizeof(int*) >= sizeof(unique_ptr<int>), |
+ "unique_ptr_larger_than_raw_ptr"); |
+ |
+ { |
+ unique_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_TRUE(scoper.get()); |
+ |
+ EXPECT_EQ(10, scoper->SomeMeth(10)); |
+ EXPECT_EQ(10, scoper.get()->SomeMeth(10)); |
+ EXPECT_EQ(10, (*scoper).SomeMeth(10)); |
+ } |
+ EXPECT_EQ(0, constructed); |
+ |
+ // Test reset() and release() |
+ { |
+ unique_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed)); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_TRUE(scoper.get()); |
+ |
+ scoper.reset(new ConDecLogger(&constructed)); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_TRUE(scoper.get()); |
+ |
+ scoper.reset(); |
+ EXPECT_EQ(0, constructed); |
+ EXPECT_FALSE(scoper.get()); |
+ |
+ scoper.reset(new ConDecLogger(&constructed)); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_TRUE(scoper.get()); |
+ |
+ ConDecLogger* take = scoper.release(); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_FALSE(scoper.get()); |
+ delete take; |
+ EXPECT_EQ(0, constructed); |
+ |
+ scoper.reset(new ConDecLogger(&constructed)); |
+ EXPECT_EQ(1, constructed); |
+ EXPECT_TRUE(scoper.get()); |
+ } |
+ EXPECT_EQ(0, constructed); |
+ |
+ // Test swap(), == and != |
+ { |
+ unique_ptr<ConDecLogger> scoper1; |
+ unique_ptr<ConDecLogger> scoper2; |
+ EXPECT_TRUE(scoper1 == scoper2.get()); |
+ EXPECT_FALSE(scoper1 != scoper2.get()); |
+ |
+ ConDecLogger* logger = new ConDecLogger(&constructed); |
+ scoper1.reset(logger); |
+ EXPECT_EQ(logger, scoper1.get()); |
+ EXPECT_FALSE(scoper2.get()); |
+ EXPECT_FALSE(scoper1 == scoper2.get()); |
+ EXPECT_TRUE(scoper1 != scoper2.get()); |
+ |
+ scoper2.swap(scoper1); |
+ EXPECT_EQ(logger, scoper2.get()); |
+ EXPECT_FALSE(scoper1.get()); |
+ EXPECT_FALSE(scoper1 == scoper2.get()); |
+ EXPECT_TRUE(scoper1 != scoper2.get()); |
+ } |
+ EXPECT_EQ(0, constructed); |
+} |
+ |
+TEST(UniquePtrTest, UniquePtrWithArray) { |
+ static const int kNumLoggers = 12; |
+ |
+ int constructed = 0; |
+ |
+ { |
+ unique_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() |
+ { |
+ unique_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. |
+ { |
+ unique_ptr<ConDecLogger[]> scoper1; |
+ unique_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); |
+} |
+ |
+TEST(UniquePtrTest, ReturnTypeBehavior) { |
+ int constructed = 0; |
+ |
+ // Test that we can return a unique_ptr. |
+ { |
+ ConDecLogger* logger = new ConDecLogger(&constructed); |
+ unique_ptr<ConDecLogger> scoper(logger); |
+ EXPECT_EQ(1, constructed); |
+ } |
+ EXPECT_EQ(0, constructed); |
+ |
+ // Test uncaught return type not leak. |
+ { |
+ ConDecLogger* logger = new ConDecLogger(&constructed); |
+ unique_ptr<ConDecLogger> scoper(logger); |
+ EXPECT_EQ(1, constructed); |
+ } |
+ EXPECT_EQ(0, constructed); |
+ |
+ // Call TestReturnOfType() so the compiler doesn't warn for an unused |
+ // function. |
+ { TestReturnOfType(&constructed); } |
+ EXPECT_EQ(0, constructed); |
+} |
+ |
+TEST(UniquePtrTest, CustomDeleter) { |
+ double dummy_value; // Custom deleter never touches this value. |
+ int deletes = 0; |
+ int alternate_deletes = 0; |
+ |
+ // Normal delete support. |
+ { |
+ deletes = 0; |
+ unique_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; |
+ { |
+ unique_ptr<double, CountingDeleter> scoper(nullptr, |
+ 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; |
+ { |
+ unique_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 swap(), ==, !=, and type-safe Boolean. |
+ { |
+ unique_ptr<double, CountingDeleter> scoper1(nullptr, |
+ CountingDeleter(&deletes)); |
+ unique_ptr<double, CountingDeleter> scoper2(nullptr, |
+ 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()); |
+ } |
+} |
+ |
+unique_ptr<int> NullIntReturn() { |
+ return nullptr; |
+} |
+ |
+TEST(UniquePtrTest, Nullptr) { |
+ unique_ptr<int> scoper1(nullptr); |
+ unique_ptr<int> scoper2(new int); |
+ scoper2 = nullptr; |
+ unique_ptr<int> scoper3(NullIntReturn()); |
+ unique_ptr<int> scoper4 = NullIntReturn(); |
+ EXPECT_EQ(nullptr, scoper1.get()); |
+ EXPECT_EQ(nullptr, scoper2.get()); |
+ EXPECT_EQ(nullptr, scoper3.get()); |
+ EXPECT_EQ(nullptr, scoper4.get()); |
+} |
+ |
+unique_ptr<int[]> NullIntArrayReturn() { |
+ return nullptr; |
+} |
+ |
+TEST(UniquePtrTest, NullptrArray) { |
+ unique_ptr<int[]> scoper1(nullptr); |
+ unique_ptr<int[]> scoper2(new int[3]); |
+ scoper2 = nullptr; |
+ unique_ptr<int[]> scoper3(NullIntArrayReturn()); |
+ unique_ptr<int[]> scoper4 = NullIntArrayReturn(); |
+ EXPECT_EQ(nullptr, scoper1.get()); |
+ EXPECT_EQ(nullptr, scoper2.get()); |
+ EXPECT_EQ(nullptr, scoper3.get()); |
+ EXPECT_EQ(nullptr, scoper4.get()); |
+} |
+ |
+// Logging a unique_ptr<T> to an ostream shouldn't convert it to a boolean |
+// value first. |
+TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) { |
+ unique_ptr<int> x(new int); |
+ std::stringstream s1; |
+ s1 << x; |
+ |
+ std::stringstream s2; |
+ s2 << x.get(); |
+ |
+ EXPECT_EQ(s2.str(), s1.str()); |
+} |