summaryrefslogtreecommitdiffstats
path: root/mfbt/tests/gtest/TestInitializedOnce.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mfbt/tests/gtest/TestInitializedOnce.cpp')
-rw-r--r--mfbt/tests/gtest/TestInitializedOnce.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/mfbt/tests/gtest/TestInitializedOnce.cpp b/mfbt/tests/gtest/TestInitializedOnce.cpp
new file mode 100644
index 0000000000..a043013451
--- /dev/null
+++ b/mfbt/tests/gtest/TestInitializedOnce.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/InitializedOnce.h"
+
+#include <type_traits>
+
+using namespace mozilla;
+
+namespace {
+template <typename T>
+void AssertIsSome(const T& aVal) {
+ ASSERT_TRUE(aVal);
+ ASSERT_TRUE(aVal.isSome());
+ ASSERT_FALSE(aVal.isNothing());
+}
+
+template <typename T>
+void AssertIsNothing(const T& aVal) {
+ ASSERT_FALSE(aVal);
+ ASSERT_FALSE(aVal.isSome());
+ ASSERT_TRUE(aVal.isNothing());
+}
+
+static_assert(std::is_trivially_destructible_v<InitializedOnce<const int>>);
+static_assert(std::is_trivially_destructible_v<LazyInitializedOnce<const int>>);
+
+static_assert(!std::is_copy_constructible_v<InitializedOnce<const int>>);
+static_assert(!std::is_copy_assignable_v<InitializedOnce<const int>>);
+
+static_assert(!std::is_default_constructible_v<InitializedOnce<const int>>);
+static_assert(std::is_default_constructible_v<LazyInitializedOnce<const int>>);
+static_assert(std::is_default_constructible_v<
+ LazyInitializedOnceEarlyDestructible<const int>>);
+
+// XXX We cannot test for move-constructability/move-assignability at the
+// moment, since the operations are always defined, but trigger static_assert's
+// if they should not be used. This is not too bad, since we are never copyable.
+
+constexpr InitializedOnce<const int>* kPtrInitializedOnceIntLazyInitForbid =
+ nullptr;
+constexpr LazyInitializedOnce<const int>* kPtrInitializedOnceIntLazyInitAllow =
+ nullptr;
+constexpr LazyInitializedOnceEarlyDestructible<const int>*
+ kPtrInitializedOnceIntLazyInitAllowResettable = nullptr;
+
+template <class T, typename = decltype(std::declval<T*>()->destroy())>
+constexpr bool test_has_destroy_method(const T*) {
+ return true;
+}
+constexpr bool test_has_destroy_method(...) { return false; }
+
+static_assert(test_has_destroy_method(kPtrInitializedOnceIntLazyInitForbid));
+static_assert(!test_has_destroy_method(kPtrInitializedOnceIntLazyInitAllow));
+static_assert(
+ test_has_destroy_method(kPtrInitializedOnceIntLazyInitAllowResettable));
+
+template <class T,
+ typename = decltype(std::declval<T*>()->init(std::declval<int>()))>
+constexpr bool test_has_init_method(const T*) {
+ return true;
+}
+constexpr bool test_has_init_method(...) { return false; }
+
+static_assert(!test_has_init_method(kPtrInitializedOnceIntLazyInitForbid));
+static_assert(test_has_init_method(kPtrInitializedOnceIntLazyInitAllow));
+static_assert(
+ test_has_init_method(kPtrInitializedOnceIntLazyInitAllowResettable));
+
+struct MoveOnly {
+ explicit constexpr MoveOnly(int aValue) : mValue{aValue} {}
+
+ MoveOnly(MoveOnly&&) = default;
+ MoveOnly& operator=(MoveOnly&&) = default;
+
+ int mValue;
+};
+
+} // namespace
+
+constexpr int testValue = 32;
+
+TEST(InitializedOnce, ImmediateInit)
+{
+ constexpr InitializedOnce<const MoveOnly> val{testValue};
+
+ // compile-time assertions
+ static_assert(val);
+ static_assert(val.isSome());
+ static_assert(!val.isNothing());
+ static_assert(testValue == (*val).mValue);
+ static_assert(testValue == val->mValue);
+ static_assert(testValue == val.ref().mValue);
+
+ // run-time assertions
+ AssertIsSome(val);
+ ASSERT_EQ(testValue, (*val).mValue);
+ ASSERT_EQ(testValue, val->mValue);
+ ASSERT_EQ(testValue, val.ref().mValue);
+}
+
+TEST(InitializedOnce, ImmediateInitReset)
+{
+ InitializedOnce<const MoveOnly> val{testValue};
+ val.destroy();
+
+ AssertIsNothing(val);
+}
+
+TEST(InitializedOnce, MoveConstruct)
+{
+ InitializedOnce<const MoveOnly> oldVal{testValue};
+ InitializedOnce<const MoveOnly> val{std::move(oldVal)};
+
+ AssertIsNothing(oldVal);
+ AssertIsSome(val);
+}
+
+TEST(InitializedOnceAllowLazy, DefaultCtor)
+{
+ LazyInitializedOnce<const MoveOnly> val;
+
+ AssertIsNothing(val);
+}
+
+TEST(InitializedOnceAllowLazy, Init)
+{
+ LazyInitializedOnce<const MoveOnly> val;
+ val.init(testValue);
+
+ AssertIsSome(val);
+ ASSERT_EQ(testValue, (*val).mValue);
+ ASSERT_EQ(testValue, val->mValue);
+ ASSERT_EQ(testValue, val.ref().mValue);
+}
+
+TEST(InitializedOnceAllowLazy, do_Init)
+{
+ LazyInitializedOnce<const MoveOnly> val;
+ do_Init(val) = MoveOnly{testValue};
+
+ AssertIsSome(val);
+ ASSERT_EQ(testValue, (*val).mValue);
+ ASSERT_EQ(testValue, val->mValue);
+ ASSERT_EQ(testValue, val.ref().mValue);
+}
+
+TEST(InitializedOnceAllowLazyResettable, DefaultCtor)
+{
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> val;
+
+ AssertIsNothing(val);
+}
+
+TEST(InitializedOnceAllowLazyResettable, Init)
+{
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> val;
+ val.init(testValue);
+
+ AssertIsSome(val);
+ ASSERT_EQ(testValue, (*val).mValue);
+ ASSERT_EQ(testValue, val->mValue);
+ ASSERT_EQ(testValue, val.ref().mValue);
+}
+
+TEST(InitializedOnceAllowLazyResettable, InitReset)
+{
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> val;
+ val.init(testValue);
+ val.destroy();
+
+ AssertIsNothing(val);
+}
+
+TEST(InitializedOnceAllowLazyResettable, MoveConstruct)
+{
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> oldVal{testValue};
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> val{std::move(oldVal)};
+
+ AssertIsNothing(oldVal);
+ AssertIsSome(val);
+}
+
+TEST(InitializedOnceAllowLazyResettable, MoveAssign)
+{
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> oldVal{testValue};
+ LazyInitializedOnceEarlyDestructible<const MoveOnly> val;
+
+ val = std::move(oldVal);
+
+ AssertIsNothing(oldVal);
+ AssertIsSome(val);
+}
+
+// XXX How do we test for assertions to be hit?