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

Side by Side Diff: base/prebind_unittest.cc

Issue 6109007: Unified callback system. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/base
Patch Set: Fixing up some comments. Created 9 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/prebind.h"
6 #include "base/uber_callback.h"
7 #include "testing/gmock/include/gmock/gmock.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 using ::testing::Mock;
11 using ::testing::Return;
12 using ::testing::StrictMock;
13
14 namespace base {
15 namespace {
16
17 class NoRef {
18 public:
19 NoRef() {}
20
21 MOCK_METHOD0(VoidMethod0, void(void));
22 MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
23
24 MOCK_METHOD0(IntMethod0, int(void));
25 MOCK_CONST_METHOD0(IntConstMethod0, int(void));
26
27 private:
28 // Particularly important in test to ensure no copies are made.
29 DISALLOW_COPY_AND_ASSIGN(NoRef);
30 };
31
32 class HasRef : public NoRef {
33 public:
34 HasRef() {}
35
36 MOCK_CONST_METHOD0(AddRef, void(void));
37 MOCK_CONST_METHOD0(Release, void(void));
38
39 private:
40 // Particularly important in test to ensure no copies are made.
41 DISALLOW_COPY_AND_ASSIGN(HasRef);
42 };
43
44 class Parent {
45 public:
46 static const int kParentValue;
47 void AddRef(void) const {}
48 void Release(void) const {}
49 virtual void VirtualSet() { value = kParentValue; }
50 virtual void NonVirtualSet() { value = kParentValue; }
51 int value;
52 };
53 const int Parent::kParentValue = 2;
54
55 class Child : public Parent {
56 public:
57 static const int kChildValue;
58 virtual void VirtualSet() { value = kChildValue; }
59 virtual void NonVirtualSet() { value = kChildValue; }
60 };
61 const int Child::kChildValue = 2;
62
63 // Used for probing the number of copies that occur if a type must be coerced
64 // during argument forwarding in the Run() methods.
65 struct DerivedCopyCounter {
66 DerivedCopyCounter(int* copies, int* assigns)
67 : copies_(copies), assigns_(assigns) {
68 }
69 int* copies_;
70 int* assigns_;
71 };
72
73 // Used for probing the number of copies in an argument.
74 class CopyCounter {
75 public:
76 CopyCounter(int* copies, int* assigns)
77 : copies_(copies), assigns_(assigns) {
78 }
79
80 CopyCounter(const CopyCounter& other)
81 : copies_(other.copies_),
82 assigns_(other.assigns_) {
83 (*copies_)++;
84 }
85
86 // Probing for copies from coerscion.
87 CopyCounter(const DerivedCopyCounter& other)
88 : copies_(other.copies_),
89 assigns_(other.assigns_) {
90 (*copies_)++;
91 }
92
93 const CopyCounter& operator=(const CopyCounter& rhs) {
94 copies_ = rhs.copies_;
95 assigns_ = rhs.assigns_;
96
97 if (assigns_) {
98 (*assigns_)++;
99 }
100
101 return *this;
102 }
103
104 private:
105 int* copies_;
106 int* assigns_;
107 };
108
109 // Test functions that we can bind on.
110 template <typename T>
111 T PolymorphicIdentity(T t) {
112 return t;
113 }
114
115 template <typename T>
116 void VoidPolymorphic1(T t) {
117 }
118
119 int Identity(int n) {
120 return n;
121 }
122
123 int Sum(int a, int b, int c, int d, int e, int f) {
124 return a + b + c + d + e + f;
125 }
126
127 const char* CStringIdentity(const char* s) {
128 return s;
129 }
130
131 int UnwrapParent(Parent p) {
132 return p.value;
133 }
134
135 int UnwrapParentPtr(Parent* p) {
136 return p->value;
137 }
138
139 int UnwrapParentConstRef(const Parent& p) {
140 return p.value;
141 }
142
143 // Only useful in no-compile tests.
144 int UnwrapParentRef(Parent& p) {
145 return p.value;
146 }
147
148 class PrebindTest : public ::testing::Test {
149 public:
150 PrebindTest() {
151 const_has_ref_ptr_ = &has_ref_;
152 const_no_ref_ptr_ = &no_ref_;
153 }
154
155 virtual ~PrebindTest() {
156 Mock::VerifyAndClearExpectations(&static_func_mock);
157 }
158
159 static void VoidFunc0(void) {
160 static_func_mock.VoidMethod0();
161 }
162
163 static int IntFunc0(void) { return static_func_mock.IntMethod0(); }
164
165 protected:
166 StrictMock<NoRef> no_ref_;
167 StrictMock<HasRef> has_ref_;
168 const HasRef* const_has_ref_ptr_;
169 const NoRef* const_no_ref_ptr_;
170
171 // Used by the static functions to perform expectations.
172 static StrictMock<NoRef> static_func_mock;
173
174 private:
175 DISALLOW_COPY_AND_ASSIGN(PrebindTest);
176 };
177
178 StrictMock<NoRef> PrebindTest::static_func_mock;
179
180 // Ensur we can create unbound callbacks. We need this to be able to store them
181 // in class members that can be assigned after construction.
182 TEST_F(PrebindTest, DefaultConstruction) {
183 /*
184 Callback<void(void)> c0;
185 Callback<void(int)> c1;
186 Callback<void(int,int)> c2;
187 Callback<void(int,int,int)> c3;
188 Callback<void(int,int,int,int)> c4;
189 Callback<void(int,int,int,int,int)> c5;
190 Callback<void(int,int,int,int,int,int)> c6;
191 */
192 }
193
194 // Sanity check that we can instantiate a callback for each arity.
195 TEST_F(PrebindTest, ArityTest) {
196 Callback<int(void)> c0 = Prebind(&Sum, 32, 16, 8, 4, 2, 1);
197 EXPECT_EQ(63, c0.Run());
198
199 Callback<int(int)> c1= Prebind(&Sum, 32, 16, 8, 4, 2);
200 EXPECT_EQ(75, c1.Run(13));
201
202 Callback<int(int,int)> c2= Prebind(&Sum, 32, 16, 8, 4);
203 EXPECT_EQ(85, c2.Run(13, 12));
204
205 Callback<int(int,int,int)> c3= Prebind(&Sum, 32, 16, 8);
206 EXPECT_EQ(92, c3.Run(13, 12, 11));
207
208 Callback<int(int,int,int,int)> c4= Prebind(&Sum, 32, 16);
209 EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
210
211 Callback<int(int,int,int,int,int)> c5= Prebind(&Sum, 32);
212 EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
213
214 Callback<int(int,int,int,int,int,int)> c6= Prebind(&Sum);
215 EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
216 }
217
218 // Function type support.
219 // - Normal function.
220 // - Method bound to non-const object.
221 // - Const method bound to non-const object.
222 // - Const method bound to const object.
223 // - Derived classes can be used with pointers to non-virtual base functions.
224 // - Derived classes can be used with pointers to virtual base functions (and
225 // preserve virtual dispatch).
226 TEST_F(PrebindTest, FunctionTypeSupport) {
227 EXPECT_CALL(static_func_mock, VoidMethod0());
228 EXPECT_CALL(has_ref_, AddRef()).Times(3);
229 EXPECT_CALL(has_ref_, Release()).Times(3);
230 EXPECT_CALL(has_ref_, VoidMethod0());
231 EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
232
233 Closure cb_normal = Prebind(&VoidFunc0);
234 Closure cb_method = Prebind(&HasRef::VoidMethod0, &has_ref_);
235 Closure cb_const_method_nonconst_obj = Prebind(&HasRef::VoidConstMethod0,
236 &has_ref_);
237 Closure cb_const_method_const_obj = Prebind(&HasRef::VoidConstMethod0,
238 const_has_ref_ptr_);
239 cb_normal.Run();
240 cb_method.Run();
241 cb_const_method_nonconst_obj.Run();
242 cb_const_method_const_obj.Run();
243
244 Child child;
245 child.value = 0;
246 Closure cb_virtual_set = Prebind(&Parent::VirtualSet, &child);
247 cb_virtual_set.Run();
248 EXPECT_EQ(Child::kChildValue, child.value);
249
250 child.value = 0;
251 Closure cb_non_virtual_set = Prebind(&Parent::NonVirtualSet, &child);
252 cb_non_virtual_set.Run();
253 EXPECT_EQ(Parent::kParentValue, child.value);
254 }
255
256 // Return value support.
257 // - function with return value.
258 // - method with return value.
259 // - const method with return value.
260 TEST_F(PrebindTest, ReturnValues) {
261 EXPECT_CALL(static_func_mock, IntMethod0()).WillOnce(Return(1337));
262 EXPECT_CALL(has_ref_, AddRef()).Times(3);
263 EXPECT_CALL(has_ref_, Release()).Times(3);
264 EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337));
265 EXPECT_CALL(has_ref_, IntConstMethod0())
266 .WillOnce(Return(41337))
267 .WillOnce(Return(51337));
268
269 Callback<int(void)> cb_normal = Prebind(&IntFunc0);
270 Callback<int(void)> cb_method = Prebind(&HasRef::IntMethod0, &has_ref_);
271 Callback<int(void)> cb_const_method_nonconst_obj =
272 Prebind(&HasRef::IntConstMethod0, &has_ref_);
273 Callback<int(void)> cb_const_method_const_obj =
274 Prebind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
275 EXPECT_EQ(1337, cb_normal.Run());
276 EXPECT_EQ(31337, cb_method.Run());
277 EXPECT_EQ(41337, cb_const_method_nonconst_obj.Run());
278 EXPECT_EQ(51337, cb_const_method_const_obj.Run());
279 }
280
281 // Argument binding tests.
282 // - Argument binding to primitive.
283 // - Argument binding to a literal integer.
284 // - Argument binding to a literal string.
285 // - Argument binding with template function.
286 // - Argument binding to an object.
287 // - Argument gets type converted.
288 // - Pointer argument gets converted.
289 // - Const Reference forces conversion.
290 TEST_F(PrebindTest, ArgumentBinding) {
291 int n = 2;
292
293 Callback<int(void)> cb_bind_primitive = Prebind(&Identity, n);
294 EXPECT_EQ(n, cb_bind_primitive.Run());
295
296 Callback<int(void)> cb_bind_int_literal = Prebind(&Identity, 3);
297 EXPECT_EQ(3, cb_bind_int_literal.Run());
298
299 /*
300 Callback<const char*(void)> cb_bind_string_literal =
301 Prebind(&CStringIdentity, "hi");
302 EXPECT_STREQ("hi", cb_bind_string_literal.Run());
303 */
304
305 Callback<int(void)> cb_bind_template_function =
306 Prebind(&PolymorphicIdentity<int>, 4);
307 EXPECT_EQ(4, cb_bind_template_function.Run());
308
309 Parent p;
310 p.value = 5;
311 Callback<int(void)> cb_bind_object = Prebind(&UnwrapParent, p);
312 EXPECT_EQ(5, cb_bind_object.Run());
313
314 Child c;
315 c.value = 6;
316 Callback<int(void)> cb_bind_promotes = Prebind(&UnwrapParent, c);
317 EXPECT_EQ(6, cb_bind_promotes.Run());
318
319 c.value = 7;
320 Callback<int(void)> cb_bind_pointer_promotes = Prebind(&UnwrapParentPtr, &c);
321 EXPECT_EQ(7, cb_bind_pointer_promotes.Run());
322
323 c.value = 8;
324 Callback<int(void)> cb_bind_const_reference_promotes =
325 Prebind(&UnwrapParentConstRef, c);
326 EXPECT_EQ(8, cb_bind_const_reference_promotes.Run());
327 }
328
329 // Unretained() wrapper support.
330 // - method bound to Unretained() non-object.
331 // - const method bound to Unretained() non-const object.
332 // - const method bound to Unretained() const object.
333 // - Unretained does not take a copy of the object.
334 TEST_F(PrebindTest, Unretained) {
335 EXPECT_CALL(no_ref_, VoidMethod0());
336 EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
337
338 Callback<void(void)> cb_method =
339 Prebind(&NoRef::VoidMethod0, Unretained(&no_ref_));
340 cb_method.Run();
341
342 Callback<void(void)> cb_const_method =
343 Prebind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
344 cb_const_method.Run();
345
346 Callback<void(void)> cb_const_method_const_ptr =
347 Prebind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
348 cb_const_method_const_ptr.Run();
349 }
350
351 // ConstRef() wrapper support.
352 // - binding w/o ConstRef takes a copy.
353 // - binding a ConstRef takes a reference.
354 TEST_F(PrebindTest, ConstRef) {
355 int n = 1;
356
357 Callback<int(void)> cb_copy = Prebind(&Identity, n);
358 Callback<int(void)> cb_const_ref = Prebind(&Identity, ConstRef(n));
359 EXPECT_EQ(n, cb_copy.Run());
360 EXPECT_EQ(n, cb_const_ref.Run());
361 n++;
362 EXPECT_EQ(n - 1, cb_copy.Run());
363 EXPECT_EQ(n, cb_const_ref.Run());
364 }
365
366 // Argument Copy-constructor usage for non-reference parameters.
367 // - Prebound arguments are only copied once.
368 // - Forwarded arguments are only copied once.
369 // - Forwarded arguments with coerscions are only copied twice (once for the
370 // coerscion, and one for the final dispatch).
371 TEST_F(PrebindTest, Copies) {
372 int copies = 0;
373 int assigns = 0;
374
375 CopyCounter counter(&copies, &assigns);
376
377 Callback<void(void)> cb_copy =
378 Prebind(&VoidPolymorphic1<CopyCounter>, counter);
379 EXPECT_GE(1, copies);
380 EXPECT_EQ(0, assigns);
381
382 copies = 0;
383 assigns = 0;
384 Callback<void(CopyCounter)> cb_forward =
385 Prebind(&VoidPolymorphic1<CopyCounter>);
386 cb_forward.Run(counter);
387 EXPECT_GE(1, copies);
388 EXPECT_EQ(0, assigns);
389
390 copies = 0;
391 assigns = 0;
392 DerivedCopyCounter dervied(&copies, &assigns);
393 Callback<void(CopyCounter)> cb_coerce =
394 Prebind(&VoidPolymorphic1<CopyCounter>);
395 cb_coerce.Run(dervied);
396 EXPECT_GE(2, copies);
397 EXPECT_EQ(0, assigns);
398 }
399
400 // Callback construction and assignment tests.
401 // - Construction from an InvokerStorageHolder should not cause ref/deref.
402 // - Assignment from other callback should only cause one ref
403 // TODO(ajwong): Is there actually a way to test this?
404
405 // Missing functionality.
406 // - Invoking the return of Prebind. Prebind(&foo).Run() does not work;
407
408 // No-compile tests. These should not compile. If they do, we are allowing
409 // error-prone, or incorrect behavior in the callback system. Uncomment the
410 // tests to check.
411 TEST_F(PrebindTest, NoCompile) {
412 // - Method bound to const-object.
413 //
414 // Only const methods should be allowed to work with const objects.
415 //
416 // Callback<void(void)> cb_method_to_const =
417 // Prebind(&HasRef::VoidMethod0, const_has_ref_ptr_);
418 // cb_method_to_const.Run();
419
420 // - Method bound to non-refcounted object.
421 // - Const Method bound to non-refcounted object.
422 //
423 // We require refcounts unless you have Unretained().
424 //
425 // Callback<void(void)> cb_no_ref =
426 // Prebind(&NoRef::VoidMethod0, &no_ref_);
427 // cb_no_ref.Run();
428 // Callback<void(void)> cb_no_ref_const =
429 // Prebind(&NoRef::VoidConstMethod0, &no_ref_);
430 // cb_no_ref_const.Run();
431
432 // - Unretained() used with a refcounted object.
433 //
434 // If the object supports refcounts, unretaining it in the callback is a
435 // memory management contract break.
436 Callback<void(void)> cb_unretained =
437 Prebind(&HasRef::VoidConstMethod0, Unretained(&has_ref_));
438 cb_unretained.Run();
439
440 // - Const argument used with non-const pointer parameter of same type.
441 // - Const argument used with non-const pointer parameter of super type.
442 //
443 // This is just a const-correctness check.
444 //
445 // const Parent* const_parent_ptr;
446 // const Child* const_child_ptr;
447 // Callback<Parent*(void)> cb_pointer_same =
448 // Prebind(&PolymorphicIdentity<Parent*>, const_parent_ptr);
449 // cb_pointer_same.Run();
450 // Callback<Parent*(void)> cb_pointer_super =
451 // Prebind(&PolymorphicIdentity<Parent*>, const_child_ptr);
452 // cb_pointer_super.Run();
453
454 // - Construction of Callback<A> from Callback<B> if A is supertype of B.
455 // Specific example: Callback<void(void)> a; Callback<int(void)> b; a = b;
456 //
457 // While this is technically safe, most people aren't used to it when coding
458 // C++ so if this is happening, it is almost certainly an error.
459 //
460 // Callback<int(void)> cb_a0 = Prebind(&Identity, 1);
461 // Callback<void(void)> cb_b0 = cb_a0;
462
463 // - Assignment of Callback<A> from Callback<B> if A is supertype of B.
464 // See explanation above.
465 //
466 // Callback<int(void)> cb_a1 = Prebind(&Identity, 1);
467 // Callback<void(void)> cb_b1;
468 // cb_a1 = cb_b1;
469
470 // - Functions with reference parameters, unsupported.
471 //
472 // Reference parameters are disallowed by the google style guide, and since we
473 // are doing argument forwarding it becomes very tricky to avoid copies,
474 // maintain const correctness, and not accidentally have the function be
475 // modifying a temporary.
476 Parent p;
477 Callback<int(Parent&)> cb_ref_arg = Prebind(&UnwrapParentRef);
478 cb_ref_arg.Run(p);
479 // Callback<int(void)> cb_ref = Prebind(&UnwrapParentRef, p);
480 // cb_ref.Run();
481 }
482
483 } // namespace
484 } // namespace base
OLDNEW
« no previous file with comments | « base/prebind_helpers.h ('k') | base/uber_callback.h » ('j') | base/uber_callback.h.pump » ('J')

Powered by Google App Engine
This is Rietveld 408576698