// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "common/indirect_value.h" #include #include namespace Carbon { namespace { TEST(IndirectValueTest, ConstAccess) { const IndirectValue v = 42; EXPECT_EQ(*v, 42); EXPECT_EQ(v.GetPointer(), &*v); } TEST(IndirectValueTest, MutableAccess) { IndirectValue v = 42; EXPECT_EQ(*v, 42); EXPECT_EQ(v.GetPointer(), &*v); *v = 0; EXPECT_EQ(*v, 0); } struct NonMovable { explicit NonMovable(int i) : i(i) {} NonMovable(NonMovable&&) = delete; auto operator=(NonMovable&&) -> NonMovable& = delete; int i; }; TEST(IndirectValueTest, Create) { IndirectValue v = CreateIndirectValue([] { return NonMovable(42); }); EXPECT_EQ(v->i, 42); } auto GetIntReference() -> const int& { static int i = 42; return i; } TEST(IndirectValueTest, CreateWithDecay) { auto v = CreateIndirectValue(GetIntReference); EXPECT_TRUE((std::is_same_v>)); EXPECT_EQ(*v, 42); } // Test double which presents a value-like interface, but tracks which special // member function (if any) caused it to reach its present value. struct TestValue { TestValue() : state("default constructed") {} TestValue(const TestValue& /*rhs*/) : state("copy constructed") {} TestValue(TestValue&& other) noexcept : state("move constructed") { other.state = "move constructed from"; } auto operator=(const TestValue& /*unused*/) noexcept -> TestValue& { state = "copy assigned"; return *this; } auto operator=(TestValue&& other) noexcept -> TestValue& { state = "move assigned"; other.state = "move assigned from"; return *this; } std::string state; }; TEST(IndirectValueTest, ConstArrow) { const IndirectValue v; EXPECT_EQ(v->state, "default constructed"); } TEST(IndirectValueTest, MutableArrow) { IndirectValue v; EXPECT_EQ(v->state, "default constructed"); v->state = "explicitly set"; EXPECT_EQ(v->state, "explicitly set"); } TEST(IndirectValueTest, CopyConstruct) { IndirectValue v1; auto v2 = v1; EXPECT_EQ(v1->state, "default constructed"); EXPECT_EQ(v2->state, "copy constructed"); } TEST(IndirectValueTest, CopyAssign) { IndirectValue v1; IndirectValue v2; v2 = v1; EXPECT_EQ(v1->state, "default constructed"); EXPECT_EQ(v2->state, "copy assigned"); } TEST(IndirectValueTest, MoveConstruct) { IndirectValue v1; auto v2 = std::move(v1); // While not entirely safe, the `v1->state` access tests move behavior. // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(v1->state, "move constructed from"); EXPECT_EQ(v2->state, "move constructed"); } TEST(IndirectValueTest, MoveAssign) { IndirectValue v1; IndirectValue v2; v2 = std::move(v1); // While not entirely safe, the `v1->state` access tests move behavior. // NOLINTNEXTLINE(bugprone-use-after-move) EXPECT_EQ(v1->state, "move assigned from"); EXPECT_EQ(v2->state, "move assigned"); } TEST(IndirectValueTest, IncompleteType) { struct S { std::optional> v; }; S s = {.v = S{}}; } } // namespace } // namespace Carbon