/* * Copyright 2020 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/callback_list.h" #include #include #include "api/function_view.h" #include "test/gtest.h" namespace webrtc { namespace { TEST(CallbackList, NoReceiverSingleMessageTest) { CallbackList c; c.Send("message"); } TEST(CallbackList, MultipleParameterMessageTest) { CallbackList c; std::string str = "messege"; int i = 10; c.Send(str, "message1", "message0", 123, &i, str); } TEST(CallbackList, NoParameterMessageTest) { CallbackList<> c; c.Send(); } TEST(CallbackList, ReferenceTest) { CallbackList c; int index = 1; c.AddReceiver([](int& index) { index++; }); c.Send(index); EXPECT_EQ(index, 2); } enum State { kNew, kChecking, }; TEST(CallbackList, SingleEnumValueTest) { CallbackList c; State s1 = kNew; int index = 0; c.AddReceiver([&index](State s) { index++; }); c.Send(s1); EXPECT_EQ(index, 1); } TEST(CallbackList, SingleEnumReferenceTest) { CallbackList c; State s = kNew; c.AddReceiver([](State& s) { s = kChecking; }); c.Send(s); EXPECT_EQ(s, kChecking); } TEST(CallbackList, ConstReferenceTest) { CallbackList c; int i = 0; int index = 1; c.AddReceiver([&i](const int& index) { i = index; }); c.Send(index); EXPECT_EQ(i, 1); } TEST(CallbackList, PointerTest) { CallbackList c; int index = 1; c.AddReceiver([](int* index) { (*index)++; }); c.Send(&index); EXPECT_EQ(index, 2); } TEST(CallbackList, CallByValue) { CallbackList c; int x = 17; c.AddReceiver([&x](int n) { x += n; }); int y = 89; c.Send(y); EXPECT_EQ(x, 106); } void PlusOne(int& a) { a++; } TEST(CallbackList, FunctionPtrTest) { CallbackList c; int index = 1; c.AddReceiver(PlusOne); c.Send(index); EXPECT_EQ(index, 2); } struct LargeNonTrivial { int a[17]; LargeNonTrivial() = default; LargeNonTrivial(LargeNonTrivial&& m) {} ~LargeNonTrivial() = default; void operator()(int& b) { b = 1; } }; TEST(CallbackList, LargeNonTrivialTest) { CallbackList c; int i = 0; static_assert(sizeof(LargeNonTrivial) > UntypedFunction::kInlineStorageSize, ""); c.AddReceiver(LargeNonTrivial()); c.Send(i); EXPECT_EQ(i, 1); } struct LargeTrivial { int a[17]; void operator()(int& x) { x = 1; } }; TEST(CallbackList, LargeTrivial) { CallbackList c; LargeTrivial lt; int i = 0; static_assert(sizeof(lt) > UntypedFunction::kInlineStorageSize, ""); c.AddReceiver(lt); c.Send(i); EXPECT_EQ(i, 1); } struct OnlyNonTriviallyConstructible { OnlyNonTriviallyConstructible() = default; OnlyNonTriviallyConstructible(OnlyNonTriviallyConstructible&& m) {} void operator()(int& a) { a = 1; } }; TEST(CallbackList, OnlyNonTriviallyMoveConstructible) { CallbackList c; int i = 0; c.AddReceiver(OnlyNonTriviallyConstructible()); c.Send(i); EXPECT_EQ(i, 1); } TEST(CallbackList, MultipleReceiverSendTest) { CallbackList c; std::function plus = PlusOne; int index = 1; c.AddReceiver(plus); c.AddReceiver([](int& i) { i--; }); c.AddReceiver(plus); c.AddReceiver(plus); c.Send(index); c.Send(index); EXPECT_EQ(index, 5); } class A { public: void increment(int& i) const { i++; } }; TEST(CallbackList, MemberFunctionTest) { CallbackList c; A a; int index = 1; c.AddReceiver([&a](int& i) { a.increment(i); }); c.Send(index); EXPECT_EQ(index, 2); } // todo(glahiru): Add a test case to catch some error for Karl's first fix TEST(CallbackList, RemoveOneReceiver) { int removal_tag[2]; CallbackList<> c; int accumulator = 0; c.AddReceiver([&accumulator] { accumulator += 1; }); c.AddReceiver(&removal_tag[0], [&accumulator] { accumulator += 10; }); c.AddReceiver(&removal_tag[1], [&accumulator] { accumulator += 100; }); c.Send(); EXPECT_EQ(accumulator, 111); c.RemoveReceivers(&removal_tag[0]); c.Send(); EXPECT_EQ(accumulator, 212); } TEST(CallbackList, RemoveZeroReceivers) { int removal_tag[3]; CallbackList<> c; int accumulator = 0; c.AddReceiver([&accumulator] { accumulator += 1; }); c.AddReceiver(&removal_tag[0], [&accumulator] { accumulator += 10; }); c.AddReceiver(&removal_tag[1], [&accumulator] { accumulator += 100; }); c.Send(); EXPECT_EQ(accumulator, 111); c.RemoveReceivers(&removal_tag[2]); c.Send(); EXPECT_EQ(accumulator, 222); } TEST(CallbackList, RemoveManyReceivers) { int removal_tag; CallbackList<> c; int accumulator = 0; c.AddReceiver([&accumulator] { accumulator += 1; }); c.AddReceiver(&removal_tag, [&accumulator] { accumulator += 10; }); c.AddReceiver([&accumulator] { accumulator += 100; }); c.AddReceiver(&removal_tag, [&accumulator] { accumulator += 1000; }); c.Send(); EXPECT_EQ(accumulator, 1111); c.RemoveReceivers(&removal_tag); c.Send(); EXPECT_EQ(accumulator, 1212); } TEST(CallbackList, RemoveFromSend) { int removal_tag = 0; CallbackList<> c; c.AddReceiver(&removal_tag, [&] { c.RemoveReceivers(&removal_tag); // Do after RemoveReceivers to make sure the lambda is still valid. ++removal_tag; }); c.Send(); c.Send(); EXPECT_EQ(removal_tag, 1); } } // namespace } // namespace webrtc