blob: d0ed717449404544ed3bb502a86ade9807193080 [file] [log] [blame]
// Copyright 2019 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 "hanging_getter.h"
#include <gtest/gtest.h>
namespace bt_lib_fidl {
namespace {
template <typename T, typename Getter = HangingGetter<T>>
class HangingGetterTestBase : public ::testing::Test {
public:
void Watch() {
getter_.Watch([this](T value) {
callback_count_++;
last_value_ = value;
});
}
int callback_count() const { return callback_count_; }
const std::optional<T>& last_value() const { return last_value_; }
Getter* getter() { return &getter_; }
private:
int callback_count_ = 0;
std::optional<T> last_value_;
Getter getter_;
};
using HangingGetterTest = HangingGetterTestBase<bool>;
TEST_F(HangingGetterTest, Armed) {
EXPECT_FALSE(getter()->armed());
Watch();
EXPECT_TRUE(getter()->armed());
}
TEST_F(HangingGetterTest, WatchFailsWhilePending) {
Watch();
EXPECT_EQ(0, callback_count());
Watch();
EXPECT_EQ(0, callback_count());
}
TEST_F(HangingGetterTest, WatchCallbackDeferredWithoutAValue) {
Watch();
EXPECT_EQ(0, callback_count());
EXPECT_FALSE(last_value().has_value());
getter()->Set(false);
EXPECT_EQ(1, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_FALSE(*last_value());
}
TEST_F(HangingGetterTest, WatchCallbackRunsRightAwayWithAValue) {
getter()->Set(false);
EXPECT_EQ(0, callback_count());
EXPECT_FALSE(last_value().has_value());
// Assign the value again to test that the latest value is returned in Watch().
getter()->Set(true);
EXPECT_EQ(0, callback_count());
EXPECT_FALSE(last_value().has_value());
EXPECT_FALSE(getter()->armed());
Watch();
EXPECT_EQ(1, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_TRUE(*last_value());
// Calling Watch() again should succeed and defer the callback.
Watch();
EXPECT_EQ(1, callback_count());
}
TEST_F(HangingGetterTest, MultipleWatchersPending) {
Watch(); // 1
Watch(); // 2
Watch(); // 3
getter()->Set(true);
EXPECT_EQ(3, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_TRUE(*last_value());
EXPECT_FALSE(getter()->armed());
}
TEST_F(HangingGetterTest, OnlyFirstOfManyWatchersRunsWithAValue) {
getter()->Set(true);
// Only the first watch call should result in a callback. The following two are expected to remain
// pending until a new value gets assigned.
Watch(); // 1
Watch(); // 2
Watch(); // 3
EXPECT_EQ(1, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_TRUE(*last_value());
EXPECT_TRUE(getter()->armed());
getter()->Set(false);
EXPECT_EQ(3, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_FALSE(*last_value());
}
TEST_F(HangingGetterTest, WatchClearsExistingValue) {
getter()->Set(true);
Watch();
EXPECT_EQ(1, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_TRUE(*last_value());
// Callback should be deferred.
Watch();
EXPECT_EQ(1, callback_count());
// Test the deferral.
getter()->Set(true);
EXPECT_EQ(2, callback_count());
}
TEST_F(HangingGetterTest, Transform) {
getter()->Set(false);
getter()->Transform([](bool current) {
EXPECT_FALSE(current);
return true;
});
Watch();
EXPECT_EQ(1, callback_count());
ASSERT_TRUE(last_value().has_value());
EXPECT_TRUE(*last_value());
}
using HangingVectorGetterTest = HangingGetterTestBase<std::vector<bool>, HangingVectorGetter<bool>>;
TEST_F(HangingVectorGetterTest, AddAndWatch) {
getter()->Add(false);
getter()->Add(true);
Watch();
EXPECT_EQ(1, callback_count());
EXPECT_TRUE(last_value().has_value());
EXPECT_EQ(2u, last_value()->size());
EXPECT_FALSE((*last_value())[0]);
EXPECT_TRUE((*last_value())[1]);
}
TEST_F(HangingVectorGetterTest, WatchAndAdd) {
Watch();
EXPECT_EQ(0, callback_count());
getter()->Add(true);
EXPECT_EQ(1, callback_count());
EXPECT_TRUE(last_value().has_value());
EXPECT_EQ(1u, last_value()->size());
EXPECT_TRUE((*last_value())[0]);
}
} // namespace
} // namespace bt_lib_fidl