blob: 05aebc23f9efab7463a8c70ba81d888671822122 [file]
// Copyright 2026 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_async2/future_task.h"
#include <optional>
#include <type_traits>
#include "pw_async2/dispatcher_for_test.h"
#include "pw_async2/poll.h"
#include "pw_async2/value_future.h"
#include "pw_unit_test/framework.h"
namespace {
using pw::async2::DispatcherForTest;
using pw::async2::FutureTask;
using pw::async2::Pending;
using pw::async2::Poll;
using pw::async2::Ready;
using pw::async2::ValueFuture;
using pw::async2::ValueProvider;
using pw::async2::VoidFuture;
TEST(FutureTask, ReadyFuture) {
DispatcherForTest dispatcher;
FutureTask<ValueFuture<bool>> task(ValueFuture<bool>::Resolved(true));
dispatcher.Post(task);
dispatcher.RunUntilStalled();
EXPECT_FALSE(task.IsRegistered());
EXPECT_TRUE(task.Wait());
}
TEST(FutureTask, PendingFuture) {
DispatcherForTest dispatcher;
ValueProvider<const char*> provider;
FutureTask<ValueFuture<const char*>> task(provider.Get());
dispatcher.Post(task);
dispatcher.RunUntilStalled();
EXPECT_TRUE(task.IsRegistered());
provider.Resolve("O_o");
dispatcher.RunUntilStalled();
EXPECT_FALSE(task.IsRegistered());
EXPECT_STREQ(task.Wait(), "O_o");
}
class MoveOnlyInt {
public:
MoveOnlyInt(int value) : value_(value) {}
MoveOnlyInt(const MoveOnlyInt&) = delete;
MoveOnlyInt& operator=(const MoveOnlyInt&) = delete;
MoveOnlyInt(MoveOnlyInt&&) = default;
MoveOnlyInt& operator=(MoveOnlyInt&&) = default;
operator int() const { return value_; }
private:
int value_;
};
TEST(FutureTask, Wait) {
DispatcherForTest dispatcher;
ValueProvider<MoveOnlyInt> provider;
FutureTask task(provider.Get());
dispatcher.Post(task);
dispatcher.RunUntilStalled();
provider.Resolve(456);
dispatcher.RunUntilStalled();
EXPECT_EQ(task.TakePoll().value(), 456);
EXPECT_EQ(task.Wait(), 456);
}
TEST(FutureTask, MoveFuture) {
DispatcherForTest dispatcher;
ValueProvider<int> provider;
ValueFuture<int> future = provider.Get();
FutureTask task(std::move(future));
dispatcher.Post(task);
provider.Resolve(-100);
dispatcher.RunUntilStalled();
EXPECT_EQ(task.TakePoll().value(), -100);
}
TEST(FutureTask, VoidFuture) {
DispatcherForTest dispatcher;
ValueProvider<void> provider;
FutureTask<VoidFuture> task(provider.Get());
dispatcher.Post(task);
provider.Resolve();
dispatcher.RunUntilStalled();
task.Join();
}
TEST(FutureTask, Reference) {
DispatcherForTest dispatcher;
ValueProvider<int> provider;
ValueFuture<int> future(provider.Get());
FutureTask task(future);
static_assert(std::is_same_v<FutureTask<ValueFuture<int>&>, decltype(task)>,
"Deduces a reference to a future");
dispatcher.Post(task);
provider.Resolve(404);
dispatcher.RunUntilStalled();
EXPECT_EQ(task.Wait(), 404);
}
TEST(FutureTask, ReferenceTakePoll) {
DispatcherForTest dispatcher;
ValueProvider<int> provider;
ValueFuture<int> future(provider.Get());
FutureTask<ValueFuture<int>&> task(future);
EXPECT_EQ(task.TakePoll(), Pending());
dispatcher.Post(task);
provider.Resolve(500);
dispatcher.RunUntilStalled();
EXPECT_EQ(task.TakePoll(), Ready(500));
}
} // namespace