Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/test/core/command/FunctorTest.cc @ 10986

Last change on this file since 10986 was 10986, checked in by landauf, 8 years ago

use the existing class 'FunctorPointer' to store the callable object. functors with callable objects (e.g. lambdas) are now treated as static functors.
this also fixes an issue on gcc: because of a bug, gcc was not able to store the function pointer of a lambda's operator() https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51048. storing the whole object is apparently a workaround for this issue.

Note: tests currently fail on MSVC because it doesn't accept std::function as a callable object.

  • Property svn:eol-style set to native
File size: 38.3 KB
Line 
1#include <gtest/gtest.h>
2#include <gmock/gmock.h>
3#include <functional>
4#include "core/command/Functor.h"
5
6namespace orxonox
7{
8    namespace
9    {
10        // Fixture
11        class FunctorTest : public ::testing::Test
12        {
13            public:
14                virtual void SetUp() override
15                {
16                }
17
18                virtual void TearDown() override
19                {
20                }
21        };
22
23        class DestroyableClass : public Destroyable
24        {
25            public:
26                virtual void        method0() { return; }
27                virtual int         method1(int arg1) { return arg1; }
28                virtual float       method2(int arg1, float arg2) { return arg2; }
29                virtual bool        method3(int arg1, float arg2, bool arg3) { return arg3; }
30                virtual std::string method4(int arg1, float arg2, bool arg3, const std::string& arg4) { return arg4; }
31                virtual Vector3     method5(int arg1, float arg2, bool arg3, const std::string& arg4, const Vector3& arg5) { return arg5; }
32
33                static void        staticmethod0()
34                    { return staticinstance->method0(); }
35                static int         staticmethod1(int arg1)
36                    { return staticinstance->method1(arg1); }
37                static float       staticmethod2(int arg1, float arg2)
38                    { return staticinstance->method2(arg1, arg2); }
39                static bool        staticmethod3(int arg1, float arg2, bool arg3)
40                    { return staticinstance->method3(arg1, arg2, arg3); }
41                static std::string staticmethod4(int arg1, float arg2, bool arg3, const std::string& arg4)
42                    { return staticinstance->method4(arg1, arg2, arg3, arg4); }
43                static Vector3     staticmethod5(int arg1, float arg2, bool arg3, const std::string& arg4, const Vector3& arg5)
44                    { return staticinstance->method5(arg1, arg2, arg3, arg4, arg5); }
45
46                static DestroyableClass* staticinstance;
47        };
48
49        DestroyableClass* DestroyableClass::staticinstance = nullptr;
50
51        class MockDestroyableClass : public DestroyableClass
52        {
53            public:
54                MOCK_METHOD0(method0, void());
55                MOCK_METHOD1(method1, int(int));
56                MOCK_METHOD2(method2, float(int, float));
57                MOCK_METHOD3(method3, bool(int, float, bool));
58                MOCK_METHOD4(method4, std::string(int, float, bool, const std::string&));
59                MOCK_METHOD5(method5, Vector3(int, float, bool, const std::string&, const Vector3&));
60        };
61
62        class NonDestroyableClass
63        {
64            public:
65                void method() {}
66        };
67
68        void f1(int, double) {}
69        void f2(int, double, double) {}
70        int f3(int, double, double) { return 0; }
71        int f4a(int arg) { return arg*2; }
72        int f4b(int arg) { return arg*3; }
73        int multiply(int a, int b) { return a*b; }
74
75        struct CallableStruct
76        {
77            public:
78                int operator()()
79                {
80                    return 1;
81                }
82        };
83    }
84
85
86    ///////////////////////////////////////////////////////////////
87    ////////////////////// Functor (general) //////////////////////
88    ///////////////////////////////////////////////////////////////
89
90    TEST_F(FunctorTest, HasCorrectType)
91    {
92        FunctorMemberPtr<DestroyableClass> functor1 = createFunctor(&DestroyableClass::method0);
93        FunctorStaticPtr functor2 = createFunctor(&DestroyableClass::staticmethod0);
94        EXPECT_EQ(Functor::Type::Member, functor1->getType());
95        EXPECT_EQ(Functor::Type::Static, functor2->getType());
96    }
97
98    TEST_F(FunctorTest, ReturnsCorrectParamCount)
99    {
100        EXPECT_EQ(0, createFunctor(&DestroyableClass::method0)->getParamCount());
101        EXPECT_EQ(1, createFunctor(&DestroyableClass::method1)->getParamCount());
102        EXPECT_EQ(2, createFunctor(&DestroyableClass::method2)->getParamCount());
103        EXPECT_EQ(3, createFunctor(&DestroyableClass::method3)->getParamCount());
104        EXPECT_EQ(4, createFunctor(&DestroyableClass::method4)->getParamCount());
105        EXPECT_EQ(5, createFunctor(&DestroyableClass::method5)->getParamCount());
106    }
107
108    TEST_F(FunctorTest, HasReturnValue)
109    {
110        EXPECT_FALSE(createFunctor(&DestroyableClass::method0)->hasReturnvalue());
111        EXPECT_TRUE(createFunctor(&DestroyableClass::method1)->hasReturnvalue());
112        EXPECT_TRUE(createFunctor(&DestroyableClass::method2)->hasReturnvalue());
113        EXPECT_TRUE(createFunctor(&DestroyableClass::method3)->hasReturnvalue());
114        EXPECT_TRUE(createFunctor(&DestroyableClass::method4)->hasReturnvalue());
115        EXPECT_TRUE(createFunctor(&DestroyableClass::method5)->hasReturnvalue());
116    }
117
118    TEST_F(FunctorTest, GetTypenameParam)
119    {
120        FunctorPtr functor = createFunctor(&DestroyableClass::method5);
121        EXPECT_EQ("int",     functor->getTypenameParam(0));
122        EXPECT_EQ("float",   functor->getTypenameParam(1));
123        EXPECT_EQ("bool",    functor->getTypenameParam(2));
124        EXPECT_EQ("string",  functor->getTypenameParam(3));
125        EXPECT_EQ("Vector3", functor->getTypenameParam(4));
126        EXPECT_EQ("",        functor->getTypenameParam(5)); // max 5 arguments supported (index 0-4) -> this returns empty string
127    }
128
129    TEST_F(FunctorTest, TypenameParamIsAlwaysVoidForFunctionWithoutParams)
130    {
131        FunctorPtr functor = createFunctor(&DestroyableClass::method0);
132        EXPECT_EQ("void", functor->getTypenameParam(0));
133        EXPECT_EQ("void", functor->getTypenameParam(1));
134        EXPECT_EQ("void", functor->getTypenameParam(2));
135        EXPECT_EQ("void", functor->getTypenameParam(3));
136        EXPECT_EQ("void", functor->getTypenameParam(4));
137        EXPECT_EQ("",     functor->getTypenameParam(5)); // max 5 arguments supported (index 0-4) -> this returns empty string
138    }
139
140    TEST_F(FunctorTest, GetTypenameReturnvalue)
141    {
142        EXPECT_EQ("void",    createFunctor(&DestroyableClass::method0)->getTypenameReturnvalue());
143        EXPECT_EQ("int",     createFunctor(&DestroyableClass::method1)->getTypenameReturnvalue());
144        EXPECT_EQ("float",   createFunctor(&DestroyableClass::method2)->getTypenameReturnvalue());
145        EXPECT_EQ("bool",    createFunctor(&DestroyableClass::method3)->getTypenameReturnvalue());
146        EXPECT_EQ("string",  createFunctor(&DestroyableClass::method4)->getTypenameReturnvalue());
147        EXPECT_EQ("Vector3", createFunctor(&DestroyableClass::method5)->getTypenameReturnvalue());
148    }
149
150    TEST_F(FunctorTest, GetFullIdentifier)
151    {
152        // static
153        EXPECT_EQ(typeid(       void(*)()),                                                     createFunctor(&DestroyableClass::staticmethod0)->getFullIdentifier());
154        EXPECT_EQ(typeid(        int(*)(int)),                                                  createFunctor(&DestroyableClass::staticmethod1)->getFullIdentifier());
155        EXPECT_EQ(typeid(      float(*)(int, float)),                                           createFunctor(&DestroyableClass::staticmethod2)->getFullIdentifier());
156        EXPECT_EQ(typeid(       bool(*)(int, float, bool)),                                     createFunctor(&DestroyableClass::staticmethod3)->getFullIdentifier());
157        EXPECT_EQ(typeid(std::string(*)(int, float, bool, const std::string&)),                 createFunctor(&DestroyableClass::staticmethod4)->getFullIdentifier());
158        EXPECT_EQ(typeid(    Vector3(*)(int, float, bool, const std::string&, const Vector3&)), createFunctor(&DestroyableClass::staticmethod5)->getFullIdentifier());
159
160        // member
161        EXPECT_EQ(typeid(       void(DestroyableClass::*)()),                                                     createFunctor(&DestroyableClass::method0)->getFullIdentifier());
162        EXPECT_EQ(typeid(        int(DestroyableClass::*)(int)),                                                  createFunctor(&DestroyableClass::method1)->getFullIdentifier());
163        EXPECT_EQ(typeid(      float(DestroyableClass::*)(int, float)),                                           createFunctor(&DestroyableClass::method2)->getFullIdentifier());
164        EXPECT_EQ(typeid(       bool(DestroyableClass::*)(int, float, bool)),                                     createFunctor(&DestroyableClass::method3)->getFullIdentifier());
165        EXPECT_EQ(typeid(std::string(DestroyableClass::*)(int, float, bool, const std::string&)),                 createFunctor(&DestroyableClass::method4)->getFullIdentifier());
166        EXPECT_EQ(typeid(    Vector3(DestroyableClass::*)(int, float, bool, const std::string&, const Vector3&)), createFunctor(&DestroyableClass::method5)->getFullIdentifier());
167    }
168
169    TEST_F(FunctorTest, GetHeaderIdentifier)
170    {
171        // static
172        EXPECT_EQ(typeid(       void(*)()),                                                     createFunctor(&DestroyableClass::staticmethod0)->getHeaderIdentifier());
173        EXPECT_EQ(typeid(        int(*)(int)),                                                  createFunctor(&DestroyableClass::staticmethod1)->getHeaderIdentifier());
174        EXPECT_EQ(typeid(      float(*)(int, float)),                                           createFunctor(&DestroyableClass::staticmethod2)->getHeaderIdentifier());
175        EXPECT_EQ(typeid(       bool(*)(int, float, bool)),                                     createFunctor(&DestroyableClass::staticmethod3)->getHeaderIdentifier());
176        EXPECT_EQ(typeid(std::string(*)(int, float, bool, const std::string&)),                 createFunctor(&DestroyableClass::staticmethod4)->getHeaderIdentifier());
177        EXPECT_EQ(typeid(    Vector3(*)(int, float, bool, const std::string&, const Vector3&)), createFunctor(&DestroyableClass::staticmethod5)->getHeaderIdentifier());
178
179        // member
180        EXPECT_EQ(typeid(       void(*)()),                                                     createFunctor(&DestroyableClass::method0)->getHeaderIdentifier());
181        EXPECT_EQ(typeid(        int(*)(int)),                                                  createFunctor(&DestroyableClass::method1)->getHeaderIdentifier());
182        EXPECT_EQ(typeid(      float(*)(int, float)),                                           createFunctor(&DestroyableClass::method2)->getHeaderIdentifier());
183        EXPECT_EQ(typeid(       bool(*)(int, float, bool)),                                     createFunctor(&DestroyableClass::method3)->getHeaderIdentifier());
184        EXPECT_EQ(typeid(std::string(*)(int, float, bool, const std::string&)),                 createFunctor(&DestroyableClass::method4)->getHeaderIdentifier());
185        EXPECT_EQ(typeid(    Vector3(*)(int, float, bool, const std::string&, const Vector3&)), createFunctor(&DestroyableClass::method5)->getHeaderIdentifier());
186    }
187
188    TEST_F(FunctorTest, GetHeaderIdentifierFor2Params)
189    {
190        // static
191        EXPECT_EQ(typeid(       void(*)()),           createFunctor(&DestroyableClass::staticmethod0)->getHeaderIdentifier(2));
192        EXPECT_EQ(typeid(        int(*)(int)),        createFunctor(&DestroyableClass::staticmethod1)->getHeaderIdentifier(2));
193        EXPECT_EQ(typeid(      float(*)(int, float)), createFunctor(&DestroyableClass::staticmethod2)->getHeaderIdentifier(2));
194        EXPECT_EQ(typeid(       bool(*)(int, float)), createFunctor(&DestroyableClass::staticmethod3)->getHeaderIdentifier(2));
195        EXPECT_EQ(typeid(std::string(*)(int, float)), createFunctor(&DestroyableClass::staticmethod4)->getHeaderIdentifier(2));
196        EXPECT_EQ(typeid(    Vector3(*)(int, float)), createFunctor(&DestroyableClass::staticmethod5)->getHeaderIdentifier(2));
197
198        // member
199        EXPECT_EQ(typeid(       void(*)()),           createFunctor(&DestroyableClass::method0)->getHeaderIdentifier(2));
200        EXPECT_EQ(typeid(        int(*)(int)),        createFunctor(&DestroyableClass::method1)->getHeaderIdentifier(2));
201        EXPECT_EQ(typeid(      float(*)(int, float)), createFunctor(&DestroyableClass::method2)->getHeaderIdentifier(2));
202        EXPECT_EQ(typeid(       bool(*)(int, float)), createFunctor(&DestroyableClass::method3)->getHeaderIdentifier(2));
203        EXPECT_EQ(typeid(std::string(*)(int, float)), createFunctor(&DestroyableClass::method4)->getHeaderIdentifier(2));
204        EXPECT_EQ(typeid(    Vector3(*)(int, float)), createFunctor(&DestroyableClass::method5)->getHeaderIdentifier(2));
205    }
206
207    TEST_F(FunctorTest, GetHeaderIdentifierForNParams)
208    {
209        // static
210        FunctorStaticPtr functorStatic = createFunctor(&DestroyableClass::staticmethod5);
211        EXPECT_EQ(typeid(Vector3(*)()),                                                     functorStatic->getHeaderIdentifier(0));
212        EXPECT_EQ(typeid(Vector3(*)(int)),                                                  functorStatic->getHeaderIdentifier(1));
213        EXPECT_EQ(typeid(Vector3(*)(int, float)),                                           functorStatic->getHeaderIdentifier(2));
214        EXPECT_EQ(typeid(Vector3(*)(int, float, bool)),                                     functorStatic->getHeaderIdentifier(3));
215        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&)),                 functorStatic->getHeaderIdentifier(4));
216        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&, const Vector3&)), functorStatic->getHeaderIdentifier(5));
217        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&, const Vector3&)), functorStatic->getHeaderIdentifier(6));
218
219        // member
220        FunctorMemberPtr<DestroyableClass> functorMember = createFunctor(&DestroyableClass::method5);
221        EXPECT_EQ(typeid(Vector3(*)()),                                                     functorMember->getHeaderIdentifier(0));
222        EXPECT_EQ(typeid(Vector3(*)(int)),                                                  functorMember->getHeaderIdentifier(1));
223        EXPECT_EQ(typeid(Vector3(*)(int, float)),                                           functorMember->getHeaderIdentifier(2));
224        EXPECT_EQ(typeid(Vector3(*)(int, float, bool)),                                     functorMember->getHeaderIdentifier(3));
225        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&)),                 functorMember->getHeaderIdentifier(4));
226        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&, const Vector3&)), functorMember->getHeaderIdentifier(5));
227        EXPECT_EQ(typeid(Vector3(*)(int, float, bool, const std::string&, const Vector3&)), functorMember->getHeaderIdentifier(6));
228    }
229
230    TEST_F(FunctorTest, CanClone)
231    {
232        FunctorPtr functor = createFunctor(&f4a);
233        FunctorPtr clone = functor->clone();
234        EXPECT_NE(nullptr, clone.get());
235    }
236
237    TEST_F(FunctorTest, ClonedFunctorCanBeCalled)
238    {
239        FunctorPtr functor = createFunctor(&f4a);
240        FunctorPtr clone = functor->clone();
241
242        EXPECT_EQ(8, (*functor)(4).get<int>());
243        EXPECT_EQ(8, (*clone)(4).get<int>());
244    }
245
246    TEST_F(FunctorTest, ClonedFunctorKeepsFunction)
247    {
248        FunctorPtr functor = createFunctor(&f4a);
249        FunctorPointer<int(*)(int)>* pointer = static_cast<FunctorPointer<int(*)(int)>*>(functor.get());
250
251        FunctorPtr clone = functor->clone();
252        FunctorPointer<int(*)(int)>* clonePointer = static_cast<FunctorPointer<int(*)(int)>*>(clone.get());
253
254        EXPECT_EQ(&f4a, pointer->getFunction());
255        EXPECT_EQ(&f4a, clonePointer->getFunction());
256    }
257
258    TEST_F(FunctorTest, ClonedFunctorKeepsObject)
259    {
260        DestroyableClass object;
261        FunctorPtr functor = createFunctor(&DestroyableClass::method0, &object);
262        FunctorPtr clone = functor->clone();
263
264        EXPECT_EQ(&object, functor->getRawObjectPointer());
265        EXPECT_EQ(&object, clone->getRawObjectPointer());
266    }
267
268    // TODO: test fails... fix or delete clone()
269//    TEST_F(FunctorTest, ClonedFunctorKeepsSafeMode)
270//    {
271//        DestroyableClass* object = new DestroyableClass();
272//        FunctorPtr functor = createFunctor(&DestroyableClass::method0, object);
273//        functor->setSafeMode(true);
274//        FunctorPtr clone = functor->clone();
275//
276//        EXPECT_EQ(object, functor->getRawObjectPointer());
277//        EXPECT_EQ(object, clone->getRawObjectPointer());
278//        object->destroy();
279//        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
280//        EXPECT_EQ(nullptr, clone->getRawObjectPointer());
281//
282//    }
283
284    TEST_F(FunctorTest, CanEvaluateArgument)
285    {
286        FunctorPtr functor = createFunctor(&f4a);
287        MultiType value("5");
288        EXPECT_FALSE(value.isType<int>());
289        EXPECT_TRUE(value.isType<std::string>());
290        functor->evaluateArgument(0, value);
291        EXPECT_TRUE(value.isType<int>());
292        EXPECT_FALSE(value.isType<std::string>());
293    }
294
295    TEST_F(FunctorTest, CanGetAndSetFunctionPointer)
296    {
297        FunctorPtr functor = createFunctor(&f4a);
298        FunctorPointer<int(*)(int)>* pointer = static_cast<FunctorPointer<int(*)(int)>*>(functor.get());
299
300        EXPECT_EQ(6, (*functor)(3).get<int>()); // 3*2 = 6
301        EXPECT_EQ(&f4a, pointer->getFunction());
302
303        pointer->setFunction(&f4b);
304
305        EXPECT_EQ(9, (*functor)(3).get<int>()); // 3*3 = 9
306        EXPECT_EQ(&f4b, pointer->getFunction());
307    }
308
309    TEST_F(FunctorTest, ReturnsValue)
310    {
311        DestroyableClass object;
312        {
313            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method1);
314            int result = (*functor)(&object, 13);
315            EXPECT_EQ(13, result);
316        }
317        {
318            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method2);
319            float result = (*functor)(&object, 0, 111.11f);
320            EXPECT_FLOAT_EQ(111.11f, result);
321        }
322        {
323            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method3);
324            bool result = (*functor)(&object, 0, 0, true);
325            EXPECT_EQ(true, result);
326        }
327        {
328            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method4);
329            std::string result = (*functor)(&object, 0, 0, false, "test");
330            EXPECT_EQ("test", result);
331        }
332        {
333            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method5);
334            Vector3 result = (*functor)(&object, 0, 0, false, "", Vector3(3, 2, 1));
335            EXPECT_EQ(Vector3(3, 2, 1), result);
336        }
337    }
338
339
340    ///////////////////////////////////////////////////////////
341    ////////////////////// FunctorMember //////////////////////
342    ///////////////////////////////////////////////////////////
343
344    TEST_F(FunctorTest, FunctorMember_CanSetObject)
345    {
346        DestroyableClass object;
347
348        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
349        EXPECT_EQ(nullptr, functor->getObject());
350        functor->setObject(&object);
351        EXPECT_EQ(&object, functor->getObject());
352        functor->setObject(nullptr);
353        EXPECT_EQ(nullptr, functor->getObject());
354    }
355
356    TEST_F(FunctorTest, FunctorMember_CanSetObjectInConstructor)
357    {
358        DestroyableClass object;
359
360        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0, &object);
361        EXPECT_EQ(&object, functor->getObject());
362        functor->setObject(nullptr);
363        EXPECT_EQ(nullptr, functor->getObject());
364    }
365
366    TEST_F(FunctorTest, FunctorMember_CanSetRawObjectPointer)
367    {
368        DestroyableClass object;
369
370        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
371        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
372        functor->setRawObjectPointer(&object);
373        EXPECT_EQ(&object, functor->getRawObjectPointer());
374        functor->setRawObjectPointer(nullptr);
375        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
376    }
377
378    TEST_F(FunctorTest, FunctorMember_RawObjectPointerAndObjectAreEqual)
379    {
380        DestroyableClass object1;
381        DestroyableClass object2;
382
383        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
384        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
385        EXPECT_EQ(nullptr, functor->getObject());
386        functor->setObject(&object1);
387        EXPECT_EQ(&object1, functor->getRawObjectPointer());
388        EXPECT_EQ(&object1, functor->getObject());
389        functor->setObject(&object2);
390        EXPECT_EQ(&object2, functor->getRawObjectPointer());
391        EXPECT_EQ(&object2, functor->getObject());
392    }
393
394    TEST_F(FunctorTest, FunctorMember_SafeModeWorks_SetObjectThenActivateSafeMode)
395    {
396        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
397        {
398            DestroyableClass object;
399            functor->setObject(&object);
400            functor->setSafeMode(true);
401            EXPECT_EQ(&object, functor->getObject());
402        }
403        EXPECT_EQ(nullptr, functor->getObject());
404    }
405
406    TEST_F(FunctorTest, FunctorMember_SafeModeWorks_ActivateSafeModeThenSetObject)
407    {
408        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
409        {
410            DestroyableClass object;
411            functor->setSafeMode(true);
412            functor->setObject(&object);
413            EXPECT_EQ(&object, functor->getObject());
414        }
415        EXPECT_EQ(nullptr, functor->getObject());
416    }
417
418    TEST_F(FunctorTest, FunctorMember_SafeModeCanBeDisabledAfterObjectWasSet)
419    {
420        DestroyableClass* ptr;
421        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
422        {
423            DestroyableClass object;
424            functor->setSafeMode(true);
425            functor->setObject(&object);
426            functor->setSafeMode(false);
427            ptr = &object; // remember the pointer
428            EXPECT_EQ(ptr, functor->getObject());
429        }
430        EXPECT_EQ(ptr, functor->getObject());
431    }
432
433    TEST_F(FunctorTest, FunctorMember_SafeModeWorks_CanChangeObject)
434    {
435        FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
436        DestroyableClass* object1 = new DestroyableClass();
437        DestroyableClass* object2 = new DestroyableClass();
438        functor->setSafeMode(true);
439
440        functor->setObject(object1);
441        EXPECT_EQ(object1, functor->getObject());
442        functor->setObject(object2);
443        EXPECT_EQ(object2, functor->getObject());
444        object1->destroy();
445        EXPECT_EQ(object2, functor->getObject());
446        object2->destroy();
447        EXPECT_EQ(nullptr, functor->getObject());
448    }
449
450    TEST_F(FunctorTest, FunctorMember_CanDestroyFunctorWhenObjectInSafeModeStillExists)
451    {
452        DestroyableClass object;
453        {
454            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
455            functor->setSafeMode(true);
456            functor->setObject(&object);
457            EXPECT_EQ(&object, functor->getObject());
458        } // functor is destroyed here
459    }
460
461    TEST_F(FunctorTest, FunctorMember_SafeModeDoesntDoAnythingWithObjectsNotInheritedFromDestroyable)
462    {
463        NonDestroyableClass* ptr;
464        FunctorMemberPtr<NonDestroyableClass> functor = createFunctor(&NonDestroyableClass::method);
465        {
466            NonDestroyableClass object;
467            functor->setSafeMode(true);
468            functor->setObject(&object);
469            ptr = &object; // remember the pointer
470            EXPECT_EQ(ptr, functor->getObject());
471        }
472        EXPECT_EQ(ptr, functor->getObject()); // pointer is still set because safe mode doesn't work on NonDestroyableClass
473    }
474
475    TEST_F(FunctorTest, FunctorMember_CanCall_WithObjectInCall)
476    {
477        MockDestroyableClass mock;
478        {
479            EXPECT_CALL(mock, method0());
480            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0);
481            (*functor)(&mock);
482        }
483        {
484            EXPECT_CALL(mock, method1(13)).WillOnce(::testing::Return(0));
485            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method1);
486            (*functor)(&mock, 13);
487        }
488        {
489            EXPECT_CALL(mock, method2(13, 111.11f)).WillOnce(::testing::Return(0.0f));
490            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method2);
491            (*functor)(&mock, 13, 111.11f);
492        }
493        {
494            EXPECT_CALL(mock, method3(13, 111.11f, true)).WillOnce(::testing::Return(false));
495            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method3);
496            (*functor)(&mock, 13, 111.11f, true);
497        }
498        {
499            EXPECT_CALL(mock, method4(13, 111.11f, true, "test")).WillOnce(::testing::Return(""));
500            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method4);
501            (*functor)(&mock, 13, 111.11f, true, "test");
502        }
503        {
504            EXPECT_CALL(mock, method5(13, 111.11f, true, "test", Vector3(3, 2, 1))).WillOnce(::testing::Return(Vector3()));
505            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method5);
506            (*functor)(&mock, 13, 111.11f, true, "test", Vector3(3, 2, 1));
507        }
508    }
509
510    TEST_F(FunctorTest, FunctorMember_CanCall_WithObjectInConstructor)
511    {
512        MockDestroyableClass mock;
513        {
514            EXPECT_CALL(mock, method0());
515            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method0, &mock);
516            (*functor)();
517        }
518        {
519            EXPECT_CALL(mock, method1(13)).WillOnce(::testing::Return(0));
520            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method1, &mock);
521            (*functor)(13);
522        }
523        {
524            EXPECT_CALL(mock, method2(13, 111.11f)).WillOnce(::testing::Return(0.0f));
525            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method2, &mock);
526            (*functor)(13, 111.11f);
527        }
528        {
529            EXPECT_CALL(mock, method3(13, 111.11f, true)).WillOnce(::testing::Return(false));
530            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method3, &mock);
531            (*functor)(13, 111.11f, true);
532        }
533        {
534            EXPECT_CALL(mock, method4(13, 111.11f, true, "test")).WillOnce(::testing::Return(""));
535            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method4, &mock);
536            (*functor)(13, 111.11f, true, "test");
537        }
538        {
539            EXPECT_CALL(mock, method5(13, 111.11f, true, "test", Vector3(3, 2, 1))).WillOnce(::testing::Return(Vector3()));
540            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method5, &mock);
541            (*functor)(13, 111.11f, true, "test", Vector3(3, 2, 1));
542        }
543    }
544
545    TEST_F(FunctorTest, FunctorMember_ReturnsZeroIfCalledWithoutObject)
546    {
547        DestroyableClass object;
548        {
549            FunctorMemberPtr<DestroyableClass> functor = createFunctor(&DestroyableClass::method1);
550            int resultWithObject = (*functor)(&object, 13);
551            int resultWithoutObject = (*functor)(13);
552            EXPECT_EQ(13, resultWithObject);
553            EXPECT_EQ(0, resultWithoutObject);
554        }
555    }
556
557
558    ///////////////////////////////////////////////////////////
559    ////////////////////// FunctorStatic //////////////////////
560    ///////////////////////////////////////////////////////////
561
562    TEST_F(FunctorTest, FunctorStatic_CanCall)
563    {
564        MockDestroyableClass mock;
565        DestroyableClass::staticinstance = &mock;
566
567        {
568            EXPECT_CALL(mock, method0());
569            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod0);
570            (*functor)();
571        }
572        {
573            EXPECT_CALL(mock, method1(13)).WillOnce(::testing::Return(0));
574            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod1);
575            (*functor)(13);
576        }
577        {
578            EXPECT_CALL(mock, method2(13, 111.11f)).WillOnce(::testing::Return(0.0f));
579            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod2);
580            (*functor)(13, 111.11f);
581        }
582        {
583            EXPECT_CALL(mock, method3(13, 111.11f, true)).WillOnce(::testing::Return(false));
584            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod3);
585            (*functor)(13, 111.11f, true);
586        }
587        {
588            EXPECT_CALL(mock, method4(13, 111.11f, true, "test")).WillOnce(::testing::Return(""));
589            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod4);
590            (*functor)(13, 111.11f, true, "test");
591        }
592        {
593            EXPECT_CALL(mock, method5(13, 111.11f, true, "test", Vector3(3, 2, 1))).WillOnce(::testing::Return(Vector3()));
594            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod5);
595            (*functor)(13, 111.11f, true, "test", Vector3(3, 2, 1));
596        }
597    }
598
599    TEST_F(FunctorTest, FunctorStatic_CanCallWithObject)
600    {
601        MockDestroyableClass mock;
602        DestroyableClass::staticinstance = &mock;
603
604        {
605            EXPECT_CALL(mock, method0());
606            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod0);
607            (*functor)(&mock); // object is ignored
608        }
609    }
610
611    TEST_F(FunctorTest, FunctorStatic_CanCallWithNull)
612    {
613        MockDestroyableClass mock;
614        DestroyableClass::staticinstance = &mock;
615
616        {
617            EXPECT_CALL(mock, method0());
618            FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod0);
619            (*functor)(nullptr); // pointer is ignored
620        }
621    }
622
623    TEST_F(FunctorTest, FunctorStatic_RawObjectPointerIsAlwaysNull)
624    {
625        DestroyableClass object;
626
627        FunctorStaticPtr functor = createFunctor(&DestroyableClass::staticmethod0);
628        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
629        functor->setRawObjectPointer(&object);
630        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
631        functor->setRawObjectPointer(nullptr);
632        EXPECT_EQ(nullptr, functor->getRawObjectPointer());
633    }
634
635    ////////////////////////////// Various tests //////////////////////////////
636
637    TEST_F(FunctorTest, CreateFunctorWithVariousFunctionTypes)
638    {
639        FunctorPtr c1 = createFunctor(&f4a);
640        FunctorPtr c2 = createFunctor(&f4b);
641        FunctorPtr c3 = createFunctor([] (int arg) { return arg*4; });
642        auto lambda = [] (int arg1, int arg2) { return arg1*arg2; };
643        FunctorPtr c4 = createFunctor(lambda);
644
645        std::function<int()> bind0 = std::bind(multiply, 4, 6);
646        std::function<int(int)> bind1 = std::bind(multiply, std::placeholders::_1, 7);
647        std::function<int(int, int)> bind2 = std::bind(multiply, std::placeholders::_1, std::placeholders::_2);
648        std::function<int(int)> function = f4a;
649
650        FunctorPtr c5 = createFunctor(bind0);
651        FunctorPtr c6 = createFunctor(bind1);
652        FunctorPtr c7 = createFunctor(bind2);
653        FunctorPtr c8 = createFunctor(function);
654
655
656        EXPECT_EQ(8,  (*c1)(4).get<int>());
657        EXPECT_EQ(12, (*c2)(4).get<int>());
658        EXPECT_EQ(16, (*c3)(4).get<int>());
659        EXPECT_EQ(20, (*c4)(4, 5).get<int>());
660        EXPECT_EQ(24, (*c5)(4).get<int>());
661        EXPECT_EQ(28, (*c6)(4).get<int>());
662        EXPECT_EQ(32, (*c7)(4, 8).get<int>());
663        EXPECT_EQ(8,  (*c8)(4).get<int>());
664
665        EXPECT_EQ(1, c1->getParamCount());
666        EXPECT_EQ(1, c2->getParamCount());
667        EXPECT_EQ(1, c3->getParamCount());
668        EXPECT_EQ(2, c4->getParamCount());
669        EXPECT_EQ(0, c5->getParamCount());
670        EXPECT_EQ(1, c6->getParamCount());
671        EXPECT_EQ(2, c7->getParamCount());
672        EXPECT_EQ(1, c8->getParamCount());
673
674        EXPECT_EQ(typeid(int(*)(int)), c1->getFullIdentifier());
675        EXPECT_EQ(typeid(int(*)(int)), c2->getFullIdentifier());
676        EXPECT_EQ(typeid(int(*)(int)), c3->getFullIdentifier());
677        EXPECT_EQ(typeid(int(*)(int, int)), c4->getFullIdentifier());
678        EXPECT_EQ(typeid(int(*)()), c5->getFullIdentifier());
679        EXPECT_EQ(typeid(int(*)(int)), c6->getFullIdentifier());
680        EXPECT_EQ(typeid(int(*)(int, int)), c7->getFullIdentifier());
681        EXPECT_EQ(typeid(int(*)(int)), c8->getFullIdentifier());
682
683        EXPECT_EQ(typeid(int(*)(int)), c1->getHeaderIdentifier());
684        EXPECT_EQ(typeid(int(*)(int)), c2->getHeaderIdentifier());
685        EXPECT_EQ(typeid(int(*)(int)), c3->getHeaderIdentifier());
686        EXPECT_EQ(typeid(int(*)(int, int)), c4->getHeaderIdentifier());
687        EXPECT_EQ(typeid(int(*)()), c5->getHeaderIdentifier());
688        EXPECT_EQ(typeid(int(*)(int)), c6->getHeaderIdentifier());
689        EXPECT_EQ(typeid(int(*)(int, int)), c7->getHeaderIdentifier());
690        EXPECT_EQ(typeid(int(*)(int)), c8->getHeaderIdentifier());
691
692        EXPECT_EQ(typeid(int(*)(int)), c1->getHeaderIdentifier(1));
693        EXPECT_EQ(typeid(int(*)(int)), c2->getHeaderIdentifier(1));
694        EXPECT_EQ(typeid(int(*)(int)), c3->getHeaderIdentifier(1));
695        EXPECT_EQ(typeid(int(*)(int)), c4->getHeaderIdentifier(1));
696        EXPECT_EQ(typeid(int(*)()), c5->getHeaderIdentifier(1));
697        EXPECT_EQ(typeid(int(*)(int)), c6->getHeaderIdentifier(1));
698        EXPECT_EQ(typeid(int(*)(int)), c7->getHeaderIdentifier(1));
699        EXPECT_EQ(typeid(int(*)(int)), c8->getHeaderIdentifier(1));
700
701        EXPECT_EQ(typeid(int(*)()), c1->getHeaderIdentifier(0));
702        EXPECT_EQ(typeid(int(*)()), c2->getHeaderIdentifier(0));
703        EXPECT_EQ(typeid(int(*)()), c3->getHeaderIdentifier(0));
704        EXPECT_EQ(typeid(int(*)()), c4->getHeaderIdentifier(0));
705        EXPECT_EQ(typeid(int(*)()), c5->getHeaderIdentifier(0));
706        EXPECT_EQ(typeid(int(*)()), c6->getHeaderIdentifier(0));
707        EXPECT_EQ(typeid(int(*)()), c7->getHeaderIdentifier(0));
708        EXPECT_EQ(typeid(int(*)()), c8->getHeaderIdentifier(0));
709    }
710
711    TEST_F(FunctorTest, CanCallFunctorWithLambdaWichIsAlreadyOutOfScope)
712    {
713        int var1 = 1;
714        FunctorPtr fp1a = createFunctor([&var1] () { return var1++; });
715        FunctorPtr fp1b = createFunctor([&var1] () { return var1; });
716        FunctorPtr fp2;
717        FunctorPtr fp3;
718
719        {
720            int var2 = 2;
721            fp2 = createFunctor([var2] () { return var2; });
722        }
723        {
724            int var3 = 3;
725            fp3 = createFunctor([var3] () { return var3; });
726        }
727
728        EXPECT_EQ(1, var1);
729        EXPECT_EQ(1, (*fp1a)().get<int>());
730        EXPECT_EQ(2, var1);
731        EXPECT_EQ(2, (*fp1b)().get<int>());
732
733        EXPECT_EQ(2, (*fp2)().get<int>());
734        EXPECT_EQ(3, (*fp3)().get<int>());
735    }
736
737    TEST_F(FunctorTest, canCompareHeaderIdentifiers)
738    {
739        FunctorPtr fp1 = createFunctor(&f1);
740        FunctorPtr fp2 = createFunctor(&f2);
741        FunctorPtr fp3 = createFunctor(&f3);
742        ASSERT_STREQ(fp1->getHeaderIdentifier(1).name(), fp2->getHeaderIdentifier(1).name());
743        ASSERT_STREQ(fp1->getHeaderIdentifier(2).name(), fp2->getHeaderIdentifier(2).name());
744        ASSERT_STRNE(fp1->getHeaderIdentifier(1).name(), fp2->getHeaderIdentifier(2).name());
745        ASSERT_STRNE(fp1->getHeaderIdentifier(10).name(), fp2->getHeaderIdentifier(10).name());
746        ASSERT_STRNE(fp2->getHeaderIdentifier(2).name(), fp3->getHeaderIdentifier(2).name());
747        ASSERT_STRNE(fp1->getHeaderIdentifier().name(), fp2->getHeaderIdentifier().name());
748        ASSERT_STRNE(fp2->getHeaderIdentifier().name(), fp3->getHeaderIdentifier().name());
749    }
750
751    TEST_F(FunctorTest, canCompareTypenames)
752    {
753        FunctorPtr fp1 = createFunctor(&f1);
754        FunctorPtr fp2 = createFunctor(&f2);
755        FunctorPtr fp3 = createFunctor(&f3);
756        ASSERT_EQ(fp1->getTypenameReturnvalue(), fp2->getTypenameReturnvalue());
757        ASSERT_EQ(fp1->getTypenameParam(0), fp3->getTypenameParam(0));
758        ASSERT_EQ("void", fp1->getTypenameReturnvalue());
759        ASSERT_EQ("int", fp3->getTypenameReturnvalue());
760        ASSERT_EQ("int", fp2->getTypenameParam(0));
761        ASSERT_EQ("double", fp3->getTypenameParam(2));
762        ASSERT_EQ("", fp3->getTypenameParam(6));
763    }
764
765    TEST_F(FunctorTest, testGetParamCountAndHasReturnValue)
766    {
767        FunctorPtr fp1 = createFunctor(&f1);
768        FunctorPtr fp2 = createFunctor(&f2);
769        FunctorPtr fp3 = createFunctor(&f3);
770        ASSERT_EQ(3, fp2->getParamCount());
771        ASSERT_NE(fp1->getParamCount(), fp3->getParamCount());
772        ASSERT_FALSE(fp2->hasReturnvalue());
773        ASSERT_TRUE(fp3->hasReturnvalue());
774    }
775
776    TEST_F(FunctorTest, canEvaluateArgument)
777    {
778        FunctorPtr fp1 = createFunctor(&f1);
779        MultiType mttype = "2";
780        fp1->evaluateArgument(0, mttype);
781        ASSERT_TRUE(mttype.isType<int>());
782        ASSERT_EQ(2, mttype.get<int>());
783        fp1->evaluateArgument(1, mttype);
784        ASSERT_TRUE(mttype.isType<double>());
785        ASSERT_EQ(2.0, mttype.get<double>());
786        mttype.reset();
787        fp1->evaluateArgument(5, mttype);
788        ASSERT_TRUE(mttype.null());
789    }
790
791    TEST_F(FunctorTest, canUseCallables)
792    {
793        int a = 0;
794        FunctorPtr fp1 = createFunctor(CallableStruct{});
795        FunctorPtr fp2 = createFunctor([](bool val) { return val; });
796        FunctorPtr fp3 = createFunctor([&a]() {return a++; });
797        FunctorPtr fp4 = createFunctor([a]() {return a; });
798        ASSERT_EQ(1, (*fp1)().get<int>());
799        ASSERT_EQ(true, (*fp2)(true).get<bool>());
800        ASSERT_EQ(0, (*fp3)().get<int>());
801        ASSERT_EQ(1, a);
802        ASSERT_EQ(0, (*fp4)().get<int>());
803        ASSERT_STREQ(fp1->getHeaderIdentifier().name(), fp3->getHeaderIdentifier().name());
804    }
805
806    TEST_F(FunctorTest, SafeModeWorks)
807    {
808        DestroyableClass* testclass = new DestroyableClass();
809        DestroyableClass* testclass2 = new DestroyableClass();
810        FunctorPtr fp1 = createFunctor(&DestroyableClass::method0, testclass);
811        fp1->setSafeMode(true);
812        FunctorPtr fp2 = createFunctor(&DestroyableClass::method0, testclass);
813        fp2->setSafeMode(true);
814        FunctorPtr fp3 = createFunctor(&DestroyableClass::method0, testclass);
815        fp2->setRawObjectPointer(testclass2);
816
817        ASSERT_NE(nullptr, fp1->getRawObjectPointer());
818        ASSERT_NE(nullptr, fp2->getRawObjectPointer());
819        ASSERT_NE(nullptr, fp3->getRawObjectPointer());
820        testclass->destroy();
821        ASSERT_EQ(nullptr, fp1->getRawObjectPointer());
822        ASSERT_NE(nullptr, fp2->getRawObjectPointer());
823        ASSERT_NE(nullptr, fp3->getRawObjectPointer());
824
825        fp3->setRawObjectPointer(testclass2);
826        fp3->setSafeMode(true);
827        fp2->setSafeMode(false);
828        testclass2->destroy();
829        ASSERT_NE(nullptr, fp2->getRawObjectPointer());
830        ASSERT_EQ(nullptr, fp3->getRawObjectPointer());
831    }
832}
Note: See TracBrowser for help on using the repository browser.