/* * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rtc_base/untyped_function.h" #include #include #include "test/gmock.h" #include "test/gtest.h" namespace webrtc { namespace { using ::testing::Pointee; TEST(UntypedFunction, Empty1) { UntypedFunction uf; EXPECT_FALSE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); } TEST(UntypedFunction, Empty2) { UntypedFunction uf = nullptr; EXPECT_FALSE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); } TEST(UntypedFunction, Empty3) { UntypedFunction uf = UntypedFunction::Create(nullptr); EXPECT_FALSE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); } TEST(UntypedFunction, CallTrivialWithInt) { auto uf = UntypedFunction::Create([](int x) { return x + 5; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(17), 22); } TEST(UntypedFunction, CallTrivialWithPointer) { auto uf = UntypedFunction::Create([](int* x) { return *x; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); int x = 12; EXPECT_EQ(uf.Call(&x), 12); } TEST(UntypedFunction, CallTrivialWithReference) { auto uf = UntypedFunction::Create([](int& x) { x = 3; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); int x = 12; uf.Call(x); EXPECT_EQ(x, 3); } TEST(UntypedFunction, CallTrivialWithRvalueReference) { auto uf = UntypedFunction::Create([](int&& x) { return x - 2; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(34), 32); } TEST(UntypedFunction, CallNontrivialWithInt) { std::vector list; auto uf = UntypedFunction::Create([list](int x) mutable { list.push_back(x); return list.size(); }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(17), 1); EXPECT_EQ(uf.Call(17), 2); } TEST(UntypedFunction, CallNontrivialWithPointer) { std::vector list; auto uf = UntypedFunction::Create([list](int* x) mutable { list.push_back(*x); return list.data(); }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); int x = 12; EXPECT_THAT(uf.Call(&x), Pointee(12)); } TEST(UntypedFunction, CallNontrivialWithReference) { std::vector list = {34, 35, 36}; auto uf = UntypedFunction::Create([list](int& x) { x = list[1]; }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); int x = 12; uf.Call(x); EXPECT_EQ(x, 35); } TEST(UntypedFunction, CallNontrivialWithRvalueReference) { std::vector list; auto uf = UntypedFunction::Create([list](int&& x) mutable { list.push_back(x); return list.size(); }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(34), 1); EXPECT_EQ(uf.Call(34), 2); } int AddFive(int x) { return x + 5; } int DereferencePointer(int* x) { return *x; } void AssignThree(int& x) { x = 3; } int SubtractTwo(int&& x) { return x - 2; } TEST(UntypedFunction, CallFunctionPointerWithInt) { auto uf = UntypedFunction::Create(AddFive); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(17), 22); } TEST(UntypedFunction, CallFunctionPointerWithPointer) { auto uf = UntypedFunction::Create(DereferencePointer); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); int x = 12; EXPECT_EQ(uf.Call(&x), 12); } TEST(UntypedFunction, CallFunctionPointerWithReference) { auto uf = UntypedFunction::Create(AssignThree); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); int x = 12; uf.Call(x); EXPECT_EQ(x, 3); } TEST(UntypedFunction, CallFunctionPointerWithRvalueReference) { auto uf = UntypedFunction::Create(SubtractTwo); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(34), 32); } TEST(UntypedFunction, CallTrivialWithNoArgs) { int arr[] = {1, 2, 3}; static_assert(sizeof(arr) <= UntypedFunction::kInlineStorageSize, ""); auto uf = UntypedFunction::Create([arr] { return arr[1]; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 2); } TEST(UntypedFunction, CallLargeTrivialWithNoArgs) { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; static_assert(sizeof(arr) > UntypedFunction::kInlineStorageSize, ""); auto uf = UntypedFunction::Create([arr] { return arr[4]; }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 5); } TEST(UntypedFunction, MoveonlyReturnValue) { auto uf = UntypedFunction::Create()>( [] { return std::make_unique(567); }); EXPECT_THAT(uf.Call()>(), Pointee(567)); } TEST(UntypedFunction, MoveonlyArgument) { auto uf = UntypedFunction::Create)>( [](std::unique_ptr x) { return *x + 19; }); EXPECT_EQ(uf.Call)>(std::make_unique(40)), 59); } TEST(UntypedFunction, MoveOnlyCallable) { auto uf = UntypedFunction::Create( [x = std::make_unique(17)] { return ++*x; }); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 18); EXPECT_EQ(uf.Call(), 19); UntypedFunction uf2 = std::move(uf); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_FALSE(uf2.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 20); EXPECT_EQ(uf.Call(), 21); } class Destroyer { public: explicit Destroyer(int& destroy_count) : destroy_count_(&destroy_count) {} ~Destroyer() { ++*destroy_count_; } int operator()() { return 72; } int* destroy_count_; }; TEST(UntypedFunction, CallableIsDestroyed) { int destroy_count = 0; { auto uf = UntypedFunction::Create(Destroyer(destroy_count)); // Destruction count is 1 here, because the temporary we created above was // destroyed. EXPECT_EQ(destroy_count, 1); { auto uf2 = std::move(uf); EXPECT_EQ(destroy_count, 1); } // `uf2` was destroyed. EXPECT_EQ(destroy_count, 2); } // `uf` was destroyed, but it didn't contain a Destroyer since we moved it to // `uf2` above. EXPECT_EQ(destroy_count, 2); } TEST(UntypedFunction, MoveAssign) { int destroy_count = 0; auto uf = UntypedFunction::Create(Destroyer(destroy_count)); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); // Destruction count is 1 here, because the temporary we created above was // destroyed. EXPECT_EQ(destroy_count, 1); UntypedFunction uf2 = nullptr; EXPECT_FALSE(uf2); EXPECT_TRUE(uf2.IsTriviallyDestructible()); uf2 = std::move(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_TRUE(uf2); EXPECT_FALSE(uf2.IsTriviallyDestructible()); EXPECT_EQ(destroy_count, 1); // The callable was not destroyed. EXPECT_EQ(uf2.Call(), 72); UntypedFunction uf3 = nullptr; uf2 = std::move(uf3); EXPECT_FALSE(uf2); EXPECT_TRUE(uf2.IsTriviallyDestructible()); EXPECT_EQ(destroy_count, 2); // The callable was destroyed by the assignment. } TEST(UntypedFunction, NullptrAssign) { int destroy_count = 0; auto uf = UntypedFunction::Create(Destroyer(destroy_count)); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); // Destruction count is 1 here, because the temporary we created above was // destroyed. EXPECT_EQ(destroy_count, 1); uf = nullptr; EXPECT_FALSE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_EQ(destroy_count, 2); // The callable was destroyed by the assignment. } TEST(UntypedFunction, Swap) { int x = 13; auto uf = UntypedFunction::Create([x]() mutable { return ++x; }); EXPECT_TRUE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); auto y = std::make_unique(113); auto uf2 = UntypedFunction::Create([y = std::move(y)] { return ++*y; }); EXPECT_TRUE(uf2); EXPECT_FALSE(uf2.IsTriviallyDestructible()); UntypedFunction uf3 = nullptr; EXPECT_FALSE(uf3); EXPECT_TRUE(uf3.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 14); swap(uf, uf2); EXPECT_TRUE(uf); EXPECT_FALSE(uf.IsTriviallyDestructible()); EXPECT_TRUE(uf2); EXPECT_TRUE(uf2.IsTriviallyDestructible()); EXPECT_EQ(uf.Call(), 114); EXPECT_EQ(uf2.Call(), 15); swap(uf, uf3); EXPECT_FALSE(uf); EXPECT_TRUE(uf.IsTriviallyDestructible()); EXPECT_TRUE(uf3); EXPECT_FALSE(uf3.IsTriviallyDestructible()); EXPECT_EQ(uf3.Call(), 115); } } // namespace } // namespace webrtc