#include #include "tools/Lazy.h" using namespace testing; // Not copyable, no default constructor, movable struct Foo { const int value; Foo(int value) : value(value) {} Foo() = delete; Foo(const Foo&) = delete; Foo& operator=(const Foo&) = delete; Foo(Foo&&) = default; Foo& operator=(Foo&&) = default; }; TEST(Lazy, basicUsage) { bool lambdaCalled = false; Lazy lazy([&lambdaCalled] { lambdaCalled = true; return Foo(42); }); EXPECT_FALSE(lambdaCalled); EXPECT_FALSE(static_cast(lazy)); EXPECT_EQ(42, (*lazy).value); EXPECT_EQ(42, lazy.value().value); EXPECT_EQ(42, lazy->value); EXPECT_TRUE(lambdaCalled); EXPECT_TRUE(static_cast(lazy)); } TEST(Lazy, constUsage) { bool lambdaCalled = false; const Lazy lazy([&lambdaCalled] { lambdaCalled = true; return Foo(42); }); EXPECT_FALSE(lambdaCalled); EXPECT_FALSE(static_cast(lazy)); EXPECT_EQ(42, (*lazy).value); EXPECT_EQ(42, lazy.value().value); EXPECT_EQ(42, lazy->value); EXPECT_TRUE(lambdaCalled); EXPECT_TRUE(static_cast(lazy)); } TEST(Lazy, copying) { Lazy a; int counter = 0; const auto createValue = [&] { return counter++; }; Lazy b(createValue); a = b; EXPECT_EQ(0, counter); EXPECT_FALSE(static_cast(a)); EXPECT_FALSE(static_cast(b)); EXPECT_EQ(0, a->value); EXPECT_EQ(1, counter); EXPECT_TRUE(static_cast(a)); EXPECT_TRUE(static_cast(b)); EXPECT_EQ(0, b->value); Lazy c(createValue); EXPECT_EQ(1, c->value); } using Expensive = Foo; #define member value; TEST(Lazy, demo) { // Constructor takes function Lazy lazy([] { return Expensive(42); }); // Multiple ways to access value Expensive& a = *lazy; Expensive& b = lazy.value(); auto c = lazy->member; // Check if initialized if (lazy) { /* ... */ } }