summaryrefslogtreecommitdiffstats
path: root/distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp')
-rw-r--r--distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp b/distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp
new file mode 100644
index 000000000..824845f20
--- /dev/null
+++ b/distrib/android-emugl/shared/emugl/common/lazy_instance_unittest.cpp
@@ -0,0 +1,146 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "emugl/common/lazy_instance.h"
+
+#include "emugl/common/mutex.h"
+#include "emugl/common/testing/test_thread.h"
+
+#include <gtest/gtest.h>
+
+namespace emugl {
+
+namespace {
+
+class Foo {
+public:
+ Foo() : mValue(42) {}
+ int get() const { return mValue; }
+ void set(int value) { mValue = value; }
+ ~Foo() { mValue = 13; }
+private:
+ int mValue;
+};
+
+class StaticCounter {
+public:
+ StaticCounter() {
+ Mutex::AutoLock lock(mMutex);
+ mCounter++;
+ }
+
+ int getValue() const {
+ Mutex::AutoLock lock(mMutex);
+ return mCounter;
+ }
+
+private:
+ static Mutex mMutex;
+ static int mCounter;
+};
+
+// NOTE: This introduces a static C++ constructor for this object file,
+// but that's ok because a LazyInstance<Mutex> should not be used to
+// test the behaviour of LazyInstance :-)
+Mutex StaticCounter::mMutex;
+int StaticCounter::mCounter = 0;
+
+} // namespace
+
+TEST(LazyInstance, HasInstance) {
+ LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT;
+ EXPECT_FALSE(foo_instance.hasInstance());
+ EXPECT_FALSE(foo_instance.hasInstance());
+ foo_instance.ptr();
+ EXPECT_TRUE(foo_instance.hasInstance());
+}
+
+TEST(LazyInstance, Simple) {
+ LazyInstance<Foo> foo_instance = LAZY_INSTANCE_INIT;
+ Foo* foo1 = foo_instance.ptr();
+ EXPECT_TRUE(foo1);
+ EXPECT_EQ(42, foo_instance->get());
+ foo1->set(10);
+ EXPECT_EQ(10, foo_instance->get());
+ EXPECT_EQ(foo1, foo_instance.ptr());
+}
+
+// For the following test, launch 1000 threads that each try to get
+// the instance pointer of a lazy instance. Then verify that they're all
+// the same value.
+//
+// The lazy instance has a special constructor that will increment a
+// global counter. This allows us to ensure that it is only called once.
+//
+
+namespace {
+
+// The following is the shared structure between all threads.
+struct MultiState {
+ MultiState(LazyInstance<StaticCounter>* staticCounter) :
+ mMutex(), mStaticCounter(staticCounter), mCount(0) {}
+
+ enum {
+ kMaxThreads = 1000,
+ };
+
+ Mutex mMutex;
+ LazyInstance<StaticCounter>* mStaticCounter;
+ size_t mCount;
+ void* mValues[kMaxThreads];
+ TestThread* mThreads[kMaxThreads];
+};
+
+// The thread function for the test below.
+static void* threadFunc(void* param) {
+ MultiState* state = static_cast<MultiState*>(param);
+ Mutex::AutoLock lock(state->mMutex);
+ if (state->mCount < MultiState::kMaxThreads) {
+ state->mValues[state->mCount++] = state->mStaticCounter->ptr();
+ }
+ return NULL;
+}
+
+} // namespace
+
+TEST(LazyInstance, MultipleThreads) {
+ LazyInstance<StaticCounter> counter_instance = LAZY_INSTANCE_INIT;
+ MultiState state(&counter_instance);
+ const size_t kNumThreads = MultiState::kMaxThreads;
+
+ // Create all threads.
+ for (size_t n = 0; n < kNumThreads; ++n) {
+ state.mThreads[n] = new TestThread(threadFunc, &state);
+ }
+
+ // Wait for their completion.
+ for (size_t n = 0; n < kNumThreads; ++n) {
+ state.mThreads[n]->join();
+ }
+
+ // Now check that the constructor was only called once.
+ EXPECT_EQ(1, counter_instance->getValue());
+
+ // Now compare all the store values, they should be the same.
+ StaticCounter* expectedValue = counter_instance.ptr();
+ for (size_t n = 0; n < kNumThreads; ++n) {
+ EXPECT_EQ(expectedValue, state.mValues[n]) << "For thread " << n;
+ }
+
+ for (size_t n = 0; n < kNumThreads; ++n) {
+ delete state.mThreads[n];
+ }
+}
+
+} // namespace emugl