From 9df5dacf85c3bfcb7db3b5a250c820fdca226d17 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Wed, 20 Dec 2017 13:37:15 -0800 Subject: [PATCH 1/1] test that the value remains alive even if the .then callback takes no arguments Summary: It was not clear to me, if a callback takes no arguments, the underlying value is guaranteed to be alive during the execution of the callback, so I wrote these tests. Reviewed By: yfeldblum Differential Revision: D6594921 fbshipit-source-id: 6a658afc1bf4d29eaa9c62269ddc21c7f897ad01 --- folly/futures/test/ThenTest.cpp | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/folly/futures/test/ThenTest.cpp b/folly/futures/test/ThenTest.cpp index 0bdd9ad5..2ec43725 100644 --- a/folly/futures/test/ThenTest.cpp +++ b/folly/futures/test/ThenTest.cpp @@ -36,6 +36,40 @@ struct Widget { throw std::logic_error("unexpected move assignment"); } }; + +struct CountedWidget : Widget { + static std::vector instances_; + bool alive = true; + /* implicit */ CountedWidget(int v) : Widget(v) { + instances_.push_back(this); + } + CountedWidget(const CountedWidget& other) : Widget(other) { + instances_.push_back(this); + } + CountedWidget(CountedWidget&& other) noexcept(false) + : Widget(std::move(other)) { + other.alive = false; + other.remove(); + instances_.push_back(this); + } + ~CountedWidget() { + if (alive) { + remove(); + } + } + + private: + CountedWidget& operator=(const CountedWidget&) = delete; + CountedWidget& operator=(CountedWidget&&) = delete; + + void remove() { + auto iter = std::find(instances_.begin(), instances_.end(), this); + EXPECT_TRUE(iter != instances_.end()); + instances_.erase(iter); + } +}; + +std::vector CountedWidget::instances_; } // namespace TEST(Then, tryConstructor) { @@ -172,6 +206,29 @@ TEST(Then, constValue) { EXPECT_EQ(future.value(), 23); } +TEST(Then, objectAliveDuringImmediateNoParamContinuation) { + auto f = makeFuture(23); + auto called = false; + f.then([&] { + EXPECT_EQ(CountedWidget::instances_.size(), 1u); + EXPECT_EQ(CountedWidget::instances_[0]->v_, 23); + called = true; + }); + EXPECT_EQ(true, called); +} + +TEST(Then, objectAliveDuringDeferredNoParamContinuation) { + auto p = Promise{}; + bool called = false; + p.getFuture().then([&] { + EXPECT_EQ(CountedWidget::instances_.size(), 1u); + EXPECT_EQ(CountedWidget::instances_[0]->v_, 23); + called = true; + }); + p.setValue(CountedWidget{23}); + EXPECT_EQ(true, called); +} + TEST(Then, voidThenShouldPropagateExceptions) { EXPECT_FALSE(makeFuture(42).then().hasException()); EXPECT_TRUE(makeFuture(std::runtime_error("err")) -- 2.34.1