| /* |
| * Copyright (C) 2011 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "platform/wtf/Functional.h" |
| |
| #include "platform/wtf/RefCounted.h" |
| #include "platform/wtf/WeakPtr.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include <utility> |
| |
| namespace WTF { |
| |
| class UnwrappedClass { |
| public: |
| explicit UnwrappedClass(int value) : value_(value) {} |
| |
| int Value() const { return value_; } |
| |
| private: |
| int value_; |
| }; |
| |
| // This class must be wrapped in bind() and unwrapped in closure execution. |
| class ClassToBeWrapped { |
| WTF_MAKE_NONCOPYABLE(ClassToBeWrapped); |
| |
| public: |
| explicit ClassToBeWrapped(int value) : value_(value) {} |
| |
| int Value() const { return value_; } |
| |
| private: |
| int value_; |
| }; |
| |
| class WrappedClass { |
| public: |
| WrappedClass(const ClassToBeWrapped& to_be_wrapped) |
| : value_(to_be_wrapped.Value()) {} |
| |
| explicit WrappedClass(int value) : value_(value) {} |
| |
| UnwrappedClass Unwrap() const { return UnwrappedClass(value_); } |
| |
| private: |
| int value_; |
| }; |
| |
| template <> |
| struct ParamStorageTraits<ClassToBeWrapped> { |
| using StorageType = WrappedClass; |
| }; |
| |
| class HasWeakPtrSupport { |
| public: |
| HasWeakPtrSupport() : weak_ptr_factory_(this) {} |
| |
| WTF::WeakPtr<HasWeakPtrSupport> CreateWeakPtr() { |
| return weak_ptr_factory_.CreateWeakPtr(); |
| } |
| |
| void RevokeAll() { weak_ptr_factory_.RevokeAll(); } |
| |
| void Increment(int* counter) { ++*counter; } |
| |
| private: |
| WTF::WeakPtrFactory<HasWeakPtrSupport> weak_ptr_factory_; |
| }; |
| |
| } // namespace WTF |
| |
| namespace base { |
| |
| template <> |
| struct BindUnwrapTraits<WTF::WrappedClass> { |
| static WTF::UnwrappedClass Unwrap(const WTF::WrappedClass& wrapped) { |
| return wrapped.Unwrap(); |
| } |
| }; |
| |
| } // namespace base |
| |
| namespace WTF { |
| namespace { |
| |
| int ReturnFortyTwo() { |
| return 42; |
| } |
| |
| TEST(FunctionalTest, Basic) { |
| std::unique_ptr<Function<int()>> return_forty_two_function = |
| Bind(ReturnFortyTwo); |
| EXPECT_EQ(42, (*return_forty_two_function)()); |
| } |
| |
| int MultiplyByTwo(int n) { |
| return n * 2; |
| } |
| |
| double MultiplyByOneAndAHalf(double d) { |
| return d * 1.5; |
| } |
| |
| TEST(FunctionalTest, UnaryBind) { |
| std::unique_ptr<Function<int()>> multiply_four_by_two_function = |
| Bind(MultiplyByTwo, 4); |
| EXPECT_EQ(8, (*multiply_four_by_two_function)()); |
| |
| std::unique_ptr<Function<double()>> multiply_by_one_and_a_half_function = |
| Bind(MultiplyByOneAndAHalf, 3); |
| EXPECT_EQ(4.5, (*multiply_by_one_and_a_half_function)()); |
| } |
| |
| TEST(FunctionalTest, UnaryPartBind) { |
| std::unique_ptr<Function<int(int)>> multiply_by_two_function = |
| Bind(MultiplyByTwo); |
| EXPECT_EQ(8, (*multiply_by_two_function)(4)); |
| |
| std::unique_ptr<Function<double(double)>> |
| multiply_by_one_and_a_half_function = Bind(MultiplyByOneAndAHalf); |
| EXPECT_EQ(4.5, (*multiply_by_one_and_a_half_function)(3)); |
| } |
| |
| int Multiply(int x, int y) { |
| return x * y; |
| } |
| |
| int Subtract(int x, int y) { |
| return x - y; |
| } |
| |
| TEST(FunctionalTest, BinaryBind) { |
| std::unique_ptr<Function<int()>> multiply_four_by_two_function = |
| Bind(Multiply, 4, 2); |
| EXPECT_EQ(8, (*multiply_four_by_two_function)()); |
| |
| std::unique_ptr<Function<int()>> subtract_two_from_four_function = |
| Bind(Subtract, 4, 2); |
| EXPECT_EQ(2, (*subtract_two_from_four_function)()); |
| } |
| |
| TEST(FunctionalTest, BinaryPartBind) { |
| std::unique_ptr<Function<int(int)>> multiply_four_function = |
| Bind(Multiply, 4); |
| EXPECT_EQ(8, (*multiply_four_function)(2)); |
| std::unique_ptr<Function<int(int, int)>> multiply_function = Bind(Multiply); |
| EXPECT_EQ(8, (*multiply_function)(4, 2)); |
| |
| std::unique_ptr<Function<int(int)>> subtract_from_four_function = |
| Bind(Subtract, 4); |
| EXPECT_EQ(2, (*subtract_from_four_function)(2)); |
| std::unique_ptr<Function<int(int, int)>> subtract_function = Bind(Subtract); |
| EXPECT_EQ(2, (*subtract_function)(4, 2)); |
| } |
| |
| void SixArgFunc(int a, double b, char c, int* d, double* e, char* f) { |
| *d = a; |
| *e = b; |
| *f = c; |
| } |
| |
| void AssertArgs(int actual_int, |
| double actual_double, |
| char actual_char, |
| int expected_int, |
| double expected_double, |
| char expected_char) { |
| EXPECT_EQ(expected_int, actual_int); |
| EXPECT_EQ(expected_double, actual_double); |
| EXPECT_EQ(expected_char, actual_char); |
| } |
| |
| TEST(FunctionalTest, MultiPartBind) { |
| int a = 0; |
| double b = 0.5; |
| char c = 'a'; |
| |
| std::unique_ptr<Function<void(int, double, char, int*, double*, char*)>> |
| unbound = Bind(SixArgFunc); |
| (*unbound)(1, 1.5, 'b', &a, &b, &c); |
| AssertArgs(a, b, c, 1, 1.5, 'b'); |
| |
| std::unique_ptr<Function<void(double, char, int*, double*, char*)>> |
| one_bound = Bind(SixArgFunc, 2); |
| (*one_bound)(2.5, 'c', &a, &b, &c); |
| AssertArgs(a, b, c, 2, 2.5, 'c'); |
| |
| std::unique_ptr<Function<void(char, int*, double*, char*)>> two_bound = |
| Bind(SixArgFunc, 3, 3.5); |
| (*two_bound)('d', &a, &b, &c); |
| AssertArgs(a, b, c, 3, 3.5, 'd'); |
| |
| std::unique_ptr<Function<void(int*, double*, char*)>> three_bound = |
| Bind(SixArgFunc, 4, 4.5, 'e'); |
| (*three_bound)(&a, &b, &c); |
| AssertArgs(a, b, c, 4, 4.5, 'e'); |
| |
| std::unique_ptr<Function<void(double*, char*)>> four_bound = |
| Bind(SixArgFunc, 5, 5.5, 'f', WTF::Unretained(&a)); |
| (*four_bound)(&b, &c); |
| AssertArgs(a, b, c, 5, 5.5, 'f'); |
| |
| std::unique_ptr<Function<void(char*)>> five_bound = |
| Bind(SixArgFunc, 6, 6.5, 'g', WTF::Unretained(&a), WTF::Unretained(&b)); |
| (*five_bound)(&c); |
| AssertArgs(a, b, c, 6, 6.5, 'g'); |
| |
| std::unique_ptr<Function<void()>> six_bound = |
| Bind(SixArgFunc, 7, 7.5, 'h', WTF::Unretained(&a), WTF::Unretained(&b), |
| WTF::Unretained(&c)); |
| (*six_bound)(); |
| AssertArgs(a, b, c, 7, 7.5, 'h'); |
| } |
| |
| class A { |
| public: |
| explicit A(int i) : i_(i) {} |
| |
| int F() { return i_; } |
| int AddF(int j) { return i_ + j; } |
| virtual int Overridden() { return 42; } |
| |
| private: |
| int i_; |
| }; |
| |
| class B : public A { |
| public: |
| explicit B(int i) : A(i) {} |
| |
| int F() { return A::F() + 1; } |
| int AddF(int j) { return A::AddF(j) + 1; } |
| int Overridden() override { return 43; } |
| }; |
| |
| TEST(FunctionalTest, MemberFunctionBind) { |
| A a(10); |
| std::unique_ptr<Function<int()>> function1 = Bind(&A::F, WTF::Unretained(&a)); |
| EXPECT_EQ(10, (*function1)()); |
| |
| std::unique_ptr<Function<int()>> function2 = |
| Bind(&A::AddF, WTF::Unretained(&a), 15); |
| EXPECT_EQ(25, (*function2)()); |
| |
| std::unique_ptr<Function<int()>> function3 = |
| Bind(&A::Overridden, WTF::Unretained(&a)); |
| EXPECT_EQ(42, (*function3)()); |
| } |
| |
| TEST(FunctionalTest, MemberFunctionBindWithSubclassPointer) { |
| B b(10); |
| std::unique_ptr<Function<int()>> function1 = Bind(&A::F, WTF::Unretained(&b)); |
| EXPECT_EQ(10, (*function1)()); |
| |
| std::unique_ptr<Function<int()>> function2 = |
| Bind(&A::AddF, WTF::Unretained(&b), 15); |
| EXPECT_EQ(25, (*function2)()); |
| |
| std::unique_ptr<Function<int()>> function3 = |
| Bind(&A::Overridden, WTF::Unretained(&b)); |
| EXPECT_EQ(43, (*function3)()); |
| |
| std::unique_ptr<Function<int()>> function4 = Bind(&B::F, WTF::Unretained(&b)); |
| EXPECT_EQ(11, (*function4)()); |
| |
| std::unique_ptr<Function<int()>> function5 = |
| Bind(&B::AddF, WTF::Unretained(&b), 15); |
| EXPECT_EQ(26, (*function5)()); |
| } |
| |
| TEST(FunctionalTest, MemberFunctionBindWithSubclassPointerWithCast) { |
| B b(10); |
| std::unique_ptr<Function<int()>> function1 = |
| Bind(&A::F, WTF::Unretained(static_cast<A*>(&b))); |
| EXPECT_EQ(10, (*function1)()); |
| |
| std::unique_ptr<Function<int()>> function2 = |
| Bind(&A::AddF, WTF::Unretained(static_cast<A*>(&b)), 15); |
| EXPECT_EQ(25, (*function2)()); |
| |
| std::unique_ptr<Function<int()>> function3 = |
| Bind(&A::Overridden, WTF::Unretained(static_cast<A*>(&b))); |
| EXPECT_EQ(43, (*function3)()); |
| } |
| |
| TEST(FunctionalTest, MemberFunctionPartBind) { |
| A a(10); |
| std::unique_ptr<Function<int(class A*)>> function1 = Bind(&A::F); |
| EXPECT_EQ(10, (*function1)(&a)); |
| |
| std::unique_ptr<Function<int(class A*, int)>> unbound_function2 = |
| Bind(&A::AddF); |
| EXPECT_EQ(25, (*unbound_function2)(&a, 15)); |
| std::unique_ptr<Function<int(int)>> object_bound_function2 = |
| Bind(&A::AddF, WTF::Unretained(&a)); |
| EXPECT_EQ(25, (*object_bound_function2)(15)); |
| } |
| |
| TEST(FunctionalTest, MemberFunctionBindByUniquePtr) { |
| std::unique_ptr<Function<int()>> function1 = |
| WTF::Bind(&A::F, WTF::MakeUnique<A>(10)); |
| EXPECT_EQ(10, (*function1)()); |
| } |
| |
| TEST(FunctionalTest, MemberFunctionBindByPassedUniquePtr) { |
| std::unique_ptr<Function<int()>> function1 = |
| WTF::Bind(&A::F, WTF::Passed(WTF::MakeUnique<A>(10))); |
| EXPECT_EQ(10, (*function1)()); |
| } |
| |
| class Number : public RefCounted<Number> { |
| public: |
| static PassRefPtr<Number> Create(int value) { |
| return AdoptRef(new Number(value)); |
| } |
| |
| ~Number() { value_ = 0; } |
| |
| int Value() const { return value_; } |
| |
| private: |
| explicit Number(int value) : value_(value) {} |
| |
| int value_; |
| }; |
| |
| int MultiplyNumberByTwo(Number* number) { |
| return number->Value() * 2; |
| } |
| |
| TEST(FunctionalTest, RefCountedStorage) { |
| RefPtr<Number> five = Number::Create(5); |
| EXPECT_EQ(1, five->RefCount()); |
| std::unique_ptr<Function<int()>> multiply_five_by_two_function = |
| Bind(MultiplyNumberByTwo, five); |
| EXPECT_EQ(2, five->RefCount()); |
| EXPECT_EQ(10, (*multiply_five_by_two_function)()); |
| EXPECT_EQ(2, five->RefCount()); |
| |
| std::unique_ptr<Function<int()>> multiply_four_by_two_function = |
| Bind(MultiplyNumberByTwo, Number::Create(4)); |
| EXPECT_EQ(8, (*multiply_four_by_two_function)()); |
| |
| RefPtr<Number> six = Number::Create(6); |
| std::unique_ptr<Function<int()>> multiply_six_by_two_function = |
| Bind(MultiplyNumberByTwo, six.Release()); |
| EXPECT_FALSE(six); |
| EXPECT_EQ(12, (*multiply_six_by_two_function)()); |
| } |
| |
| TEST(FunctionalTest, UnretainedWithRefCounted) { |
| RefPtr<Number> five = Number::Create(5); |
| EXPECT_EQ(1, five->RefCount()); |
| std::unique_ptr<Function<int()>> multiply_five_by_two_function = |
| Bind(MultiplyNumberByTwo, WTF::Unretained(five.Get())); |
| EXPECT_EQ(1, five->RefCount()); |
| EXPECT_EQ(10, (*multiply_five_by_two_function)()); |
| EXPECT_EQ(1, five->RefCount()); |
| } |
| |
| int ProcessUnwrappedClass(const UnwrappedClass& u, int v) { |
| return u.Value() * v; |
| } |
| |
| // Tests that: |
| // - ParamStorageTraits's wrap()/unwrap() are called, and |
| // - bind()'s arguments are passed as references to ParamStorageTraits::wrap() |
| // with no additional copies. |
| // This test would fail in compile if something is wrong, |
| // rather than in runtime. |
| TEST(FunctionalTest, WrapUnwrap) { |
| std::unique_ptr<Function<int()>> function = |
| Bind(ProcessUnwrappedClass, ClassToBeWrapped(3), 7); |
| EXPECT_EQ(21, (*function)()); |
| } |
| |
| TEST(FunctionalTest, WrapUnwrapInPartialBind) { |
| std::unique_ptr<Function<int(int)>> partially_bound_function = |
| Bind(ProcessUnwrappedClass, ClassToBeWrapped(3)); |
| EXPECT_EQ(21, (*partially_bound_function)(7)); |
| } |
| |
| bool LotsOfArguments(int first, |
| int second, |
| int third, |
| int fourth, |
| int fifth, |
| int sixth, |
| int seventh, |
| int eighth, |
| int ninth, |
| int tenth) { |
| return first == 1 && second == 2 && third == 3 && fourth == 4 && fifth == 5 && |
| sixth == 6 && seventh == 7 && eighth == 8 && ninth == 9 && tenth == 10; |
| } |
| |
| TEST(FunctionalTest, LotsOfBoundVariables) { |
| std::unique_ptr<Function<bool(int, int)>> eight_bound = |
| Bind(LotsOfArguments, 1, 2, 3, 4, 5, 6, 7, 8); |
| EXPECT_TRUE((*eight_bound)(9, 10)); |
| |
| std::unique_ptr<Function<bool(int)>> nine_bound = |
| Bind(LotsOfArguments, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
| EXPECT_TRUE((*nine_bound)(10)); |
| |
| std::unique_ptr<Function<bool()>> all_bound = |
| Bind(LotsOfArguments, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); |
| EXPECT_TRUE((*all_bound)()); |
| } |
| |
| class MoveOnly { |
| public: |
| explicit MoveOnly(int value) : value_(value) {} |
| MoveOnly(MoveOnly&& other) : value_(other.value_) { |
| // Reset the value on move. |
| other.value_ = 0; |
| } |
| |
| int Value() const { return value_; } |
| |
| private: |
| MoveOnly(const MoveOnly&) = delete; |
| MoveOnly& operator=(const MoveOnly&) = delete; |
| |
| // Disable move-assignment, since it isn't used within bind(). |
| MoveOnly& operator=(MoveOnly&&) = delete; |
| |
| int value_; |
| }; |
| |
| int SingleMoveOnlyByRvalueReference(MoveOnly&& move_only) { |
| int value = move_only.Value(); |
| MoveOnly(std::move(move_only)); |
| return value; |
| } |
| |
| int TripleMoveOnlysByRvalueReferences(MoveOnly&& first, |
| MoveOnly&& second, |
| MoveOnly&& third) { |
| int value = first.Value() + second.Value() + third.Value(); |
| MoveOnly(std::move(first)); |
| MoveOnly(std::move(second)); |
| MoveOnly(std::move(third)); |
| return value; |
| } |
| |
| int SingleMoveOnlyByValue(MoveOnly move_only) { |
| return move_only.Value(); |
| } |
| |
| int TripleMoveOnlysByValues(MoveOnly first, MoveOnly second, MoveOnly third) { |
| return first.Value() + second.Value() + third.Value(); |
| } |
| |
| TEST(FunctionalTest, BindMoveOnlyObjects) { |
| MoveOnly one(1); |
| std::unique_ptr<Function<int()>> bound = |
| Bind(SingleMoveOnlyByRvalueReference, WTF::Passed(std::move(one))); |
| EXPECT_EQ(0, one.Value()); // Should be moved away. |
| EXPECT_EQ(1, (*bound)()); |
| // The stored value must be cleared in the first function call. |
| EXPECT_EQ(0, (*bound)()); |
| |
| bound = Bind(SingleMoveOnlyByValue, WTF::Passed(MoveOnly(1))); |
| EXPECT_EQ(1, (*bound)()); |
| EXPECT_EQ(0, (*bound)()); |
| |
| bound = Bind(TripleMoveOnlysByRvalueReferences, WTF::Passed(MoveOnly(1)), |
| WTF::Passed(MoveOnly(2)), WTF::Passed(MoveOnly(3))); |
| EXPECT_EQ(6, (*bound)()); |
| EXPECT_EQ(0, (*bound)()); |
| |
| bound = Bind(TripleMoveOnlysByValues, WTF::Passed(MoveOnly(1)), |
| WTF::Passed(MoveOnly(2)), WTF::Passed(MoveOnly(3))); |
| EXPECT_EQ(6, (*bound)()); |
| EXPECT_EQ(0, (*bound)()); |
| } |
| |
| class CountCopy { |
| public: |
| CountCopy() : copies_(0) {} |
| CountCopy(const CountCopy& other) : copies_(other.copies_ + 1) {} |
| |
| int Copies() const { return copies_; } |
| |
| private: |
| // Copy/move-assignment is not needed in the test. |
| CountCopy& operator=(const CountCopy&) = delete; |
| CountCopy& operator=(CountCopy&&) = delete; |
| |
| int copies_; |
| }; |
| |
| int TakeCountCopyAsConstReference(const CountCopy& counter) { |
| return counter.Copies(); |
| } |
| |
| int TakeCountCopyAsValue(CountCopy counter) { |
| return counter.Copies(); |
| } |
| |
| TEST(FunctionalTest, CountCopiesOfBoundArguments) { |
| CountCopy lvalue; |
| std::unique_ptr<Function<int()>> bound = |
| Bind(TakeCountCopyAsConstReference, lvalue); |
| EXPECT_EQ(2, (*bound)()); // wrapping and unwrapping. |
| |
| bound = Bind(TakeCountCopyAsConstReference, CountCopy()); // Rvalue. |
| EXPECT_EQ(2, (*bound)()); |
| |
| bound = Bind(TakeCountCopyAsValue, lvalue); |
| // wrapping, unwrapping and copying in the final function argument. |
| EXPECT_EQ(3, (*bound)()); |
| |
| bound = Bind(TakeCountCopyAsValue, CountCopy()); |
| EXPECT_EQ(3, (*bound)()); |
| } |
| |
| TEST(FunctionalTest, MoveUnboundArgumentsByRvalueReference) { |
| std::unique_ptr<Function<int(MoveOnly &&)>> bound_single = |
| Bind(SingleMoveOnlyByRvalueReference); |
| EXPECT_EQ(1, (*bound_single)(MoveOnly(1))); |
| EXPECT_EQ(42, (*bound_single)(MoveOnly(42))); |
| |
| std::unique_ptr<Function<int(MoveOnly&&, MoveOnly&&, MoveOnly &&)>> |
| bound_triple = Bind(TripleMoveOnlysByRvalueReferences); |
| EXPECT_EQ(6, (*bound_triple)(MoveOnly(1), MoveOnly(2), MoveOnly(3))); |
| EXPECT_EQ(666, (*bound_triple)(MoveOnly(111), MoveOnly(222), MoveOnly(333))); |
| |
| std::unique_ptr<Function<int(MoveOnly)>> bound_single_by_value = |
| Bind(SingleMoveOnlyByValue); |
| EXPECT_EQ(1, (*bound_single_by_value)(MoveOnly(1))); |
| |
| std::unique_ptr<Function<int(MoveOnly, MoveOnly, MoveOnly)>> |
| bound_triple_by_value = Bind(TripleMoveOnlysByValues); |
| EXPECT_EQ(6, (*bound_triple_by_value)(MoveOnly(1), MoveOnly(2), MoveOnly(3))); |
| } |
| |
| TEST(FunctionalTest, CountCopiesOfUnboundArguments) { |
| CountCopy lvalue; |
| std::unique_ptr<Function<int(const CountCopy&)>> bound1 = |
| Bind(TakeCountCopyAsConstReference); |
| EXPECT_EQ(0, (*bound1)(lvalue)); // No copies! |
| EXPECT_EQ(0, (*bound1)(CountCopy())); |
| |
| std::unique_ptr<Function<int(CountCopy)>> bound2 = Bind(TakeCountCopyAsValue); |
| // At Function::operator(), at Callback::Run() and at the destination |
| // function. |
| EXPECT_EQ(3, (*bound2)(lvalue)); |
| // Compiler is allowed to optimize one copy away if the argument is rvalue. |
| EXPECT_LE((*bound2)(CountCopy()), 2); |
| } |
| |
| TEST(FunctionalTest, WeakPtr) { |
| HasWeakPtrSupport obj; |
| int counter = 0; |
| std::unique_ptr<WTF::Closure> bound = |
| WTF::Bind(&HasWeakPtrSupport::Increment, obj.CreateWeakPtr(), |
| WTF::Unretained(&counter)); |
| |
| (*bound)(); |
| EXPECT_FALSE(bound->IsCancelled()); |
| EXPECT_EQ(1, counter); |
| |
| obj.RevokeAll(); |
| EXPECT_TRUE(bound->IsCancelled()); |
| (*bound)(); |
| EXPECT_EQ(1, counter); |
| } |
| |
| } // anonymous namespace |
| |
| } // namespace WTF |