summaryrefslogtreecommitdiff
path: root/base/lazy_instance_unittest.cc
diff options
context:
space:
mode:
authorDaniel Erat <derat@google.com>2015-07-06 13:18:13 -0600
committerDaniel Erat <derat@google.com>2015-07-07 08:49:02 -0600
commitb8cf94937c52feb53b55c39e3f82094d27de464c (patch)
tree20cd8f9867dfe9c0c2510899346c744605425b75 /base/lazy_instance_unittest.cc
parent5bb0a2e04cf1346d5a2819f277381c0415549600 (diff)
downloadlibchrome-b8cf94937c52feb53b55c39e3f82094d27de464c.tar.gz
Add upstream code as of Chromium r334380.
Copy the unchanged source from https://chromium.googlesource.com/chromium/src/base/ as of r334380 (really r334285 a.k.a. 23911a0c in the base/ subtree). Also add MODULE_LICENSE_BSD and copy Chromium's current LICENSE file to NOTICE. Bug: 22317122 Change-Id: I89863bfeca67b3a1ff05e6078f2f9ee4e31c5c99
Diffstat (limited to 'base/lazy_instance_unittest.cc')
-rw-r--r--base/lazy_instance_unittest.cc172
1 files changed, 172 insertions, 0 deletions
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000000..ec9ef26732
--- /dev/null
+++ b/base/lazy_instance_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium 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 "base/at_exit.h"
+#include "base/atomic_sequence_num.h"
+#include "base/lazy_instance.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+base::StaticAtomicSequenceNumber constructed_seq_;
+base::StaticAtomicSequenceNumber destructed_seq_;
+
+class ConstructAndDestructLogger {
+ public:
+ ConstructAndDestructLogger() {
+ constructed_seq_.GetNext();
+ }
+ ~ConstructAndDestructLogger() {
+ destructed_seq_.GetNext();
+ }
+};
+
+class SlowConstructor {
+ public:
+ SlowConstructor() : some_int_(0) {
+ // Sleep for 1 second to try to cause a race.
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+ ++constructed;
+ some_int_ = 12;
+ }
+ int some_int() const { return some_int_; }
+
+ static int constructed;
+ private:
+ int some_int_;
+};
+
+int SlowConstructor::constructed = 0;
+
+class SlowDelegate : public base::DelegateSimpleThread::Delegate {
+ public:
+ explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
+ : lazy_(lazy) {}
+
+ void Run() override {
+ EXPECT_EQ(12, lazy_->Get().some_int());
+ EXPECT_EQ(12, lazy_->Pointer()->some_int());
+ }
+
+ private:
+ base::LazyInstance<SlowConstructor>* lazy_;
+};
+
+} // namespace
+
+static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
+ LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, Basic) {
+ {
+ base::ShadowingAtExitManager shadow;
+
+ EXPECT_EQ(0, constructed_seq_.GetNext());
+ EXPECT_EQ(0, destructed_seq_.GetNext());
+
+ lazy_logger.Get();
+ EXPECT_EQ(2, constructed_seq_.GetNext());
+ EXPECT_EQ(1, destructed_seq_.GetNext());
+
+ lazy_logger.Pointer();
+ EXPECT_EQ(3, constructed_seq_.GetNext());
+ EXPECT_EQ(2, destructed_seq_.GetNext());
+ }
+ EXPECT_EQ(4, constructed_seq_.GetNext());
+ EXPECT_EQ(4, destructed_seq_.GetNext());
+}
+
+static base::LazyInstance<SlowConstructor> lazy_slow =
+ LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, ConstructorThreadSafety) {
+ {
+ base::ShadowingAtExitManager shadow;
+
+ SlowDelegate delegate(&lazy_slow);
+ EXPECT_EQ(0, SlowConstructor::constructed);
+
+ base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
+ pool.AddWork(&delegate, 20);
+ EXPECT_EQ(0, SlowConstructor::constructed);
+
+ pool.Start();
+ pool.JoinAll();
+ EXPECT_EQ(1, SlowConstructor::constructed);
+ }
+}
+
+namespace {
+
+// DeleteLogger is an object which sets a flag when it's destroyed.
+// It accepts a bool* and sets the bool to true when the dtor runs.
+class DeleteLogger {
+ public:
+ DeleteLogger() : deleted_(NULL) {}
+ ~DeleteLogger() { *deleted_ = true; }
+
+ void SetDeletedPtr(bool* deleted) {
+ deleted_ = deleted;
+ }
+
+ private:
+ bool* deleted_;
+};
+
+} // anonymous namespace
+
+TEST(LazyInstanceTest, LeakyLazyInstance) {
+ // Check that using a plain LazyInstance causes the dtor to run
+ // when the AtExitManager finishes.
+ bool deleted1 = false;
+ {
+ base::ShadowingAtExitManager shadow;
+ static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
+ test.Get().SetDeletedPtr(&deleted1);
+ }
+ EXPECT_TRUE(deleted1);
+
+ // Check that using a *leaky* LazyInstance makes the dtor not run
+ // when the AtExitManager finishes.
+ bool deleted2 = false;
+ {
+ base::ShadowingAtExitManager shadow;
+ static base::LazyInstance<DeleteLogger>::Leaky
+ test = LAZY_INSTANCE_INITIALIZER;
+ test.Get().SetDeletedPtr(&deleted2);
+ }
+ EXPECT_FALSE(deleted2);
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+ AlignedData() {}
+ ~AlignedData() {}
+ base::AlignedMemory<alignment, alignment> data_;
+};
+
+} // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(LazyInstanceTest, Alignment) {
+ using base::LazyInstance;
+
+ // Create some static instances with increasing sizes and alignment
+ // requirements. By ordering this way, the linker will need to do some work to
+ // ensure proper alignment of the static data.
+ static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
+ static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
+ static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
+
+ EXPECT_ALIGNED(align4.Pointer(), 4);
+ EXPECT_ALIGNED(align32.Pointer(), 32);
+ EXPECT_ALIGNED(align4096.Pointer(), 4096);
+}