Index: base/bind_unittest.cc |
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc |
index f885403c92dfa68b0ba0a4afe534e4c3d39ad918..50845be62041ff639a1fdfcb8d6798fc597721ce 100644 |
--- a/base/bind_unittest.cc |
+++ b/base/bind_unittest.cc |
@@ -150,7 +150,7 @@ class DeleteCounter { |
template <typename T> |
T PassThru(T scoper) { |
- return scoper.Pass(); |
+ return scoper; |
} |
// Some test functions that we can Bind to. |
@@ -327,8 +327,8 @@ TEST_F(BindTest, CurryingRvalueResultOfBind) { |
// preserve virtual dispatch). |
TEST_F(BindTest, FunctionTypeSupport) { |
EXPECT_CALL(static_func_mock_, VoidMethod0()); |
- EXPECT_CALL(has_ref_, AddRef()).Times(5); |
- EXPECT_CALL(has_ref_, Release()).Times(5); |
+ EXPECT_CALL(has_ref_, AddRef()).Times(4); |
+ EXPECT_CALL(has_ref_, Release()).Times(4); |
EXPECT_CALL(has_ref_, VoidMethod0()).Times(2); |
EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2); |
@@ -715,7 +715,7 @@ TEST_F(BindTest, ScopedPtr) { |
// Tests the Passed() function's support for pointers. |
scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes)); |
Callback<scoped_ptr<DeleteCounter>(void)> unused_callback = |
- Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr)); |
+ Bind(&PassThru<scoped_ptr<DeleteCounter>>, Passed(&ptr)); |
EXPECT_FALSE(ptr.get()); |
EXPECT_EQ(0, deletes); |
@@ -752,6 +752,105 @@ TEST_F(BindTest, ScopedPtr) { |
cb_unbound.Run(ptr.Pass()); |
} |
+// RValue support. |
+// - Bind() can take move-only values by RValue-reference. |
+// - Using an RValue gives Callback Ownership. |
+// - Ownership is transferred from Callback to callee on the first Run(). |
+// - Callback supports unbound arguments. |
+TEST_F(BindTest, ScopedPtrRValue) { |
+ int deletes = 0; |
+ |
+ // Tests the Passed() function's support for pointers. |
+ scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes)); |
+ Callback<scoped_ptr<DeleteCounter>(void)> unused_callback = |
+ Bind(&PassThru<scoped_ptr<DeleteCounter>>, std::move(ptr)); |
+ EXPECT_FALSE(ptr.get()); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // If we never invoke the Callback, it retains ownership and deletes. |
+ unused_callback.Reset(); |
+ EXPECT_EQ(1, deletes); |
+ |
+ // Tests the Passed() function's support for rvalues. |
+ deletes = 0; |
+ DeleteCounter* counter = new DeleteCounter(&deletes); |
+ Callback<scoped_ptr<DeleteCounter>(void)> callback = |
+ Bind(&PassThru<scoped_ptr<DeleteCounter> >, |
+ scoped_ptr<DeleteCounter>(counter)); |
+ EXPECT_FALSE(ptr.get()); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Check that ownership can be transferred back out. |
+ scoped_ptr<DeleteCounter> result = callback.Run(); |
+ ASSERT_EQ(counter, result.get()); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Resetting does not delete since ownership was transferred. |
+ callback.Reset(); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Ensure that we actually did get ownership. |
+ result.reset(); |
+ EXPECT_EQ(1, deletes); |
+ |
+ // Test unbound argument forwarding. |
+ Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound = |
+ Bind(&PassThru<scoped_ptr<DeleteCounter> >); |
+ ptr.reset(new DeleteCounter(&deletes)); |
+ cb_unbound.Run(std::move(ptr)); |
+} |
+ |
+// RValue support. |
+// - Bind() can take move-only values by RValue-reference. |
+// - Using an RValue gives Callback Ownership. |
+// - Ownership is transferred from Callback to callee on the first Run(). |
+// - Callback supports unbound arguments. |
+TEST_F(BindTest, ContainerOfMoveOnlyValues) { |
+ int deletes = 0; |
+ |
+ // Tests the Passed() function's support for pointers. |
+ std::vector<scoped_ptr<DeleteCounter>> ptrs; |
+ ptrs.emplace_back(new DeleteCounter(&deletes)); |
+ Callback<std::vector<scoped_ptr<DeleteCounter>>(void)> unused_callback = |
+ Bind(&PassThru<std::vector<scoped_ptr<DeleteCounter>>>, std::move(ptrs)); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // If we never invoke the Callback, it retains ownership and deletes. |
+ unused_callback.Reset(); |
+ EXPECT_EQ(1, deletes); |
+ |
+ // Tests the Passed() function's support for rvalues. |
+ deletes = 0; |
+ ptrs.clear(); |
+ DeleteCounter* counter = new DeleteCounter(&deletes); |
+ ptrs.emplace_back(counter); |
+ Callback<std::vector<scoped_ptr<DeleteCounter>>(void)> callback = |
+ Bind(&PassThru<std::vector<scoped_ptr<DeleteCounter>>>, std::move(ptrs)); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Check that ownership can be transferred back out. |
+ std::vector<scoped_ptr<DeleteCounter>> result = callback.Run(); |
+ ASSERT_EQ(1u, result.size()); |
+ ASSERT_EQ(counter, result[0].get()); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Resetting does not delete since ownership was transferred. |
+ callback.Reset(); |
+ EXPECT_EQ(0, deletes); |
+ |
+ // Ensure that we actually did get ownership. |
+ result.clear(); |
+ EXPECT_EQ(1, deletes); |
+ |
+ // Test unbound argument forwarding. |
+ Callback<std::vector<scoped_ptr<DeleteCounter>>( |
+ std::vector<scoped_ptr<DeleteCounter>>)> |
+ cb_unbound = Bind(&PassThru<std::vector<scoped_ptr<DeleteCounter>>>); |
+ ptrs.clear(); |
+ ptrs.emplace_back(new DeleteCounter(&deletes)); |
+ cb_unbound.Run(std::move(ptrs)); |
+} |
+ |
// Argument Copy-constructor usage for non-reference parameters. |
// - Bound arguments are only copied once. |
// - Forwarded arguments are only copied once. |