blob: abe959600733be6f7ebc7ffdce3a7fc3ec63ec16 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/base/async/SubscriberList.h"
#include <gtest/gtest.h>
#include <memory>
using android::base::SubscriberList;
using android::base::SubscriptionToken;
using std::unique_ptr;
namespace {
// Everything is public. Life is easy.
class TestClient {
public:
void notify() { ++mCalls; }
int mCalls = 0;
};
class TestFeed {
public:
// This struct is purely instructional.
struct SubscriberInfo {
TestClient* client;
SubscriberInfo(TestClient* c) : client(c) {}
};
using SubscriberList = android::base::SubscriberList<SubscriberInfo>;
SubscriptionToken subscribe(TestClient* client) {
return mSubscribers.emplace(client);
}
SubscriptionToken subscribeViaInsert(TestClient* client) {
SubscriberInfo info(client);
return mSubscribers.insert(info);
}
void notifyAll() {
for (auto& subscriber : mSubscribers) {
subscriber.client->notify();
}
}
SubscriberList mSubscribers;
};
} // namespace
TEST(SubscriberList, insert) {
TestClient client;
TestFeed feed;
auto token = feed.subscribeViaInsert(&client);
feed.notifyAll();
EXPECT_EQ(1, client.mCalls);
feed.notifyAll();
EXPECT_EQ(2, client.mCalls);
token.reset();
feed.notifyAll();
EXPECT_EQ(2, client.mCalls);
}
TEST(SubscriberList, emplace) {
TestClient client;
TestFeed feed;
auto token = feed.subscribe(&client);
feed.notifyAll();
EXPECT_EQ(1, client.mCalls);
feed.notifyAll();
EXPECT_EQ(2, client.mCalls);
token.reset();
feed.notifyAll();
EXPECT_EQ(2, client.mCalls);
}
TEST(SubscriberList, deadList) {
TestClient client1, client2;
unique_ptr<TestFeed> feed(new TestFeed());
auto token1 = feed->subscribe(&client1);
auto token2 = feed->subscribe(&client2);
feed->notifyAll();
EXPECT_EQ(1, client1.mCalls);
EXPECT_EQ(1, client2.mCalls);
token1.reset();
feed->notifyAll();
EXPECT_EQ(1, client1.mCalls);
EXPECT_EQ(2, client2.mCalls);
feed.reset();
// This _may_ crash if our implementation doesn't invalidate tokens
// properly. Unfortunately there isn't a way to make this crash every time.
token2.reset();
}