blob: ae1f922d0c7b71707235affe6258dd8a2c3d003a [file] [log] [blame]
/*
* 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