blob: 49ca688d90209e3a40a95bf061e1728481ba911e [file] [log] [blame]
// Copyright 2023 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/poll.h"
#include <type_traits>
#include "gtest/gtest.h"
#include "pw_result/result.h"
namespace pw::async2 {
namespace {
class MoveOnly {
public:
MoveOnly() = delete;
MoveOnly(int value) : value_(value) {}
MoveOnly(const MoveOnly&) = delete;
MoveOnly& operator=(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) = default;
MoveOnly& operator=(MoveOnly&&) = default;
int value() const { return value_; }
private:
int value_;
};
struct Immovable {
public:
Immovable() = delete;
Immovable(MoveOnly&& value) : value_(std::move(value)) {}
Immovable(const Immovable&) = delete;
Immovable& operator=(const Immovable&) = delete;
Immovable(Immovable&&) = delete;
Immovable& operator=(Immovable&&) = delete;
int value() const { return value_.value(); }
private:
MoveOnly value_;
};
TEST(Poll, ConstructsReadyInPlace) {
Poll<Immovable> mr(std::in_place, MoveOnly(5));
EXPECT_TRUE(mr.IsReady());
EXPECT_EQ(mr->value(), 5);
}
TEST(Poll, ConstructsReadyFromValueType) {
Poll<MoveOnly> mr = MoveOnly(5);
EXPECT_TRUE(mr.IsReady());
EXPECT_EQ(mr->value(), 5);
}
TEST(Poll, ConstructsFromValueConvertibleToValueType) {
Poll<Immovable> mr(MoveOnly(5));
EXPECT_TRUE(mr.IsReady());
EXPECT_EQ(mr->value(), 5);
}
TEST(Poll, ConstructsFromPollWithValueConvertibleToValueType) {
Poll<MoveOnly> move_poll(MoveOnly(5));
Poll<Immovable> no_move_poll(std::move(move_poll));
EXPECT_TRUE(no_move_poll.IsReady());
EXPECT_EQ(no_move_poll->value(), 5);
}
TEST(Poll, ConstructsPendingFromPendingType) {
Poll<MoveOnly> mr(Pending());
EXPECT_FALSE(mr.IsReady());
}
TEST(Poll, ConstructorInfersValueType) {
auto res = Poll("hello");
static_assert(std::is_same_v<decltype(res), Poll<const char*>>);
EXPECT_TRUE(res.IsReady());
EXPECT_STREQ(res.value(), "hello");
}
TEST(Poll, ReadinessOnReadyValueReturnsReadyWithoutValue) {
Poll<int> v = Ready(5);
Poll<> readiness = v.Readiness();
EXPECT_TRUE(readiness.IsReady());
}
TEST(Poll, ReadinessOnPendingValueReturnsPendingWithoutValue) {
Poll<int> v = Pending();
Poll<> readiness = v.Readiness();
EXPECT_TRUE(readiness.IsPending());
}
TEST(Poll, ReadyToString) {
char buffer[128] = {};
Poll<> v = Ready();
EXPECT_EQ(5u, ToString(v, buffer).size());
EXPECT_STREQ("Ready", buffer);
}
TEST(Poll, ReadyValueToString) {
char buffer[128] = {};
Poll<uint16_t> v = 5;
EXPECT_EQ(8u, ToString(v, buffer).size());
EXPECT_STREQ("Ready(5)", buffer);
}
TEST(Poll, PendingToString) {
char buffer[128] = {};
Poll<uint16_t> v = Pending();
EXPECT_EQ(7u, ToString(v, buffer).size());
EXPECT_STREQ("Pending", buffer);
}
TEST(PendingFunction, ReturnsValueConvertibleToPendingPoll) {
Poll<MoveOnly> mr = Pending();
EXPECT_FALSE(mr.IsReady());
}
TEST(ReadyFunction, CalledWithNoArgumentsReturnsPollWithReadyType) {
Poll<> mr = Ready();
EXPECT_TRUE(mr.IsReady());
[[maybe_unused]] ReadyType& ready_value = mr.value();
}
TEST(ReadyFunction, ConstructsReadyInPlace) {
Poll<Immovable> mr = Ready<Immovable>(std::in_place, MoveOnly(5));
EXPECT_TRUE(mr.IsReady());
EXPECT_EQ(mr->value(), 5);
}
TEST(ReadyFunction, ConstructsReadyFromValueType) {
Poll<MoveOnly> mr = Ready(MoveOnly(5));
EXPECT_TRUE(mr.IsReady());
EXPECT_EQ(mr->value(), 5);
}
Poll<Result<int>> EndToEndTest(int input) {
if (input == 0) {
// Check that returning plain ``Status`` works.
return Status::PermissionDenied();
}
if (input == 1) {
// Check that returning ``Pending`` works.
return Pending();
}
if (input == 2) {
// Check that returning ``Result<int>`` works.
Result<int> v = 2;
return v;
}
if (input == 3) {
// Check that returning plain ``int`` works.
return 3;
}
if (input == 4) {
// Check that returning ``Poll<int>`` works.
return Ready(4);
}
if (input == 5) {
// Check that returning ``Poll<Status>`` works.
return Ready(Status::DataLoss());
}
return Status::Unknown();
}
TEST(EndToEndTest, ReturnsStatus) {
Poll<Result<int>> result = EndToEndTest(0);
ASSERT_TRUE(result.IsReady());
EXPECT_EQ(result->status(), Status::PermissionDenied());
}
TEST(EndToEndTest, ReturnsPending) {
Poll<Result<int>> result = EndToEndTest(1);
EXPECT_FALSE(result.IsReady());
}
TEST(EndToEndTest, ReturnsValue) {
Poll<Result<int>> result = EndToEndTest(3);
ASSERT_TRUE(result.IsReady());
ASSERT_TRUE(result->ok());
EXPECT_EQ(**result, 3);
}
TEST(EndToEndTest, ReturnsReady) {
Poll<Result<int>> result = EndToEndTest(4);
ASSERT_TRUE(result.IsReady());
ASSERT_TRUE(result->ok());
EXPECT_EQ(**result, 4);
}
TEST(EndToEndTest, ReturnsPollStatus) {
Poll<Result<int>> result = EndToEndTest(5);
ASSERT_TRUE(result.IsReady());
EXPECT_EQ(result->status(), Status::DataLoss());
}
} // namespace
} // namespace pw::async2