blob: 9074443b3cbbe785732f811ce7d0267a00598625 [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/base/internal/invoke.h"
16
17#include <functional>
18#include <memory>
19#include <string>
20#include <utility>
21
22#include "gmock/gmock.h"
23#include "gtest/gtest.h"
24#include "absl/memory/memory.h"
25#include "absl/strings/str_cat.h"
26
27namespace absl {
28namespace base_internal {
29namespace {
30
31int Function(int a, int b) { return a - b; }
32
33int Sink(std::unique_ptr<int> p) {
34 return *p;
35}
36
37std::unique_ptr<int> Factory(int n) {
38 return make_unique<int>(n);
39}
40
41void NoOp() {}
42
43struct ConstFunctor {
44 int operator()(int a, int b) const { return a - b; }
45};
46
47struct MutableFunctor {
48 int operator()(int a, int b) { return a - b; }
49};
50
51struct EphemeralFunctor {
52 int operator()(int a, int b) && { return a - b; }
53};
54
55struct OverloadedFunctor {
56 template <typename... Args>
57 std::string operator()(const Args&... args) & {
58 return StrCat("&", args...);
59 }
60 template <typename... Args>
61 std::string operator()(const Args&... args) const& {
62 return StrCat("const&", args...);
63 }
64 template <typename... Args>
65 std::string operator()(const Args&... args) && {
66 return StrCat("&&", args...);
67 }
68};
69
70struct Class {
71 int Method(int a, int b) { return a - b; }
72 int ConstMethod(int a, int b) const { return a - b; }
73 int RefMethod(int a, int b) & { return a - b; }
74 int RefRefMethod(int a, int b) && { return a - b; }
75 int NoExceptMethod(int a, int b) noexcept { return a - b; }
76 int VolatileMethod(int a, int b) volatile { return a - b; }
77
78 int member;
79};
80
81struct FlipFlop {
82 int ConstMethod() const { return member; }
83 FlipFlop operator*() const { return {-member}; }
84
85 int member;
86};
87
88// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending
89// on which one is valid.
90template <typename F>
91decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) {
92 return Invoke(f);
93}
94
95template <typename F>
96decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) {
97 return Invoke(f, 42);
98}
99
100TEST(InvokeTest, Function) {
101 EXPECT_EQ(1, Invoke(Function, 3, 2));
102 EXPECT_EQ(1, Invoke(&Function, 3, 2));
103}
104
105TEST(InvokeTest, NonCopyableArgument) {
106 EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42)));
107}
108
109TEST(InvokeTest, NonCopyableResult) {
110 EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42));
111}
112
113TEST(InvokeTest, VoidResult) {
114 Invoke(NoOp);
115}
116
117TEST(InvokeTest, ConstFunctor) {
118 EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2));
119}
120
121TEST(InvokeTest, MutableFunctor) {
122 MutableFunctor f;
123 EXPECT_EQ(1, Invoke(f, 3, 2));
124 EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2));
125}
126
127TEST(InvokeTest, EphemeralFunctor) {
128 EphemeralFunctor f;
129 EXPECT_EQ(1, Invoke(std::move(f), 3, 2));
130 EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2));
131}
132
133TEST(InvokeTest, OverloadedFunctor) {
134 OverloadedFunctor f;
135 const OverloadedFunctor& cf = f;
136
137 EXPECT_EQ("&", Invoke(f));
138 EXPECT_EQ("& 42", Invoke(f, " 42"));
139
140 EXPECT_EQ("const&", Invoke(cf));
141 EXPECT_EQ("const& 42", Invoke(cf, " 42"));
142
143 EXPECT_EQ("&&", Invoke(std::move(f)));
144 EXPECT_EQ("&& 42", Invoke(std::move(f), " 42"));
145}
146
147TEST(InvokeTest, ReferenceWrapper) {
148 ConstFunctor cf;
149 MutableFunctor mf;
150 EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2));
151 EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2));
152 EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2));
153}
154
155TEST(InvokeTest, MemberFunction) {
156 std::unique_ptr<Class> p(new Class);
157 std::unique_ptr<const Class> cp(new Class);
158 std::unique_ptr<volatile Class> vp(new Class);
159
160 EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2));
161 EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
162 EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
163 EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
164 EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
165 EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
166 EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT
167 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
168 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
169 EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
170
171 EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
172 EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
173 EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2));
174
175 EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
176 EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
177 EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
178
179 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
180 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
181 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
182 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
183 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
184 EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
185
186 EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
187 EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
188 EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
189}
190
191TEST(InvokeTest, DataMember) {
192 std::unique_ptr<Class> p(new Class{42});
193 std::unique_ptr<const Class> cp(new Class{42});
194 EXPECT_EQ(42, Invoke(&Class::member, p));
195 EXPECT_EQ(42, Invoke(&Class::member, *p));
196 EXPECT_EQ(42, Invoke(&Class::member, p.get()));
197
198 Invoke(&Class::member, p) = 42;
199 Invoke(&Class::member, p.get()) = 42;
200
201 EXPECT_EQ(42, Invoke(&Class::member, cp));
202 EXPECT_EQ(42, Invoke(&Class::member, *cp));
203 EXPECT_EQ(42, Invoke(&Class::member, cp.get()));
204}
205
206TEST(InvokeTest, FlipFlop) {
207 FlipFlop obj = {42};
208 // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
209 // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
210 EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj));
211 EXPECT_EQ(42, Invoke(&FlipFlop::member, obj));
212}
213
214TEST(InvokeTest, SfinaeFriendly) {
215 CallMaybeWithArg(NoOp);
216 EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
217}
218
219} // namespace
220} // namespace base_internal
221} // namespace absl