OLD | NEW |
| (Empty) |
1 // Copyright 2010 The Ginsu Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #include "c_salt/callback.h" | |
6 | |
7 #include <cassert> | |
8 #include <iostream> | |
9 #include <limits> | |
10 #include <string> | |
11 #include <vector> | |
12 | |
13 #include "c_salt/npapi/variant_converter.h" | |
14 #include "c_salt/variant_ptrs.h" | |
15 #include "c_salt/variant.h" | |
16 #include "gmock/gmock.h" | |
17 #include "gtest/gtest.h" | |
18 | |
19 namespace { | |
20 | |
21 using c_salt::Variant; | |
22 using c_salt::SharedVariant; | |
23 typedef std::vector<SharedVariant> VariantVector; | |
24 | |
25 // An overload of the stream insertion operator to print c_salt variants | |
26 std::ostream& operator<<(std::ostream& s, const Variant& c_salt_var) { | |
27 s << c_salt_var.StringValue(); | |
28 return s; | |
29 } | |
30 | |
31 // An overload for streaming a vector of streamable types. | |
32 template <class T> | |
33 std::ostream& operator<<(std::ostream& s, const std::vector<T>& vector) { | |
34 typename std::vector<T>::const_iterator iter(vector.begin()), | |
35 last(vector.end()-1); | |
36 for (; iter != last; ++iter) { | |
37 s << *iter << ", "; | |
38 } | |
39 s << *iter << "\n"; | |
40 } | |
41 | |
42 // FakeCallback is a class that provides a member function with a signature | |
43 // defined by a given template parameter. It allows us to set a value for it | |
44 // to return when called, and it stores a vector of variants of the arguments | |
45 // it was passed so that we can inspect it and ensure that the correct | |
46 // parameters were passed. | |
47 // The actual implementation is below, spread between FakeCallback | |
48 // specializations, FakeCallbackReturnHandler, and FakeCallbackBase: | |
49 // /------------------\ | |
50 // | FakeCallbackBase | < Defines common things for FakeCallbacks | |
51 // \------------------/ | |
52 // ^ | |
53 // | inherits from | |
54 // /-------------------------------\ | |
55 // | FakeCallbackReturnHandlerBase | < Handles void returns | |
56 // \-------------------------------/ | |
57 // ^ | |
58 // | inherits from | |
59 // /--------------\ | |
60 // | FakeCallback | < Defines Func, sets passed_params_vector_ based | |
61 // \--------------/ on the arguments it is passed. | |
62 // | |
63 template <class Signature> | |
64 struct FakeCallback; | |
65 | |
66 // All things common to FakeCallback specializations | |
67 class FakeCallbackBase { | |
68 protected: | |
69 VariantVector passed_params_vector_; | |
70 SharedVariant value_to_return_; | |
71 FakeCallbackBase() {} | |
72 ~FakeCallbackBase() {} | |
73 public: | |
74 void Clear() { | |
75 passed_params_vector_.clear(); | |
76 } | |
77 void set_value_to_return(SharedVariant var) { | |
78 value_to_return_ = var; | |
79 } | |
80 const VariantVector& passed_params_vector() { | |
81 return passed_params_vector_; | |
82 } | |
83 }; | |
84 | |
85 // FakeCallbackReturnHandler is specialized on return type. For void return | |
86 // type, we don't return anything. This one is the default implementation for | |
87 // non-void return types. We just return return_val. | |
88 template <class ReturnType> | |
89 class FakeCallbackReturnHandler : public FakeCallbackBase { | |
90 public: | |
91 ReturnType value_to_return() { | |
92 return value_to_return_->GetValue<ReturnType>(); | |
93 } | |
94 }; | |
95 // The specialization for void return types. Don't return anything. | |
96 template <> | |
97 class FakeCallbackReturnHandler<void> : public FakeCallbackBase { | |
98 public: | |
99 void value_to_return() {} | |
100 }; | |
101 | |
102 template <class Signature> | |
103 struct FakeCallback; | |
104 | |
105 template <class Ret> | |
106 struct FakeCallback<Ret()> : public FakeCallbackReturnHandler<Ret> { | |
107 Ret Func() { | |
108 this->passed_params_vector_.clear(); | |
109 return this->value_to_return(); | |
110 } | |
111 }; | |
112 template <class Ret, class Arg1> | |
113 struct FakeCallback<Ret(Arg1)> : public FakeCallbackReturnHandler<Ret> { | |
114 Ret Func(Arg1 a1) { | |
115 this->passed_params_vector_.clear(); | |
116 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
117 return this->value_to_return(); | |
118 } | |
119 }; | |
120 template <class Ret, class Arg1, class Arg2> | |
121 struct FakeCallback<Ret(Arg1, Arg2)> | |
122 : public FakeCallbackReturnHandler<Ret> { | |
123 Ret Func(Arg1 a1, Arg2 a2) { | |
124 this->passed_params_vector_.clear(); | |
125 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
126 this->passed_params_vector_.push_back(SharedVariant(new Variant(a2))); | |
127 return this->value_to_return(); | |
128 } | |
129 }; | |
130 template <class Ret, class Arg1, class Arg2, class Arg3> | |
131 struct FakeCallback<Ret(Arg1, Arg2, Arg3)> | |
132 : public FakeCallbackReturnHandler<Ret> { | |
133 Ret Func(Arg1 a1, Arg2 a2, Arg3 a3) { | |
134 this->passed_params_vector_.clear(); | |
135 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
136 this->passed_params_vector_.push_back(SharedVariant(new Variant(a2))); | |
137 this->passed_params_vector_.push_back(SharedVariant(new Variant(a3))); | |
138 return this->value_to_return(); | |
139 } | |
140 }; | |
141 template <class Ret, class Arg1, class Arg2, class Arg3, class Arg4> | |
142 struct FakeCallback<Ret(Arg1, Arg2, Arg3, Arg4)> | |
143 : public FakeCallbackReturnHandler<Ret> { | |
144 Ret Func(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) { | |
145 this->passed_params_vector_.clear(); | |
146 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
147 this->passed_params_vector_.push_back(SharedVariant(new Variant(a2))); | |
148 this->passed_params_vector_.push_back(SharedVariant(new Variant(a3))); | |
149 this->passed_params_vector_.push_back(SharedVariant(new Variant(a4))); | |
150 return this->value_to_return(); | |
151 } | |
152 }; | |
153 template <class Ret, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5> | |
154 struct FakeCallback<Ret(Arg1, Arg2, Arg3, Arg4, Arg5)> | |
155 : public FakeCallbackReturnHandler<Ret> { | |
156 Ret Func(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) { | |
157 this->passed_params_vector_.clear(); | |
158 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
159 this->passed_params_vector_.push_back(SharedVariant(new Variant(a2))); | |
160 this->passed_params_vector_.push_back(SharedVariant(new Variant(a3))); | |
161 this->passed_params_vector_.push_back(SharedVariant(new Variant(a4))); | |
162 this->passed_params_vector_.push_back(SharedVariant(new Variant(a5))); | |
163 return this->value_to_return(); | |
164 } | |
165 }; | |
166 template <class Ret, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, | |
167 class Arg6> | |
168 struct FakeCallback<Ret(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> | |
169 : public FakeCallbackReturnHandler<Ret> { | |
170 Ret Func(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5, Arg6 a6) { | |
171 this->passed_params_vector_.clear(); | |
172 this->passed_params_vector_.push_back(SharedVariant(new Variant(a1))); | |
173 this->passed_params_vector_.push_back(SharedVariant(new Variant(a2))); | |
174 this->passed_params_vector_.push_back(SharedVariant(new Variant(a3))); | |
175 this->passed_params_vector_.push_back(SharedVariant(new Variant(a4))); | |
176 this->passed_params_vector_.push_back(SharedVariant(new Variant(a5))); | |
177 this->passed_params_vector_.push_back(SharedVariant(new Variant(a6))); | |
178 return this->value_to_return(); | |
179 } | |
180 }; | |
181 | |
182 | |
183 // The actual implementation of InvokeAndCheckEquivalence. This is sort of a | |
184 // hack to make the type of FakeCallback<Signature>::Func available through | |
185 // function template type deduction. | |
186 // See InvokeAndCheckEquivalence below for information on what the function | |
187 // does. | |
188 template <class Signature, class ReturnType, class MemFunSignature> | |
189 void InvokeAndCheckEquivalenceImpl(const VariantVector& parameters_to_pass, | |
190 ReturnType expected_return_value, | |
191 FakeCallback<Signature> callback_mock, | |
192 MemFunSignature func_ptr) { | |
193 // Create an appropriate FunctionInvoker that can handle the type of | |
194 // FakeCallback<Signature>::Func. | |
195 c_salt::FunctionInvoker<MemFunSignature> invoker(&callback_mock, func_ptr); | |
196 // Remember the expected return value (as a variant) | |
197 SharedVariant expected_return_value_var(new Variant(expected_return_value)); | |
198 callback_mock.set_value_to_return(expected_return_value_var); | |
199 // actual_return_value_var will be set when we invoke the function. | |
200 SharedVariant actual_return_value_var; | |
201 invoker.Invoke(&(*parameters_to_pass.begin()), | |
202 &(*parameters_to_pass.end()), | |
203 &actual_return_value_var); | |
204 // The value written to actual_return_value_var should match the expected | |
205 // value we told callback_mock to return. | |
206 EXPECT_EQ(*expected_return_value_var, *actual_return_value_var); | |
207 // The parameters that callback_mock received should match the ones we passed. | |
208 // Along the way: | |
209 // -Invoke converted the vector of variants in to the individual parameters | |
210 // of the real C++ types necessary for passing to FakeCallback::Func | |
211 // -Invoke called FakeCallback::Func with those arguments (via a | |
212 // boost::function) | |
213 // -FakeCallback::Func took the real arguments and pushed them in to its | |
214 // passed_params_vector. | |
215 // All that should result in the values in | |
216 // callback_mock.passed_params_vector() matching the values we sent in at the | |
217 // outset in parameters_to_pass. | |
218 // First, make sure the sizes match; we assume this in the loop that follows. | |
219 ASSERT_EQ(parameters_to_pass.size(), | |
220 callback_mock.passed_params_vector().size()); | |
221 VariantVector::const_iterator | |
222 expected_params_iter(parameters_to_pass.begin()), | |
223 expected_params_end(parameters_to_pass.end()), | |
224 actual_params_iter(callback_mock.passed_params_vector().begin()); | |
225 for (; | |
226 expected_params_iter != expected_params_end; | |
227 ++expected_params_iter, ++actual_params_iter) { | |
228 EXPECT_EQ(*(*expected_params_iter), *(*actual_params_iter)); | |
229 } | |
230 } | |
231 | |
232 // Use a FunctionInvoker to invoke Func on the given FakeCallback, passing | |
233 // parameters_to_pass. Set the FakeCallback to return expected_return_value. | |
234 // Then, use gtest macros to make sure that the FakeCallback was passed the | |
235 // correct parameters and that its return value was converted properly also. | |
236 template <class Signature, class ReturnType> | |
237 void InvokeAndCheckEquivalence(const VariantVector& parameters_to_pass, | |
238 ReturnType expected_return_value, | |
239 FakeCallback<Signature> callback_mock) { | |
240 InvokeAndCheckEquivalenceImpl(parameters_to_pass, | |
241 expected_return_value, | |
242 callback_mock, | |
243 &FakeCallback<Signature>::Func); | |
244 } | |
245 | |
246 } // unnamed namespace | |
247 | |
248 // Test framework. We just put some values we want to test for each type | |
249 // in to vectors. | |
250 class CallbackTest : public ::testing::Test { | |
251 protected: | |
252 virtual void SetUp() { | |
253 int32_t_values_.push_back(0); | |
254 int32_t_values_.push_back( | |
255 std::numeric_limits<int32_t>::max()); | |
256 int32_t_values_.push_back( | |
257 std::numeric_limits<int32_t>::min()); | |
258 | |
259 bool_values_.push_back(false); | |
260 bool_values_.push_back(true); | |
261 | |
262 string_values_.push_back(""); | |
263 string_values_.push_back("Hello world!"); | |
264 | |
265 double_values_.push_back(0.0); | |
266 double_values_.push_back( | |
267 std::numeric_limits<double>::infinity()); | |
268 double_values_.push_back( | |
269 std::numeric_limits<double>::max()); | |
270 double_values_.push_back( | |
271 std::numeric_limits<double>::min()); | |
272 } | |
273 | |
274 // These vectors define what values we will test for each possible parameter | |
275 // type. | |
276 std::vector<int32_t> int32_t_values_; | |
277 std::vector<bool> bool_values_; | |
278 std::vector<double> double_values_; | |
279 std::vector<std::string> string_values_; | |
280 }; | |
281 | |
282 using std::string; // So we can refer to it as just string for the macros | |
283 | |
284 // Check that all values we want to test for the given type are returned | |
285 // properly. | |
286 #define TEST_RETURN_TYPE(TYPE) \ | |
287 { \ | |
288 VariantVector params; \ | |
289 FakeCallback<TYPE()> mock; \ | |
290 std::vector<TYPE>::const_iterator iter(this->TYPE ## _values_.begin()), \ | |
291 the_end(this->TYPE ## _values_.end()); \ | |
292 for (; iter != the_end; ++iter) { \ | |
293 InvokeAndCheckEquivalence(params, *iter, mock); \ | |
294 } \ | |
295 } | |
296 | |
297 // Test that each type is returned properly. | |
298 TEST_F(CallbackTest, EmptyParamsCheckReturn) { | |
299 TEST_RETURN_TYPE(bool); //NOLINT - Lint thinks this is a function declaration | |
300 TEST_RETURN_TYPE(double); //NOLINT | |
301 TEST_RETURN_TYPE(int32_t); //NOLINT | |
302 TEST_RETURN_TYPE(string); //NOLINT | |
303 } | |
304 | |
305 // Check that all values we want to test for the given type are passed properly | |
306 // to 1-param functions. | |
307 #define TEST_PARAM_TYPE1(TYPE) \ | |
308 { \ | |
309 VariantVector params(1); \ | |
310 FakeCallback<bool(TYPE)> mock; /* NOLINT - thinks that's a C-style cast */ \ | |
311 std::vector<TYPE>::const_iterator iter(this->TYPE ## _values_.begin()), \ | |
312 the_end(this->TYPE ## _values_.end()); \ | |
313 for (; iter != the_end; ++iter) { \ | |
314 params[0].reset(new Variant(*iter)); \ | |
315 InvokeAndCheckEquivalence(params, false, mock); \ | |
316 } \ | |
317 } | |
318 | |
319 // Check that all values we want to test for the given types are passed properly | |
320 // to 2-param functions. | |
321 #define TEST_PARAM_TYPE2(TYPE1, TYPE2) \ | |
322 { \ | |
323 VariantVector params(2); \ | |
324 FakeCallback<bool(TYPE1, TYPE2)> mock; /* NOLINT: thinks C-style cast */ \ | |
325 std::vector<TYPE1>::const_iterator iter1(this->TYPE1 ## _values_.begin()), \ | |
326 the_end1(this->TYPE1 ## _values_.end()); \ | |
327 for (; iter1 != the_end1; ++iter1) { \ | |
328 params[0].reset(new Variant(*iter1)); \ | |
329 std::vector<TYPE2>::const_iterator iter2(this->TYPE2 ## _values_.begin()), \ | |
330 the_end2(this->TYPE2 ## _values_.end()); \ | |
331 for (; iter2 != the_end2; ++iter2) { \ | |
332 params[1].reset(new Variant(*iter2)); \ | |
333 InvokeAndCheckEquivalence(params, false, mock); \ | |
334 } \ | |
335 } \ | |
336 } | |
337 | |
338 TEST_F(CallbackTest, CheckParamsThorough) { | |
339 // Test 1-parameter calls for all types | |
340 TEST_PARAM_TYPE1(bool); // NOLINT - Lint thinks these are function | |
341 // declarations with unnamed parameters. | |
342 TEST_PARAM_TYPE1(double); // NOLINT | |
343 TEST_PARAM_TYPE1(int32_t); // NOLINT | |
344 TEST_PARAM_TYPE1(string); // NOLINT | |
345 // Test 2-parameter calls for all pairs of types | |
346 TEST_PARAM_TYPE2(bool, bool); // NOLINT | |
347 TEST_PARAM_TYPE2(bool, double); // NOLINT | |
348 TEST_PARAM_TYPE2(bool, int32_t); // NOLINT | |
349 TEST_PARAM_TYPE2(bool, string); // NOLINT | |
350 TEST_PARAM_TYPE2(double, bool); // NOLINT | |
351 TEST_PARAM_TYPE2(double, double); // NOLINT | |
352 TEST_PARAM_TYPE2(double, int32_t); // NOLINT | |
353 TEST_PARAM_TYPE2(double, string); // NOLINT | |
354 TEST_PARAM_TYPE2(int32_t, bool); // NOLINT | |
355 TEST_PARAM_TYPE2(int32_t, double); // NOLINT | |
356 TEST_PARAM_TYPE2(int32_t, int32_t); // NOLINT | |
357 TEST_PARAM_TYPE2(int32_t, string); // NOLINT | |
358 TEST_PARAM_TYPE2(string, bool); // NOLINT | |
359 TEST_PARAM_TYPE2(string, double); // NOLINT | |
360 TEST_PARAM_TYPE2(string, int32_t); // NOLINT | |
361 TEST_PARAM_TYPE2(string, string); // NOLINT | |
362 } | |
363 | |
364 // Try a few arbitrarily chosen invocations, making sure to cover | |
365 // each number of arguments. | |
366 TEST_F(CallbackTest, CheckParamsSpotTesting) { | |
367 { | |
368 VariantVector params(3); | |
369 FakeCallback<bool(double, int32_t, std::string)> mock3; // NOLINT: not cast | |
370 params[0].reset(new Variant(3.1415)); | |
371 params[1].reset(new Variant(static_cast<int32_t>(42))); | |
372 params[2].reset(new Variant(std::string( | |
373 "\"Beware of bugs in the above code; I have only proved it correct, " | |
374 "not tried it.\" -Knuth"))); | |
375 InvokeAndCheckEquivalence(params, false, mock3); | |
376 | |
377 // Add another param, this time a bool. | |
378 FakeCallback<bool(double, int32_t, std::string, bool)> mock4; // NOLINT | |
379 params.push_back(SharedVariant(new Variant(false))); | |
380 InvokeAndCheckEquivalence(params, false, mock4); | |
381 | |
382 // Add another param, this time another int32_t. | |
383 FakeCallback<bool(double, // NOLINT - this is not a C-style cast | |
384 int32_t, | |
385 std::string, | |
386 bool, | |
387 int32_t)> mock5; | |
388 params.push_back(SharedVariant(new Variant(static_cast<int32_t>(5)))); | |
389 InvokeAndCheckEquivalence(params, false, mock5); | |
390 | |
391 // Add another param, this time another double. | |
392 FakeCallback<bool(double, // NOLINT - this is not a C-style cast | |
393 int32_t, | |
394 std::string, | |
395 bool, | |
396 int32_t, | |
397 double)> | |
398 mock6; | |
399 params.push_back(SharedVariant(new Variant(3.0e6))); | |
400 InvokeAndCheckEquivalence(params, false, mock6); | |
401 } | |
402 } | |
403 | |
404 // Try a few arbitrarily chosen invocations, making sure to cover | |
405 // each number of arguments. | |
406 TEST_F(CallbackTest, CheckConstRefParams) { | |
407 { | |
408 VariantVector params(3); | |
409 FakeCallback<bool(const double&, // NOLINT - this is not a C-style cast | |
410 const int32_t&, | |
411 const std::string&)> mock3; | |
412 params[0].reset(new Variant(3.1415)); | |
413 params[1].reset(new Variant(static_cast<int32_t>(42))); | |
414 params[2].reset(new Variant(std::string( | |
415 "\"Beware of bugs in the above code; I have only proved it correct, " | |
416 "not tried it.\" -Knuth"))); | |
417 InvokeAndCheckEquivalence(params, false, mock3); | |
418 | |
419 // Add another param, this time a bool. | |
420 FakeCallback<bool(const double&, // NOLINT - this is not a C-style cast | |
421 const int32_t&, | |
422 const std::string&, | |
423 const bool&)> mock4; | |
424 params.push_back(SharedVariant(new Variant(false))); | |
425 InvokeAndCheckEquivalence(params, false, mock4); | |
426 | |
427 // Add another param, this time another int32_t. | |
428 FakeCallback<bool(const double&, // NOLINT - this is not a C-style cast | |
429 const int32_t&, | |
430 const std::string&, | |
431 const bool&, | |
432 const int32_t&)> mock5; | |
433 params.push_back(SharedVariant(new Variant(static_cast<int32_t>(5)))); | |
434 InvokeAndCheckEquivalence(params, false, mock5); | |
435 | |
436 // Add another param, this time another double. | |
437 FakeCallback<bool(const double&, // NOLINT - this is not a C-style cast | |
438 const int32_t&, | |
439 const std::string&, | |
440 const bool&, | |
441 const int32_t&, | |
442 const double&)> | |
443 mock6; | |
444 params.push_back(SharedVariant(new Variant(3.0e6))); | |
445 InvokeAndCheckEquivalence(params, false, mock6); | |
446 } | |
447 } | |
OLD | NEW |