├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── access_function.cpp ├── access_member.cpp ├── multiple_instances.cpp └── no_macro.cpp ├── include └── accessor │ └── accessor.hpp └── tests ├── accessMemberTestSuite.cpp ├── callFunctionTestSuite.cpp ├── functionWrapperTestSuite.cpp ├── memberWrapperTestSuite.cpp └── test_helper.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | project(Accessor LANGUAGES CXX) 3 | 4 | include(GNUInstallDirs) 5 | 6 | set(library_name accessor) 7 | add_library(${library_name} INTERFACE) 8 | target_include_directories(${library_name} INTERFACE 9 | $ 10 | $) 11 | 12 | install(TARGETS accessor EXPORT ${library_name}Config 13 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 14 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 15 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # For Windows 16 | 17 | install(DIRECTORY include/ 18 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 19 | FILES_MATCHING PATTERN "*.hpp*") 20 | 21 | install(EXPORT ${library_name}Config DESTINATION share/${library_name}/cmake) 22 | 23 | export(TARGETS accessor FILE ${library_name}Config.cmake) 24 | 25 | #EXAMPLES 26 | if(${EXAMPLES}) 27 | set (CMAKE_CXX_STANDARD 14) 28 | 29 | add_executable(accessFunctions examples/access_function.cpp) 30 | target_link_libraries(accessFunctions accessor) 31 | 32 | add_executable(accessMembers examples/access_member.cpp) 33 | target_link_libraries(accessMembers accessor) 34 | 35 | add_executable(accessColletion examples/multiple_instances.cpp) 36 | target_link_libraries(accessColletion accessor) 37 | 38 | add_executable(accessNoMacro examples/no_macro.cpp) 39 | target_link_libraries(accessNoMacro accessor) 40 | endif() 41 | 42 | #TESTS 43 | enable_testing() 44 | add_executable(functionWrapperTestSuite tests/functionWrapperTestSuite.cpp) 45 | target_link_libraries(functionWrapperTestSuite accessor) 46 | 47 | add_executable(memberWrapperTestSuite tests/memberWrapperTestSuite.cpp) 48 | target_link_libraries(memberWrapperTestSuite accessor) 49 | 50 | add_executable(callFunctionTestSuite tests/callFunctionTestSuite.cpp) 51 | target_link_libraries(callFunctionTestSuite accessor) 52 | 53 | add_executable(accessMemberTestSuite tests/accessMemberTestSuite.cpp) 54 | target_link_libraries(accessMemberTestSuite accessor) 55 | 56 | add_test(functionWrapperTests functionWrapperTestSuite) 57 | add_test(memberWrapperTests memberWrapperTestSuite) 58 | add_test(callFunctionTest callFunctionTestSuite) 59 | add_test(accessMemberTest accessMemberTestSuite) 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Hubert Liberacki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Accessor 3 | Header only, fully template based library which enables accessing private data members. Techniques used by this library to achieve its purpose are fully legal and allowed by the standard. 4 | The library is based on __Explicit instantiation__ of __class template instantion__. 5 | 6 | >Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private. 7 | 8 | _source: https://en.cppreference.com/w/cpp/language/class_template_ 9 | 10 | The article describing implementation of this technique can be find [Here](https://github.com/insooth/insooth.github.io/blob/master/accessing-private-members.md) 11 | 12 | First reference to this technique is in [Johannes Schaub - litb blog](http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html?m=1) 13 | 14 | Herb Sutter [GotW blog post](http://www.gotw.ca/gotw/076.htm) why in general you should not access private members. Be wise and don't try to break things if you don't have to! 15 | 16 | ## Motivation 17 | 18 | This library is not meant to break any C++ design rules, even though it's fully legal from standard point of view. The purpose of this library is to use it when necessary within tests. Code shall be written in the way that it can be later tested, but as we all know in most cases and it especially applies to legacy code, there are situations where one need to access private member and no mocking can be applied anymore. 19 | 20 | In situations like that provided technique is far better than common `#define private public`, using `friend` keyword or even flag `no-access-control` for gcc. 21 | 22 | ## Installation 23 | 24 | Installation is done using CMake 25 | ```sh 26 | mkdir build 27 | cd build 28 | cmake .. 29 | make && make install 30 | ``` 31 | 32 | ## Importing Accessor as a target 33 | 34 | Installed Accessor library can be easily imported by any CMake based project 35 | ```cmake 36 | find_package(accessor REQUIRED) 37 | # ... 38 | target_link_libraries(${exec_name} accessor) 39 | ``` 40 | 41 | ## Building examples 42 | 43 | There is set of mini [examples](https://github.com/hliberacki/cpp-member-accessor/tree/master/examples), which shows how various data members and methods can be accessed. To build them, the additional CMake flag shall be passed. 44 | 45 | ```sh 46 | cmake -DEXAMPLES=1 .. 47 | make 48 | ``` 49 | 50 | ## Running tests 51 | 52 | There is set of [tests](https://github.com/hliberacki/cpp-member-accessor/tree/master/tests) using only CMake [CTest](https://cmake.org/cmake/help/v3.0/manual/ctest.1.html). 53 | 54 | ```sh 55 | make test 56 | ``` 57 | ## Usage 58 | 59 | Full set of examples is avaiable [here](https://github.com/hliberacki/cpp-member-accessor/tree/master/examples). Below there is only quick _getting started_ section 60 | 61 | There are two ways of using this library, first is using straight library API and the second is by calling Macro which calls library API. 62 | Both ways will be presented, choose which one is better for you, yet both will use the same test class to access its data. 63 | 64 | ```cpp 65 | class Test 66 | { 67 | void foo() { std::cout << "private method: Foo" << '\n'; } 68 | 69 | int getSum(int first, int second ) const { return first + second; } 70 | 71 | template 72 | T max(T& lhs, T& rhs) { return (lhs > rhs) ? lhs : rhs; } 73 | 74 | int mFooBar {1}; 75 | }; 76 | ``` 77 | 78 | ### Macroless 79 | 80 | The first step for accessing private data, is to create own type or an alias which will be further passed for accessing functions. 81 | 82 | ```cpp 83 | struct TestFoo : ::accessor::FunctionWrapper {}; 84 | struct TestFooBar : ::accessor::MemberWrapper {}; 85 | ``` 86 | Or 87 | ```cpp 88 | using TestFoo = ::accessor::FunctionWrapper; 89 | using TestFooBar = ::accessor::MemberWrapper; 90 | ``` 91 | 92 | Accessing multiple members with the same type is only possible with the definition of a struct. 93 | `FunctionWrapper` takes types `` 94 | `MemberWrapper` works similar to `FunctionWrapper` it takes types `` 95 | 96 | Then __explicit template instantantion__ of created type `TestFoo` and `TestFooBar` shall be used 97 | 98 | ```cpp 99 | using TestFoo = ::accessor::FunctionWrapper; 100 | template class ::accessor::MakeProxy; 101 | 102 | using TestFooBar = ::accessor::MemberWrapper; 103 | template class ::accessor::MakeProxy; 104 | ``` 105 | 106 | `MakeProxy` takes as parameters `` 107 | 108 | After those steps we can simply call private `foo` method of class `Test` 109 | 110 | ```cpp 111 | Test t; 112 | ::accessor::callFunction(t); 113 | auto ref = ::accessor::accessMember(t); \\ return std::ref(Test::mFooBar) 114 | ``` 115 | 116 | `callFunction` takes any `Test` object which has `Test::foo` method to call, and variadic arguments needed for that method. 117 | `accessMember` works as `callFunction` yet it return `std::ref` to private data member of class `Test` 118 | 119 | Examples of instantion and calling for rest of Test class methods. 120 | 121 | ```cpp 122 | using TestGetSum = ::accessor::ConstFunctionWrapper; 123 | template class ::accessor::MakeProxy; 124 | 125 | template 126 | using TestMax = ::accessor::FunctionWrapper; 127 | template class ::accessor::MakeProxy, &Test::max>; 128 | template class ::accessor::MakeProxy, &Test::max>; 129 | 130 | .... 131 | 132 | int main() 133 | { 134 | int result = ::accessor::callFunction(t, 1, 1); 135 | result = ::accessor::callFunction>(t, 10, 20); 136 | uint32_t res = ::accessor::callFunction>(t, 100u, 200u); 137 | return 0; 138 | } 139 | ``` 140 | 141 | ### With Macros 142 | 143 | If you are not happy with the need of explicitly calling template instantiation, then there are also macros which does it for you 144 | 145 | ```cpp 146 | FUNCTION_ACCESSOR(TestFoo, Test, foo, void) // Test::foo 147 | CONST_FUNCTION_ACCESSOR(TestSum, Test, getSum, int, int, int) //Test::getSum 148 | FUNCTION_ACCESSOR(TestMaxInt, Test, max, int, int&, int&) //Test::max 149 | FUNCTION_ACCESSOR(TestMaxUInt, Test, max, uint32_t, uint32_t&, uint32_t&) //Test::max 150 | MEMBER_ACCESSOR(TestFooBar, Test, mFooBar, int) // Test::mFooBar 151 | ``` 152 | 153 | Below is what those Macros shall be satisfied with 154 | 155 | ```cpp 156 | FUNCTION_ACCESSOR(TypeForAccessing, BaseClass, nameOfMemberToAccess, returnType, functionArgumentTypes...) 157 | CONST_FUNCTION_ACCESSOR(TypeForAccessing, BaseClass, nameOfMemberToAccess, returnType, functionArgumentTypes...) 158 | MEMBER_ACCESSOR(TypeForAccessing, BaseClass, nameOfMemberToAccess, MemberType) 159 | ``` 160 | 161 | The rest is done the very same way as it was done without macros, using `callFunction` and `accessMember` 162 | 163 | Full code 164 | 165 | ```cpp 166 | FUNCTION_ACCESSOR(TestFoo, Test, foo, void) // Test::foo 167 | CONST_FUNCTION_ACCESSOR(TestSum, Test, getSum, int, int, int) //Test::getSum 168 | FUNCTION_ACCESSOR(TestMaxInt, Test, max, int, int&, int&) //Test::max 169 | FUNCTION_ACCESSOR(TestMaxUInt, Test, max, uint32_t, uint32_t&, uint32_t&) //Test::max 170 | MEMBER_ACCESSOR(TestFooBar, Test, mFooBar, int) // Test::mFooBar 171 | 172 | int main() 173 | { 174 | accessor::callFunction(t); //Test::foo 175 | int result = ::accessor::callFunction(t, 1, 1); //Test::getSum 176 | result = ::accessor::callFunction>(t, 10, 20); //Test::max 177 | uint32_t res = ::accessor::callFunction>(t, 100u, 200u); //Test::max 178 | 179 | auto ref = accessor::accessMember(t); //Test::mFoobar 180 | ref.get() = 200; //change mFooBar value; 181 | return 0; 182 | } 183 | ``` 184 | 185 | ## License 186 | 187 | [MIT License](https://github.com/hliberacki/cpp-member-accessor/blob/master/LICENSE) 188 | -------------------------------------------------------------------------------- /examples/access_function.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "accessor/accessor.hpp" 3 | #include 4 | 5 | class Test 6 | { 7 | void foo() { std::cout << "private method: Foo" << '\n'; } 8 | 9 | void bar(int i, double d) 10 | { 11 | std::cout << "private method: Bar. Args:[" << i << ", " << d << "]"<< '\n'; 12 | } 13 | 14 | int getSum(int first, int second ) const { return first + second; } 15 | 16 | template 17 | T max(T& lhs, T& rhs) { return (lhs > rhs) ? lhs : rhs; } 18 | }; 19 | 20 | FUNCTION_ACCESSOR(TestFoo, Test, foo, void) 21 | FUNCTION_ACCESSOR(TestBar, Test, bar, void, int, double) 22 | CONST_FUNCTION_ACCESSOR(TestSum, Test, getSum, int, int, int) 23 | 24 | FUNCTION_ACCESSOR(TestMaxInt, Test, max, int, int&, int&) 25 | FUNCTION_ACCESSOR(TestMaxFloat, Test, max, float, float&, float&) 26 | 27 | int main() 28 | { 29 | Test t; 30 | 31 | std::cout << "\nfoo() : "; 32 | accessor::callFunction(t); 33 | 34 | std::cout << "\nbar(20, 30) : "; 35 | accessor::callFunction(t, 20, 30); 36 | 37 | std::cout << "\ngetSum(20, 30) : "; 38 | auto result = accessor::callFunction(t, 20, 30); 39 | std::cout << "sum output: " << result << '\n'; 40 | 41 | std::cout << "\nmax(20, 30) : "; 42 | auto maxInt = accessor::callFunction(t, 20, 30); 43 | std::cout << maxInt << '\n'; 44 | 45 | std::cout << "\nmax(0.7f, 0.5f): "; 46 | auto maxFloat = accessor::callFunction(t, 0.7f, 0.5f); 47 | std::cout << maxFloat << '\n'; 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /examples/access_member.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "accessor/accessor.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | struct Dummy 8 | { 9 | int mVal {0}; 10 | }; 11 | 12 | class Test 13 | { 14 | int mFoo {1}; 15 | int mFoo2 {2}; 16 | std::string mBar {"Hello World"}; 17 | Dummy mFooBar; 18 | std::vector mVec; 19 | }; 20 | 21 | MEMBER_ACCESSOR(TestFoo, Test, mFoo, int) 22 | MEMBER_ACCESSOR(TestFoo2, Test, mFoo2, int) 23 | MEMBER_ACCESSOR(TestBar, Test, mBar, std::string) 24 | MEMBER_ACCESSOR(TestFooBar, Test, mFooBar, Dummy) 25 | MEMBER_ACCESSOR(TestVec, Test, mVec, std::vector) 26 | 27 | int main() 28 | { 29 | Test t; 30 | 31 | std::cout << "\nmFoo : " 32 | << accessor::accessMember(t) << '\n'; 33 | 34 | std::cout << "\nChanging mFoo to : " << 2000 << '\n'; 35 | auto foobar = accessor::accessMember(t); 36 | foobar.get() = 2000; 37 | 38 | std::cout << "\nmFoo : " 39 | << accessor::accessMember(t) << '\n'; 40 | 41 | std::cout << "\nmFoo2 : " 42 | << accessor::accessMember(t) << '\n'; 43 | 44 | std::cout << "\nmBar : " 45 | << accessor::accessMember(t).get() << '\n'; 46 | 47 | std::cout << "\nmFooBar : " 48 | << accessor::accessMember(t).get().mVal << '\n'; 49 | 50 | std::cout << "\nmVec size: " << accessor::accessMember(t).get().size() 51 | << " emplacing elements {0,1,2,3,4,5,6,7,8,9}" << '\n'; 52 | 53 | for(int i = 0; i < 10 ; ++i) 54 | { 55 | accessor::accessMember(t).get().emplace_back(i); 56 | } 57 | 58 | std::cout << "\nmVec size: " << accessor::accessMember(t).get().size() 59 | << " elements: { "; 60 | 61 | for(auto item : accessor::accessMember(t).get()) 62 | { 63 | std::cout << item << " "; 64 | } 65 | 66 | std::cout << "}\n"; 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /examples/multiple_instances.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "accessor/accessor.hpp" 3 | #include 4 | #include 5 | 6 | class Test 7 | { 8 | public: 9 | Test() = default; 10 | Test(int i) : mBar{i} {} 11 | 12 | private: 13 | void foo() { std::cout << "private method: Foo" << '\n'; } 14 | int mBar {1}; 15 | }; 16 | 17 | FUNCTION_ACCESSOR(TestFooView, Test, foo, void) 18 | MEMBER_ACCESSOR(TestBarView, Test, mBar, int) 19 | 20 | int main() 21 | { 22 | std::vector collection; 23 | 24 | for(int i = 0; i < 5; ++i) 25 | { 26 | collection.emplace_back(i); 27 | } 28 | 29 | std::cout << "Applying the same accessors on each elemet of vector container" << '\n'; 30 | 31 | for(auto item : collection) 32 | { 33 | std::cout << "\n################################" << '\n'; 34 | accessor::callFunction(item); 35 | std::cout << "mBar: " << accessor::accessMember(item).get() << '\n'; 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/no_macro.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "accessor/accessor.hpp" 3 | #include 4 | 5 | class Test 6 | { 7 | void foo() { std::cout << "private method: Foo" << '\n'; } 8 | 9 | void bar(int i, double d) 10 | { 11 | std::cout << "private method: Bar. Args:[" << i << ", " << d << "]"<< '\n'; 12 | } 13 | 14 | int getSum(int first, int second ) const { return first + second; } 15 | 16 | template 17 | T max(T& lhs, T& rhs) { return (lhs > rhs) ? lhs : rhs; } 18 | 19 | int mFooBar {1}; 20 | }; 21 | 22 | using TestFoo = accessor::FunctionWrapper; 23 | using TestBar = accessor::FunctionWrapper; 24 | using TestSum = accessor::ConstFunctionWrapper; 25 | using TestMaxInt = accessor::FunctionWrapper; 26 | using TestMaxFloat = accessor::FunctionWrapper; 27 | 28 | template 29 | using TestMax = accessor::FunctionWrapper; 30 | 31 | using TestFooBar = accessor::MemberWrapper; 32 | 33 | template class accessor::MakeProxy; 34 | template class accessor::MakeProxy; 35 | template class accessor::MakeProxy; 36 | template class accessor::MakeProxy; 37 | template class accessor::MakeProxy; 38 | template class accessor::MakeProxy, &Test::max>; 39 | template class accessor::MakeProxy; 40 | 41 | int main() 42 | { 43 | Test t; 44 | 45 | std::cout << "\nfoo() : "; 46 | accessor::callFunction(t); 47 | 48 | std::cout << "\nbar(20, 30) : "; 49 | accessor::callFunction(t, 20, 30); 50 | 51 | std::cout << "\ngetSum(20, 30) : "; 52 | auto result = accessor::callFunction(t, 20, 30); 53 | std::cout << "sum output: " << result << '\n'; 54 | 55 | std::cout << "\nmax(20, 30) : "; 56 | auto maxInt = accessor::callFunction(t, 20, 30); 57 | std::cout << maxInt << '\n'; 58 | 59 | std::cout << "\nmax(0.7f, 0.5f) : "; 60 | auto maxFloat = accessor::callFunction(t, 0.7f, 0.5f); 61 | std::cout << maxFloat << '\n'; 62 | 63 | std::cout << "\nmax(0.37, 0.56): "; 64 | auto maxDouble = accessor::callFunction>(t, 0.37, 0.56); 65 | std::cout << maxDouble << '\n'; 66 | 67 | std::cout << "\nmFooBar : " << accessor::accessMember(t) 68 | << '\n'; 69 | auto fooBar = accessor::accessMember(t); 70 | fooBar.get() *= 2; 71 | 72 | std::cout << "\nMultiply mFooBar by 2" << '\n'; 73 | std::cout << "mFooBar : " << accessor::accessMember(t) 74 | << '\n'; 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /include/accessor/accessor.hpp: -------------------------------------------------------------------------------- 1 | //************************************************************************************ 2 | // Copyright Hubert Liberacki (hliberacki@gmail.com) 3 | // Copyright Krzysztof Ostrowski 4 | // 5 | // Project home: https://github.com/hliberacki/cpp-member-accessor 6 | // 7 | // MIT LICENSE : https://github.com/hliberacki/cpp-member-accessor/blob/master/LICENSE 8 | //************************************************************************************ 9 | 10 | #ifndef ACCESSOR_INCLUDE_ACCESSOR_HPP 11 | #define ACCESSOR_INCLUDE_ACCESSOR_HPP 12 | 13 | #include 14 | 15 | namespace accessor 16 | { 17 | template 18 | struct MemberWrapper 19 | { 20 | using type = T (C::*); 21 | }; 22 | 23 | template 24 | struct FunctionWrapper 25 | { 26 | using type = R (C::*)(Args...); 27 | }; 28 | 29 | template 30 | struct ConstFunctionWrapper 31 | { 32 | using type = R (C::*)(Args...) const; 33 | }; 34 | 35 | template 36 | struct Proxy 37 | { 38 | static typename T::type value; 39 | }; 40 | 41 | template 42 | typename T::type Proxy::value; 43 | 44 | template 45 | class MakeProxy 46 | { 47 | struct Setter { Setter() { Proxy::value = AccessPointer; } }; 48 | static Setter instance; 49 | }; 50 | 51 | template 52 | typename MakeProxy::Setter MakeProxy::instance; 53 | 54 | template 55 | auto callFunction(Instance & instance, Args ...args) 56 | { 57 | return (instance.*(Proxy::value))(args...); 58 | } 59 | 60 | template 61 | auto accessMember(Instance & instance) 62 | { 63 | return std::ref(instance.*(Proxy::value)); 64 | } 65 | } 66 | 67 | #define FUNCTION_HELPER(...) \ 68 | accessor::FunctionWrapper<__VA_ARGS__> 69 | 70 | #define CONST_FUNCTION_HELPER(...) \ 71 | accessor::ConstFunctionWrapper<__VA_ARGS__> 72 | 73 | #define FUNCTION_ACCESSOR(accessor_name, base, method, ...) \ 74 | struct accessor_name : FUNCTION_HELPER(base, __VA_ARGS__) {}; \ 75 | template class accessor::MakeProxy; 76 | 77 | #define CONST_FUNCTION_ACCESSOR(accessor_name, base, method, ...) \ 78 | struct accessor_name : CONST_FUNCTION_HELPER(base, __VA_ARGS__) {}; \ 79 | template class accessor::MakeProxy; 80 | 81 | #define MEMBER_ACCESSOR(accessor_name, base, member, ret_type) \ 82 | struct accessor_name : accessor::MemberWrapper {}; \ 83 | template class accessor::MakeProxy; 84 | 85 | #endif // ACCESSOR_INCLUDE_ACCESSOR_HPP 86 | -------------------------------------------------------------------------------- /tests/accessMemberTestSuite.cpp: -------------------------------------------------------------------------------- 1 | #include "test_helper.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | class Test 7 | { 8 | public: 9 | Test() = default; 10 | Test(std::vector data, std::vector data2) : 11 | mFooBar{data}, mFooBar2 {data2} {} 12 | 13 | private: 14 | int mFoo {0}; 15 | int mFoo2 {1}; 16 | std::vector mFooBar; 17 | std::vector mFooBar2; 18 | }; 19 | 20 | 21 | struct TestFoo : ::accessor::MemberWrapper {}; 22 | template class ::accessor::MakeProxy; 23 | 24 | struct TestFoo2 : ::accessor::MemberWrapper {}; 25 | template class ::accessor::MakeProxy; 26 | 27 | bool accessSimpleMember() 28 | { 29 | Test t; 30 | 31 | return (::accessor::accessMember(t) == 0) 32 | && (::accessor::accessMember(t) == 1); 33 | } 34 | 35 | bool changeValueOfSimpleMember() 36 | { 37 | Test t; 38 | 39 | ::accessor::accessMember(t).get() = 100; 40 | ::accessor::accessMember(t).get() = 101; 41 | return (::accessor::accessMember(t) == 100) 42 | && (::accessor::accessMember(t) == 101); 43 | } 44 | 45 | struct TestFooBar : ::accessor::MemberWrapper> {}; 46 | template class ::accessor::MakeProxy; 47 | 48 | struct TestFooBar2 : ::accessor::MemberWrapper> {}; 49 | template class ::accessor::MakeProxy; 50 | 51 | bool accessContainerType() 52 | { 53 | std::vector testData = {0, 1, 2, 4, 5, 6, 7, 8, 9}; 54 | std::vector testData2 = {10, 11, 12, 14, 15, 16, 17, 18, 19}; 55 | Test t(testData, testData2); 56 | 57 | bool testResult = true; 58 | 59 | for (uint8_t i = 0; i < testData.size(); ++i) 60 | { 61 | testResult = testResult && (testData[i] == ::accessor::accessMember(t).get()[i]); 62 | } 63 | for (uint8_t i = 0; i < testData2.size(); ++i) 64 | { 65 | testResult = testResult && (testData2[i] == ::accessor::accessMember(t).get()[i]); 66 | } 67 | 68 | return testResult; 69 | } 70 | 71 | bool emplaceElementsToContainer() 72 | { 73 | Test t; 74 | std::vector testData = {0, 1, 2, 4, 5, 6, 7, 8, 9}; 75 | std::vector testData2 = {10, 11, 12, 14, 15, 16, 17, 18, 19}; 76 | 77 | auto refFooBar = ::accessor::accessMember(t); 78 | for (auto item: testData) 79 | { 80 | refFooBar.get().emplace_back(item); 81 | } 82 | 83 | auto refFooBar2 = ::accessor::accessMember(t); 84 | for (auto item: testData2) 85 | { 86 | refFooBar2.get().emplace_back(item); 87 | } 88 | 89 | bool testResult = true; 90 | 91 | for (uint8_t i = 0; i < testData.size(); ++i) 92 | { 93 | testResult = testResult && (testData[i] == ::accessor::accessMember(t).get()[i]); 94 | } 95 | for (uint8_t i = 0; i < testData2.size(); ++i) 96 | { 97 | testResult = testResult && (testData2[i] == ::accessor::accessMember(t).get()[i]); 98 | } 99 | 100 | return testResult; 101 | } 102 | 103 | int main() 104 | { 105 | ::testHelper::validateTest(accessSimpleMember()); 106 | ::testHelper::validateTest(changeValueOfSimpleMember()); 107 | ::testHelper::validateTest(accessContainerType()); 108 | ::testHelper::validateTest(emplaceElementsToContainer()); 109 | 110 | return ::testHelper::failedTests(); 111 | } 112 | 113 | -------------------------------------------------------------------------------- /tests/callFunctionTestSuite.cpp: -------------------------------------------------------------------------------- 1 | #include "test_helper.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Test 10 | { 11 | public: 12 | Test() 13 | { 14 | mVisitedMethods.emplace("foo", 0); 15 | mVisitedMethods.emplace("getSum", 0); 16 | mVisitedMethods.emplace("max", 0); 17 | } 18 | 19 | int getMethodVisitedCounter(std::string methodName) 20 | { 21 | auto found = mVisitedMethods.find(methodName); 22 | return (found != std::end(mVisitedMethods)) ? found->second : -1; 23 | } 24 | 25 | private: 26 | void incrementMethodVisitedCounter(std::string methodName) 27 | { 28 | auto found = mVisitedMethods.find(methodName); 29 | if (found != std::end(mVisitedMethods)) 30 | ++found->second; 31 | } 32 | 33 | void foo() { incrementMethodVisitedCounter("foo"); } 34 | 35 | int getSum(int first, int second ) 36 | { 37 | incrementMethodVisitedCounter("getSum"); 38 | return first + second; 39 | } 40 | 41 | template 42 | T max(T& lhs, T& rhs) 43 | { 44 | incrementMethodVisitedCounter("max"); 45 | return (lhs > rhs) ? lhs : rhs; 46 | } 47 | 48 | std::map mVisitedMethods; 49 | }; 50 | 51 | 52 | using TestFoo = ::accessor::FunctionWrapper; 53 | template class ::accessor::MakeProxy; 54 | 55 | bool callOnceSimpleFoo() 56 | { 57 | Test t; 58 | ::accessor::callFunction(t); 59 | return (t.getMethodVisitedCounter("foo") == 1); 60 | } 61 | 62 | bool callMultipleSimpleFoo() 63 | { 64 | Test t; 65 | int callsNumber = 10; 66 | 67 | for (int i = 0; i < callsNumber; ++i ) 68 | { 69 | ::accessor::callFunction(t); 70 | } 71 | 72 | return (t.getMethodVisitedCounter("foo") == 10); 73 | } 74 | 75 | using TestGetSum = ::accessor::FunctionWrapper; 76 | template class ::accessor::MakeProxy; 77 | 78 | bool callOnceGetSum() 79 | { 80 | Test t; 81 | 82 | return (::accessor::callFunction(t, 1, 1) == 2) && 83 | (t.getMethodVisitedCounter("getSum") > 0); 84 | } 85 | 86 | bool callMultipleGetSum() 87 | { 88 | Test t; 89 | int callsNumber = 10; 90 | bool testResult = false; 91 | 92 | for (int i = 0; i < callsNumber; ++i) 93 | { 94 | int expectedSum = i + callsNumber; 95 | testResult = (::accessor::callFunction(t, i, callsNumber) == expectedSum) && 96 | (t.getMethodVisitedCounter("getSum") > i); 97 | } 98 | 99 | return testResult; 100 | } 101 | 102 | template 103 | using TestMax = ::accessor::FunctionWrapper; 104 | template class ::accessor::MakeProxy, &Test::max>; 105 | template class ::accessor::MakeProxy, &Test::max>; 106 | 107 | bool calOnceTemplatedMax() 108 | { 109 | Test t; 110 | bool testResult = false; 111 | 112 | { 113 | testResult = (::accessor::callFunction>(t, 10, 20) == 20) && 114 | (t.getMethodVisitedCounter("max") > 0); 115 | } 116 | 117 | { 118 | testResult = (::accessor::callFunction>(t, 100u, 200u) == 200u) && 119 | (t.getMethodVisitedCounter("max") > 1); 120 | } 121 | 122 | return testResult; 123 | } 124 | 125 | 126 | bool calMultipleTemplatedMax() 127 | { 128 | Test t; 129 | int callsNumber = 10; 130 | bool testResult = false; 131 | 132 | for (int i = 0; i < callsNumber; ++i) 133 | { 134 | auto maxRes = ::accessor::callFunction>(t, i, callsNumber - i); 135 | testResult = (maxRes == std::max(i, callsNumber - i)) && 136 | (t.getMethodVisitedCounter("max") > i); 137 | } 138 | 139 | return testResult; 140 | } 141 | 142 | int main() 143 | { 144 | ::testHelper::validateTest(callOnceSimpleFoo()); 145 | ::testHelper::validateTest(callMultipleSimpleFoo()); 146 | ::testHelper::validateTest(callOnceGetSum()); 147 | ::testHelper::validateTest(callMultipleGetSum()); 148 | ::testHelper::validateTest(calOnceTemplatedMax()); 149 | ::testHelper::validateTest(calMultipleTemplatedMax()); 150 | 151 | return ::testHelper::failedTests(); 152 | } 153 | -------------------------------------------------------------------------------- /tests/functionWrapperTestSuite.cpp: -------------------------------------------------------------------------------- 1 | #include "test_helper.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | class Test 7 | { 8 | void foo() {} 9 | int bar(int, float) {} 10 | int & foobar(int&, float&, std::vector, int*) {} 11 | 12 | template 13 | T generic(T, Args...) {} 14 | 15 | void cfoo() const {} 16 | }; 17 | 18 | bool checkSignatureBasic() 19 | { 20 | using fooSig = void(Test::*)(); 21 | return std::is_same::type>::value; 22 | } 23 | 24 | bool checkFunctionSignature() 25 | { 26 | bool testResult = false; 27 | 28 | { 29 | using barSig = int(Test::*)(int, float); 30 | testResult = std::is_same::type>::value; 32 | } 33 | 34 | { 35 | using foobarSig = int&(Test::*)(int&, float&, std::vector, int*); 36 | testResult = std::is_same, int*>::type>::value; 39 | } 40 | 41 | return testResult; 42 | } 43 | 44 | 45 | template 46 | using genericSigInt = T(Test::*)(Args...); 47 | 48 | bool checkTemplateFunctionSignature() 49 | { 50 | bool testResult = false; 51 | 52 | { 53 | testResult = std::is_same, 54 | ::accessor::FunctionWrapper::type>::value; 55 | } 56 | 57 | { 58 | testResult = std::is_same, 59 | ::accessor::FunctionWrapper::type>::value; 61 | } 62 | 63 | return testResult; 64 | } 65 | 66 | bool checkConstFunctionSignature() 67 | { 68 | using cfooSig = void(Test::*)() const; 69 | return std::is_same::type>::value; 70 | } 71 | 72 | int main() 73 | { 74 | ::testHelper::validateTest(checkSignatureBasic()); 75 | ::testHelper::validateTest(checkFunctionSignature()); 76 | ::testHelper::validateTest(checkTemplateFunctionSignature()); 77 | ::testHelper::validateTest(checkConstFunctionSignature()); 78 | 79 | return ::testHelper::failedTests(); 80 | } 81 | 82 | -------------------------------------------------------------------------------- /tests/memberWrapperTestSuite.cpp: -------------------------------------------------------------------------------- 1 | #include "test_helper.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | class Test 7 | { 8 | int mFoo; 9 | const float mBar; 10 | std::vector mFooBar; 11 | }; 12 | 13 | bool checkSignatureBasic() 14 | { 15 | using fooSig = int(Test::*); 16 | return std::is_same::type>::value; 17 | } 18 | 19 | bool checkConstSignatureBasic() 20 | { 21 | using barSig = const float(Test::*); 22 | return std::is_same::type>::value; 23 | } 24 | 25 | bool checkCollectionSignatureBasic() 26 | { 27 | using foobarSig = std::vector(Test::*); 28 | return std::is_same>::type>::value; 29 | } 30 | 31 | int main() 32 | { 33 | ::testHelper::validateTest(checkSignatureBasic()); 34 | ::testHelper::validateTest(checkConstSignatureBasic()); 35 | ::testHelper::validateTest(checkCollectionSignatureBasic()); 36 | 37 | return ::testHelper::failedTests(); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /tests/test_helper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ACCESSOR_TESTS_TEST_HELPER_HPP 2 | #define ACCESSOR_TESTS_TEST_HELPER_HPP 3 | #include 4 | namespace testHelper 5 | { 6 | inline static int & failedTests() 7 | { 8 | static int testFailed = 0; 9 | return testFailed; 10 | } 11 | 12 | void validateTest(bool expression) 13 | { 14 | if (!expression) 15 | ++failedTests(); 16 | } 17 | } 18 | 19 | #endif // ACCESSOR_TESTS_TEST_HELPER_HPP 20 | 21 | 22 | --------------------------------------------------------------------------------