| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/fpromise/promise.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "unittest_utils.h" |
| |
| namespace { |
| |
| class fake_context : public fpromise::context { |
| public: |
| fpromise::executor* executor() const override { ASSERT_CRITICAL(false); } |
| fpromise::suspended_task suspend_task() override { ASSERT_CRITICAL(false); } |
| }; |
| |
| TEST(FutureTests, empty_future) { |
| fake_context context; |
| |
| { |
| fpromise::future<> nihil; |
| EXPECT_EQ(fpromise::future_state::empty, nihil.state()); |
| EXPECT_FALSE(nihil); |
| EXPECT_TRUE(nihil.is_empty()); |
| EXPECT_FALSE(nihil.is_pending()); |
| EXPECT_FALSE(nihil.is_ok()); |
| EXPECT_FALSE(nihil.is_error()); |
| EXPECT_FALSE(nihil.is_ready()); |
| EXPECT_FALSE(nihil(context)); |
| |
| EXPECT_TRUE(nihil == nullptr); |
| EXPECT_TRUE(nullptr == nihil); |
| EXPECT_FALSE(nihil != nullptr); |
| EXPECT_FALSE(nullptr != nihil); |
| } |
| |
| { |
| fpromise::future<> nihil(nullptr); |
| EXPECT_EQ(fpromise::future_state::empty, nihil.state()); |
| EXPECT_FALSE(nihil); |
| EXPECT_TRUE(nihil.is_empty()); |
| EXPECT_FALSE(nihil.is_pending()); |
| EXPECT_FALSE(nihil.is_ok()); |
| EXPECT_FALSE(nihil.is_error()); |
| EXPECT_FALSE(nihil.is_ready()); |
| EXPECT_FALSE(nihil(context)); |
| } |
| |
| { |
| fpromise::future<> nihil(fpromise::promise<>(nullptr)); |
| EXPECT_EQ(fpromise::future_state::empty, nihil.state()); |
| EXPECT_FALSE(nihil); |
| EXPECT_TRUE(nihil.is_empty()); |
| EXPECT_FALSE(nihil.is_pending()); |
| EXPECT_FALSE(nihil.is_ok()); |
| EXPECT_FALSE(nihil.is_error()); |
| EXPECT_FALSE(nihil.is_ready()); |
| EXPECT_FALSE(nihil(context)); |
| } |
| |
| { |
| fpromise::future<> nihil(fpromise::pending()); |
| EXPECT_EQ(fpromise::future_state::empty, nihil.state()); |
| EXPECT_FALSE(nihil); |
| EXPECT_TRUE(nihil.is_empty()); |
| EXPECT_FALSE(nihil.is_pending()); |
| EXPECT_FALSE(nihil.is_ok()); |
| EXPECT_FALSE(nihil.is_error()); |
| EXPECT_FALSE(nihil.is_ready()); |
| EXPECT_FALSE(nihil(context)); |
| } |
| } |
| |
| TEST(FutureTests, pending_future) { |
| fake_context context; |
| |
| uint64_t run_count = 0; |
| fpromise::future<int, int> fut( |
| fpromise::make_promise([&](fpromise::context& context) -> fpromise::result<int, int> { |
| if (++run_count == 3) |
| return fpromise::ok(42); |
| return fpromise::pending(); |
| })); |
| EXPECT_EQ(fpromise::future_state::pending, fut.state()); |
| EXPECT_TRUE(fut); |
| EXPECT_FALSE(fut.is_empty()); |
| EXPECT_TRUE(fut.is_pending()); |
| EXPECT_FALSE(fut.is_ok()); |
| EXPECT_FALSE(fut.is_error()); |
| EXPECT_FALSE(fut.is_ready()); |
| |
| EXPECT_FALSE(fut == nullptr); |
| EXPECT_FALSE(nullptr == fut); |
| EXPECT_TRUE(fut != nullptr); |
| EXPECT_TRUE(nullptr != fut); |
| |
| // evaluate the future |
| EXPECT_FALSE(fut(context)); |
| EXPECT_EQ(1, run_count); |
| EXPECT_FALSE(fut(context)); |
| EXPECT_EQ(2, run_count); |
| EXPECT_TRUE(fut(context)); |
| EXPECT_EQ(3, run_count); |
| |
| // check the result |
| EXPECT_EQ(fpromise::future_state::ok, fut.state()); |
| EXPECT_EQ(fpromise::result_state::ok, fut.result().state()); |
| EXPECT_EQ(42, fut.result().value()); |
| |
| // do something similar but this time produce an error to ensure |
| // that this state change works as expected too |
| fut = fpromise::make_promise([&](fpromise::context& context) -> fpromise::result<int, int> { |
| if (++run_count == 5) |
| return fpromise::error(42); |
| return fpromise::pending(); |
| }); |
| EXPECT_EQ(fpromise::future_state::pending, fut.state()); |
| EXPECT_FALSE(fut(context)); |
| EXPECT_EQ(4, run_count); |
| EXPECT_TRUE(fut(context)); |
| EXPECT_EQ(5, run_count); |
| EXPECT_EQ(fpromise::future_state::error, fut.state()); |
| EXPECT_EQ(fpromise::result_state::error, fut.result().state()); |
| EXPECT_EQ(42, fut.result().error()); |
| } |
| |
| TEST(FutureTests, ok_future) { |
| fake_context context; |
| fpromise::future<int> fut(fpromise::ok(42)); |
| EXPECT_EQ(fpromise::future_state::ok, fut.state()); |
| EXPECT_TRUE(fut); |
| EXPECT_FALSE(fut.is_empty()); |
| EXPECT_FALSE(fut.is_pending()); |
| EXPECT_TRUE(fut.is_ok()); |
| EXPECT_FALSE(fut.is_error()); |
| EXPECT_TRUE(fut.is_ready()); |
| EXPECT_TRUE(fut(context)); |
| |
| EXPECT_FALSE(fut == nullptr); |
| EXPECT_FALSE(nullptr == fut); |
| EXPECT_TRUE(fut != nullptr); |
| EXPECT_TRUE(nullptr != fut); |
| |
| // non-destructive access |
| EXPECT_EQ(fpromise::result_state::ok, fut.result().state()); |
| EXPECT_EQ(42, fut.result().value()); |
| EXPECT_EQ(42, fut.value()); |
| |
| // destructive access |
| fut = fpromise::ok(43); |
| EXPECT_EQ(fpromise::future_state::ok, fut.state()); |
| EXPECT_EQ(43, fut.take_result().value()); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| |
| fut = fpromise::ok(44); |
| EXPECT_EQ(fpromise::future_state::ok, fut.state()); |
| EXPECT_EQ(44, fut.take_value()); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| |
| fut = fpromise::ok(45); |
| EXPECT_EQ(fpromise::future_state::ok, fut.state()); |
| EXPECT_EQ(45, fut.take_ok_result().value); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| } |
| |
| TEST(FutureTests, error_future) { |
| fake_context context; |
| fpromise::future<void, int> fut(fpromise::error(42)); |
| EXPECT_EQ(fpromise::future_state::error, fut.state()); |
| EXPECT_TRUE(fut); |
| EXPECT_FALSE(fut.is_empty()); |
| EXPECT_FALSE(fut.is_pending()); |
| EXPECT_FALSE(fut.is_ok()); |
| EXPECT_TRUE(fut.is_error()); |
| EXPECT_TRUE(fut.is_ready()); |
| EXPECT_TRUE(fut(context)); |
| |
| EXPECT_FALSE(fut == nullptr); |
| EXPECT_FALSE(nullptr == fut); |
| EXPECT_TRUE(fut != nullptr); |
| EXPECT_TRUE(nullptr != fut); |
| |
| // non-destructive access |
| EXPECT_EQ(fpromise::result_state::error, fut.result().state()); |
| EXPECT_EQ(42, fut.result().error()); |
| EXPECT_EQ(42, fut.error()); |
| |
| // destructive access |
| fut = fpromise::error(43); |
| EXPECT_EQ(fpromise::future_state::error, fut.state()); |
| EXPECT_EQ(43, fut.take_result().error()); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| |
| fut = fpromise::error(44); |
| EXPECT_EQ(fpromise::future_state::error, fut.state()); |
| EXPECT_EQ(44, fut.take_error()); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| |
| fut = fpromise::error(45); |
| EXPECT_EQ(fpromise::future_state::error, fut.state()); |
| EXPECT_EQ(45, fut.take_error_result().error); |
| EXPECT_EQ(fpromise::future_state::empty, fut.state()); |
| } |
| |
| TEST(FutureTests, assignment_and_swap) { |
| fpromise::future<> x; |
| EXPECT_EQ(fpromise::future_state::empty, x.state()); |
| |
| x = fpromise::ok(); |
| EXPECT_EQ(fpromise::future_state::ok, x.state()); |
| |
| x = fpromise::error(); |
| EXPECT_EQ(fpromise::future_state::error, x.state()); |
| |
| x = fpromise::pending(); |
| EXPECT_EQ(fpromise::future_state::empty, x.state()); |
| |
| x = nullptr; |
| EXPECT_EQ(fpromise::future_state::empty, x.state()); |
| |
| x = fpromise::promise<>(); |
| EXPECT_EQ(fpromise::future_state::empty, x.state()); |
| |
| x = fpromise::make_promise([] {}); |
| EXPECT_EQ(fpromise::future_state::pending, x.state()); |
| |
| fpromise::future<> y(std::move(x)); |
| EXPECT_EQ(fpromise::future_state::pending, y.state()); |
| EXPECT_EQ(fpromise::future_state::empty, x.state()); |
| |
| x.swap(y); |
| EXPECT_EQ(fpromise::future_state::pending, x.state()); |
| EXPECT_EQ(fpromise::future_state::empty, y.state()); |
| |
| x.swap(x); |
| EXPECT_EQ(fpromise::future_state::pending, x.state()); |
| } |
| |
| TEST(FutureTests, make_future) { |
| fake_context context; |
| uint64_t run_count = 0; |
| auto fut = fpromise::make_future(fpromise::make_promise([&] { |
| run_count++; |
| return fpromise::ok(42); |
| })); |
| EXPECT_TRUE(fut(context)); |
| EXPECT_EQ(42, fut.value()); |
| } |
| |
| // Ensure that fpromise::future is considered nullable so that there is |
| // consistency with the fact that it can be initialized and assigned from |
| // nullptr similar to fit::function. |
| static_assert(fit::is_nullable<fpromise::future<>>::value, ""); |
| |
| } // namespace |