- add sources.
[platform/framework/web/crosswalk.git] / src / base / lazy_instance_unittest.cc
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/at_exit.h"
6 #include "base/atomic_sequence_num.h"
7 #include "base/lazy_instance.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/threading/simple_thread.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace {
13
14 base::StaticAtomicSequenceNumber constructed_seq_;
15 base::StaticAtomicSequenceNumber destructed_seq_;
16
17 class ConstructAndDestructLogger {
18  public:
19   ConstructAndDestructLogger() {
20     constructed_seq_.GetNext();
21   }
22   ~ConstructAndDestructLogger() {
23     destructed_seq_.GetNext();
24   }
25 };
26
27 class SlowConstructor {
28  public:
29   SlowConstructor() : some_int_(0) {
30     // Sleep for 1 second to try to cause a race.
31     base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
32     ++constructed;
33     some_int_ = 12;
34   }
35   int some_int() const { return some_int_; }
36
37   static int constructed;
38  private:
39   int some_int_;
40 };
41
42 int SlowConstructor::constructed = 0;
43
44 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
45  public:
46   explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
47       : lazy_(lazy) {}
48
49   virtual void Run() OVERRIDE {
50     EXPECT_EQ(12, lazy_->Get().some_int());
51     EXPECT_EQ(12, lazy_->Pointer()->some_int());
52   }
53
54  private:
55   base::LazyInstance<SlowConstructor>* lazy_;
56 };
57
58 }  // namespace
59
60 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
61     LAZY_INSTANCE_INITIALIZER;
62
63 TEST(LazyInstanceTest, Basic) {
64   {
65     base::ShadowingAtExitManager shadow;
66
67     EXPECT_EQ(0, constructed_seq_.GetNext());
68     EXPECT_EQ(0, destructed_seq_.GetNext());
69
70     lazy_logger.Get();
71     EXPECT_EQ(2, constructed_seq_.GetNext());
72     EXPECT_EQ(1, destructed_seq_.GetNext());
73
74     lazy_logger.Pointer();
75     EXPECT_EQ(3, constructed_seq_.GetNext());
76     EXPECT_EQ(2, destructed_seq_.GetNext());
77   }
78   EXPECT_EQ(4, constructed_seq_.GetNext());
79   EXPECT_EQ(4, destructed_seq_.GetNext());
80 }
81
82 static base::LazyInstance<SlowConstructor> lazy_slow =
83     LAZY_INSTANCE_INITIALIZER;
84
85 TEST(LazyInstanceTest, ConstructorThreadSafety) {
86   {
87     base::ShadowingAtExitManager shadow;
88
89     SlowDelegate delegate(&lazy_slow);
90     EXPECT_EQ(0, SlowConstructor::constructed);
91
92     base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
93     pool.AddWork(&delegate, 20);
94     EXPECT_EQ(0, SlowConstructor::constructed);
95
96     pool.Start();
97     pool.JoinAll();
98     EXPECT_EQ(1, SlowConstructor::constructed);
99   }
100 }
101
102 namespace {
103
104 // DeleteLogger is an object which sets a flag when it's destroyed.
105 // It accepts a bool* and sets the bool to true when the dtor runs.
106 class DeleteLogger {
107  public:
108   DeleteLogger() : deleted_(NULL) {}
109   ~DeleteLogger() { *deleted_ = true; }
110
111   void SetDeletedPtr(bool* deleted) {
112     deleted_ = deleted;
113   }
114
115  private:
116   bool* deleted_;
117 };
118
119 }  // anonymous namespace
120
121 TEST(LazyInstanceTest, LeakyLazyInstance) {
122   // Check that using a plain LazyInstance causes the dtor to run
123   // when the AtExitManager finishes.
124   bool deleted1 = false;
125   {
126     base::ShadowingAtExitManager shadow;
127     static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
128     test.Get().SetDeletedPtr(&deleted1);
129   }
130   EXPECT_TRUE(deleted1);
131
132   // Check that using a *leaky* LazyInstance makes the dtor not run
133   // when the AtExitManager finishes.
134   bool deleted2 = false;
135   {
136     base::ShadowingAtExitManager shadow;
137     static base::LazyInstance<DeleteLogger>::Leaky
138         test = LAZY_INSTANCE_INITIALIZER;
139     test.Get().SetDeletedPtr(&deleted2);
140   }
141   EXPECT_FALSE(deleted2);
142 }
143
144 namespace {
145
146 template <size_t alignment>
147 class AlignedData {
148  public:
149   AlignedData() {}
150   ~AlignedData() {}
151   base::AlignedMemory<alignment, alignment> data_;
152 };
153
154 }  // anonymous namespace
155
156 #define EXPECT_ALIGNED(ptr, align) \
157     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
158
159 TEST(LazyInstanceTest, Alignment) {
160   using base::LazyInstance;
161
162   // Create some static instances with increasing sizes and alignment
163   // requirements. By ordering this way, the linker will need to do some work to
164   // ensure proper alignment of the static data.
165   static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
166   static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
167   static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
168
169   EXPECT_ALIGNED(align4.Pointer(), 4);
170   EXPECT_ALIGNED(align32.Pointer(), 32);
171   EXPECT_ALIGNED(align4096.Pointer(), 4096);
172 }