Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3146)

Unified Diff: base/callback_list_unittest.cc

Issue 22877038: Add a CallbackRegistry class to base/ to manage callbacks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« base/callback_list.h ('K') | « base/callback_list.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/callback_list_unittest.cc
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..66a73171103fe6982f29a93c8e6dc1651c506708
--- /dev/null
+++ b/base/callback_list_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
Avi (use Gerrit) 2013/08/23 16:51:12 New files get "Copyright 2013".
Cait (Slow) 2013/08/23 18:21:10 Done.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_list.h"
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+typedef CallbackList<base::Closure> TestCallbackList;
+
+class Listener {
+ public:
+ explicit Listener() : total(0) {}
+ virtual ~Listener() {}
+ virtual void OnEvent() {
+ total ++;
Avi (use Gerrit) 2013/08/23 16:51:12 No space.
Cait (Slow) 2013/08/23 18:21:10 Done.
+ }
+ int total;
+};
+
+class Remover : public Listener {
+ public:
+ explicit Remover() : removal_cb_(base::Closure()) {}
+ virtual ~Remover() {}
+ virtual void OnEvent() OVERRIDE {
+ Listener::OnEvent();
+ removal_cb_.Run();
+ }
+ virtual void SetCallback(const base::Closure& cb) {
+ removal_cb_ = cb;
+ }
+
+ private:
+ base::Closure removal_cb_;
+};
+
+class Adder : public Listener {
+ public:
+ explicit Adder(TestCallbackList* cb_list)
+ : added(false),
+ cb_list_(cb_list) {}
+ virtual ~Adder() {}
+ virtual void OnAddedEvent() {
+ if (!added) {
+ added = true;
+ cb_list_->RegisterCallback(
+ base::Bind(&Adder::OnEvent, base::Unretained(this)));
+ }
+ }
+ bool added;
+
+ private:
+ TestCallbackList* cb_list_;
+};
+
+class Clearer : public Listener{
Avi (use Gerrit) 2013/08/23 16:51:12 Space before {
Cait (Slow) 2013/08/23 18:21:10 Done.
+ public:
+ explicit Clearer(TestCallbackList* cb_list)
+ : added(false),
+ cb_list_(cb_list) {}
+ virtual ~Clearer() {}
+ virtual void OnClearAndAddEvent() {
+ cb_list_->Clear();
+ cb_list_->RegisterCallback(
+ base::Bind(&Clearer::OnEvent, base::Unretained(this)));
+ added = true;
+ }
+ bool added;
+
+ private:
+ TestCallbackList* cb_list_;
+};
+
+class ListDestructor {
+ public:
+ explicit ListDestructor(TestCallbackList* cb_list)
+ : cb_list_(cb_list) {}
+ virtual ~ListDestructor() {}
+ virtual void OnEvent() {
+ delete cb_list_;
+ }
+
+ private:
+ TestCallbackList* cb_list_;
+};
+
+TEST(CallbackListTest, BasicTest) {
+ TestCallbackList cb_list;
+ Listener a, b, c;
+ base::Closure a_cb = base::Bind(&Listener::OnEvent, base::Unretained(&a));
+ base::Closure b_cb = base::Bind(&Listener::OnEvent, base::Unretained(&b));
+
+ base::Closure remove_a = cb_list.RegisterCallback(a_cb);
+
+ EXPECT_TRUE(cb_list.HasCallback(a_cb));
+ EXPECT_FALSE(cb_list.HasCallback(b_cb));
+
+ base::Closure remove_b = cb_list.RegisterCallback(b_cb);
+ EXPECT_TRUE(cb_list.HasCallback(b_cb));
+
+ EXPECT_FALSE(remove_a.is_null());
+ EXPECT_FALSE(remove_b.is_null());
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ EXPECT_EQ(1, a.total);
+ EXPECT_EQ(1, b.total);
+
+ remove_b.Run();
+
+ base::Closure remove_c = cb_list.RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&c)));
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ EXPECT_EQ(2, a.total);
+ EXPECT_EQ(1, b.total);
+ EXPECT_EQ(1, c.total);
+
+ remove_a.Run();
+ remove_b.Run();
+ remove_c.Run();
+
+ EXPECT_FALSE(cb_list.might_have_callbacks());
+}
+
+TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
+ TestCallbackList cb_list;
+ Listener a, b;
+ Remover remover_1, remover_2;
+
+ base::Closure remover_1_cb = cb_list.RegisterCallback(
+ base::Bind(&Remover::OnEvent, base::Unretained(&remover_1)));
+ base::Closure remover_2_cb = cb_list.RegisterCallback(
+ base::Bind(&Remover::OnEvent, base::Unretained(&remover_2)));
+ base::Closure a_cb = cb_list.RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&a)));
+ base::Closure b_cb = cb_list.RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&b)));
+
+ // |remover_1| will remove itself.
+ remover_1.SetCallback(remover_1_cb);
+ // |remover_2| will remove a.
+ remover_2.SetCallback(a_cb);
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ // |remover_1| runs once (and rms itself), |remover_2| runs once (and removes
Avi (use Gerrit) 2013/08/23 16:51:12 s/rms/removes/
Cait (Slow) 2013/08/23 18:21:10 Done.
+ // a), |a| never runs, and |b| runs once.
+ EXPECT_EQ(1, remover_1.total);
+ EXPECT_EQ(1, remover_2.total);
+ EXPECT_EQ(0, a.total);
+ EXPECT_EQ(1, b.total);
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ // Only |remover_2| and |b| run this time.
+ EXPECT_EQ(1, remover_1.total);
+ EXPECT_EQ(2, remover_2.total);
+ EXPECT_EQ(0, a.total);
+ EXPECT_EQ(2, b.total);
+
+ EXPECT_TRUE(cb_list.might_have_callbacks());
+
+ remover_2_cb.Run();
+ b_cb.Run();
+
+ EXPECT_FALSE(cb_list.might_have_callbacks());
+}
+
+TEST(CallbackListTest, AddCallbacksDuringIteration) {
Avi (use Gerrit) 2013/08/23 16:51:12 So we're only supporting the equivalent of NOTIFY_
Cait (Slow) 2013/08/23 18:21:10 Actually, adding support for EXISTING_ONLY was pre
+ TestCallbackList cb_list;
+ Adder a(&cb_list);
+ Listener b;
+ cb_list.RegisterCallback(
+ base::Bind(&Adder::OnAddedEvent, base::Unretained(&a)));
+ cb_list.RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&b)));
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ EXPECT_EQ(1, a.total);
+ EXPECT_EQ(1, b.total);
+ EXPECT_TRUE(a.added);
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ EXPECT_EQ(2, a.total);
+ EXPECT_EQ(2, b.total);
+}
+
+TEST(CallbackListTest, ClearCallbacksDuringIteration) {
+ TestCallbackList cb_list;
+ Clearer a(&cb_list);
+ Listener b;
+ cb_list.RegisterCallback(
+ base::Bind(&Clearer::OnClearAndAddEvent, base::Unretained(&a)));
+ cb_list.RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&b)));
+
+ FOR_EACH_CALLBACK(base::Closure, cb_list);
+
+ EXPECT_EQ(1, a.total);
+ EXPECT_EQ(0, b.total);
+ EXPECT_TRUE(a.added);
+}
+
+TEST(CallbackListTest, AddNullCallbacks) {
+ TestCallbackList cb_list;
+
+ base::Closure noop = cb_list.RegisterCallback(base::Closure());
+ base::Closure noop2 = cb_list.RegisterCallback(base::Closure());
+
+ // NULL callbacks should not get added.
+ EXPECT_FALSE(cb_list.might_have_callbacks());
+
+ noop.Run();
+ noop2.Run();
+
+ // |noop| and |noop2| should be no-ops.
+ EXPECT_FALSE(cb_list.might_have_callbacks());
+}
+
+TEST(CallbackListTest, IteratorOutlivesList) {
+ TestCallbackList* cb_list = new TestCallbackList();
+ ListDestructor destructor(cb_list);
+ cb_list->RegisterCallback(
+ base::Bind(&ListDestructor::OnEvent, base::Unretained(&destructor)));
+ Listener a;
+ cb_list->RegisterCallback(
+ base::Bind(&Listener::OnEvent, base::Unretained(&a)));
+
+ FOR_EACH_CALLBACK(base::Closure, *cb_list);
+
+ // |a| never gets called, as |cb_list| got deleted first.
+ EXPECT_EQ(0, a.total);
+}
+
+} // namespace
Avi (use Gerrit) 2013/08/23 16:51:12 What happened to tests of callbacks with parameter
Cait (Slow) 2013/08/23 18:21:10 Done.
+} // namespace base
« base/callback_list.h ('K') | « base/callback_list.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698