xref: /aosp_15_r20/external/cronet/base/functional/function_ref_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2022 The Chromium Authors
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/functional/function_ref.h"
6 
7 #include <stdint.h>
8 
9 #include <concepts>
10 #include <optional>
11 
12 #include "base/compiler_specific.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/abseil-cpp/absl/functional/function_ref.h"
15 
16 namespace base {
17 
18 namespace {
19 
Func(float)20 char Func(float) {
21   return 'a';
22 }
23 
24 }  // namespace
25 
TEST(FunctionRef,Lambda)26 TEST(FunctionRef, Lambda) {
27   auto add = [](int a, int b) { return a + b; };
28 
29   {
30     const FunctionRef<int(int, int)> ref = add;
31     EXPECT_EQ(19, ref(17, 2));
32   }
33 
34   {
35     const auto add_const = add;
36     const FunctionRef<int(int, int)> ref = add_const;
37     EXPECT_EQ(19, ref(17, 2));
38   }
39 }
40 
TEST(FunctionRef,CapturingLambda)41 TEST(FunctionRef, CapturingLambda) {
42   int x = 3;
43   const auto lambda = [&x] { return x; };
44   FunctionRef<int()> ref = lambda;
45   EXPECT_EQ(3, ref());
46 }
47 
TEST(FunctionRef,FunctionPtr)48 TEST(FunctionRef, FunctionPtr) {
49   [](FunctionRef<char(float)> ref) { EXPECT_EQ('a', ref(1.0)); }(&Func);
50   const FunctionRef<char(float)> ref = +[](float) { return 'a'; };
51   EXPECT_EQ('a', ref(1.0f));
52 }
53 
TEST(FunctionRef,Functor)54 TEST(FunctionRef, Functor) {
55   struct S {
56     int operator()(int x) const { return x; }
57   };
58   const S s;
59   const FunctionRef<int(int)> ref = s;
60   EXPECT_EQ(17, ref(17));
61 }
62 
TEST(FunctionRef,Method)63 TEST(FunctionRef, Method) {
64   struct S {
65     int Method() const { return value; }
66 
67     const int value;
68   };
69   const S s(25);
70   [&s](FunctionRef<int(const S*)> ref) { EXPECT_EQ(25, ref(&s)); }(&S::Method);
71 }
72 
73 // If we construct from another `FunctionRef`, that should work fine, even if
74 // the input is destroyed before we call the output. In other words, we should
75 // reference the underlying callable, not the `FunctionRef`.
76 //
77 // We construct in a `noinline` function to maximize the chance that ASAN
78 // notices the use-after-free if we get this wrong.
ConstructFromLValue(std::optional<FunctionRef<int ()>> & ref)79 NOINLINE void ConstructFromLValue(std::optional<FunctionRef<int()>>& ref) {
80   const auto return_17 = [] { return 17; };
81   FunctionRef<int()> other = return_17;
82   ref.emplace(other);
83 }
ConstructFromConstLValue(std::optional<FunctionRef<int ()>> & ref)84 NOINLINE void ConstructFromConstLValue(std::optional<FunctionRef<int()>>& ref) {
85   const auto return_17 = [] { return 17; };
86   const FunctionRef<int()> other = return_17;
87   ref.emplace(other);
88 }
ConstructFromRValue(std::optional<FunctionRef<int ()>> & ref)89 NOINLINE void ConstructFromRValue(std::optional<FunctionRef<int()>>& ref) {
90   const auto return_17 = [] { return 17; };
91   using Ref = FunctionRef<int()>;
92   ref.emplace(Ref(return_17));
93 }
ConstructFromConstRValue(std::optional<FunctionRef<int ()>> & ref)94 NOINLINE void ConstructFromConstRValue(std::optional<FunctionRef<int()>>& ref) {
95   const auto return_17 = [] { return 17; };
96   using Ref = const FunctionRef<int()>;
97   ref.emplace(Ref(return_17));
98 }
TEST(FunctionRef,ConstructionFromOtherFunctionRefObjects)99 TEST(FunctionRef, ConstructionFromOtherFunctionRefObjects) {
100   using Ref = FunctionRef<int()>;
101   std::optional<Ref> ref;
102 
103   ConstructFromLValue(ref);
104   EXPECT_EQ(17, (*ref)());
105 
106   ConstructFromConstLValue(ref);
107   EXPECT_EQ(17, (*ref)());
108 
109   ConstructFromRValue(ref);
110   EXPECT_EQ(17, (*ref)());
111 
112   ConstructFromConstRValue(ref);
113   EXPECT_EQ(17, (*ref)());
114 
115   // It shouldn't be possible to construct from `FunctionRef` objects with
116   // differing signatures, even if they are compatible with `int()`.
117   static_assert(!std::constructible_from<Ref, FunctionRef<void()>>);
118   static_assert(!std::constructible_from<Ref, FunctionRef<int(int)>>);
119   static_assert(!std::constructible_from<Ref, FunctionRef<int64_t()>>);
120 
121   // Check again with various qualifiers.
122   static_assert(!std::constructible_from<Ref, const FunctionRef<void()>>);
123   static_assert(!std::constructible_from<Ref, FunctionRef<void()>&>);
124   static_assert(!std::constructible_from<Ref, FunctionRef<void()>&&>);
125   static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&>);
126   static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&&>);
127 }
128 
129 // `FunctionRef` allows functors with convertible return types to be adapted.
TEST(FunctionRef,ConvertibleReturnTypes)130 TEST(FunctionRef, ConvertibleReturnTypes) {
131   {
132     const auto lambda = [] { return true; };
133     const FunctionRef<int()> ref = lambda;
134     EXPECT_EQ(1, ref());
135   }
136 
137   {
138     class Base {};
139     class Derived : public Base {};
140 
141     const auto lambda = []() -> Derived* { return nullptr; };
142     const FunctionRef<const Base*()> ref = lambda;
143     EXPECT_EQ(nullptr, ref());
144   }
145 }
146 
TEST(FunctionRef,ConstructionFromInexactMatches)147 TEST(FunctionRef, ConstructionFromInexactMatches) {
148   // Lambda.
149   const auto lambda = [](int32_t x) { return x; };
150 
151   // Capturing lambda.
152   const auto capturing_lambda = [&](int32_t x) { return lambda(x); };
153 
154   // Function pointer.
155   int32_t (*const function_ptr)(int32_t) = +lambda;
156 
157   // Functor.
158   struct Functor {
159     int32_t operator()(int32_t x) const { return x; }
160   };
161   const Functor functor;
162 
163   // Method.
164   struct Obj {
165     int32_t Method(int32_t x) const { return x; }
166   };
167   int32_t (Obj::*const method)(int32_t) const = &Obj::Method;
168 
169   // Each of the objects above should work for a `FunctionRef` with a
170   // convertible return type. In this case, they all return `int32_t`, which
171   // should be seamlessly convertible to `int64_t` below.
172   static_assert(
173       std::constructible_from<FunctionRef<int64_t(int32_t)>, decltype(lambda)>);
174   static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
175                                         decltype(capturing_lambda)>);
176   static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
177                                         decltype(function_ptr)>);
178   static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>,
179                                         decltype(functor)>);
180   static_assert(
181       std::constructible_from<FunctionRef<int64_t(const Obj*, int32_t)>,
182                               decltype(method)>);
183 
184   // It shouldn't be possible to construct a `FunctionRef` from any of the
185   // objects above if we discard the return value.
186   static_assert(
187       !std::constructible_from<FunctionRef<void(int32_t)>, decltype(lambda)>);
188   static_assert(!std::constructible_from<FunctionRef<void(int32_t)>,
189                                          decltype(capturing_lambda)>);
190   static_assert(!std::constructible_from<FunctionRef<void(int32_t)>,
191                                          decltype(function_ptr)>);
192   static_assert(
193       !std::constructible_from<FunctionRef<void(int32_t)>, decltype(functor)>);
194   static_assert(!std::constructible_from<FunctionRef<void(const Obj*, int32_t)>,
195                                          decltype(method)>);
196 
197   // It shouldn't be possible to construct a `FunctionRef` from a pointer to a
198   // functor, even with a compatible signature.
199   static_assert(!std::constructible_from<FunctionRef<int32_t(int32_t)>,
200                                          decltype(&functor)>);
201 }
202 
TEST(FunctionRef,ConstructionFromAbslFunctionRef)203 TEST(FunctionRef, ConstructionFromAbslFunctionRef) {
204   // It shouldn't be possible to construct a `FunctionRef` from an
205   // `absl::FunctionRef`, whether the signatures are compatible or not.
206   using Ref = FunctionRef<int(int)>;
207   static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void()>>);
208   static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void(int)>>);
209   static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<int(int)>>);
210 
211   // Check again with various qualifiers.
212   using AbslRef = absl::FunctionRef<int(int)>;
213   static_assert(!std::is_constructible_v<Ref, const AbslRef>);
214   static_assert(!std::is_constructible_v<Ref, AbslRef&>);
215   static_assert(!std::is_constructible_v<Ref, AbslRef&&>);
216   static_assert(!std::is_constructible_v<Ref, const AbslRef&>);
217   static_assert(!std::is_constructible_v<Ref, const AbslRef&&>);
218 }
219 
220 }  // namespace base
221