/* -*- 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 using namespace mozilla; namespace { template void AssertIsSome(const T& aVal) { ASSERT_TRUE(aVal); ASSERT_TRUE(aVal.isSome()); ASSERT_FALSE(aVal.isNothing()); } template void AssertIsNothing(const T& aVal) { ASSERT_FALSE(aVal); ASSERT_FALSE(aVal.isSome()); ASSERT_TRUE(aVal.isNothing()); } static_assert(std::is_trivially_destructible_v>); static_assert(std::is_trivially_destructible_v>); static_assert(!std::is_copy_constructible_v>); static_assert(!std::is_copy_assignable_v>); static_assert(!std::is_default_constructible_v>); static_assert(std::is_default_constructible_v>); static_assert(std::is_default_constructible_v< LazyInitializedOnceEarlyDestructible>); // 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* kPtrInitializedOnceIntLazyInitForbid = nullptr; constexpr LazyInitializedOnce* kPtrInitializedOnceIntLazyInitAllow = nullptr; constexpr LazyInitializedOnceEarlyDestructible* kPtrInitializedOnceIntLazyInitAllowResettable = nullptr; template ()->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 ()->init(std::declval()))> 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 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 val{testValue}; val.destroy(); AssertIsNothing(val); } TEST(InitializedOnce, MoveConstruct) { InitializedOnce oldVal{testValue}; InitializedOnce val{std::move(oldVal)}; AssertIsNothing(oldVal); AssertIsSome(val); } TEST(InitializedOnceAllowLazy, DefaultCtor) { LazyInitializedOnce val; AssertIsNothing(val); } TEST(InitializedOnceAllowLazy, Init) { LazyInitializedOnce 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 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 val; AssertIsNothing(val); } TEST(InitializedOnceAllowLazyResettable, Init) { LazyInitializedOnceEarlyDestructible 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 val; val.init(testValue); val.destroy(); AssertIsNothing(val); } TEST(InitializedOnceAllowLazyResettable, MoveConstruct) { LazyInitializedOnceEarlyDestructible oldVal{testValue}; LazyInitializedOnceEarlyDestructible val{std::move(oldVal)}; AssertIsNothing(oldVal); AssertIsSome(val); } TEST(InitializedOnceAllowLazyResettable, MoveAssign) { LazyInitializedOnceEarlyDestructible oldVal{testValue}; LazyInitializedOnceEarlyDestructible val; val = std::move(oldVal); AssertIsNothing(oldVal); AssertIsSome(val); } // XXX How do we test for assertions to be hit?