1 // Copyright 2016 Klemens Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 // For more information, see http://www.boost.org
8 
9 #include <boost/predef.h>
10 
11 #if (__cplusplus >= 201402L) || (BOOST_COMP_MSVC >= BOOST_VERSION_NUMBER(14,0,0))
12 
13 #include "../example/b2_workarounds.hpp"
14 
15 #include <boost/dll/smart_library.hpp>
16 #include <boost/core/lightweight_test.hpp>
17 #include <boost/filesystem.hpp>
18 #include <boost/variant.hpp>
19 
20 #include <iostream>
21 
22 struct override_class
23 {
24     int arr[32];
25 };
26 
27 
main(int argc,char * argv[])28 int main(int argc, char* argv[])
29 {
30     using namespace boost::dll;
31     using namespace boost::dll::experimental;
32     boost::dll::fs::path pt = b2_workarounds::first_lib_from_argv(argc, argv);
33 
34     BOOST_TEST(!pt.empty());
35     std::cout << "Library: " << pt << std::endl;
36     std::cerr << 1 << ' ';
37     smart_library sm(pt);
38 
39     auto& unscoped_var = sm.get_variable<int>("unscoped_var");
40     BOOST_TEST(unscoped_var == 42);
41     std::cerr << 2 << ' ';
42     auto& unscoped_c_var = sm.get_variable<const double>("unscoped_c_var");
43     BOOST_TEST(unscoped_c_var == 1.234);
44 
45     std::cerr << 3 << ' ';
46     auto& sp_variable = sm.get_variable<double>("some_space::variable");
47     BOOST_TEST(sp_variable == 0.2);
48 
49     std::cerr << 4 << ' ';
50     auto scoped_fun = sm.get_function<const int&()>("some_space::scoped_fun");
51     BOOST_TEST(scoped_fun != nullptr);
52     {    std::cerr << 5 << ' ';
53         auto &res = scoped_fun();
54         const int expected = 0xDEADBEEF;
55         BOOST_TEST(res == expected);
56     }
57     std::cerr << 6 << ' ';
58     auto ovl1 = sm.get_function<void(int)>   ("overloaded");
59     auto ovl2 = sm.get_function<void(double)>("overloaded");
60     std::cerr << 7 << ' ';
61     BOOST_TEST(ovl1 != nullptr);
62     BOOST_TEST(ovl2 != nullptr);
63     BOOST_TEST(reinterpret_cast<void*>(ovl1) != reinterpret_cast<void*>(ovl2));
64     std::cerr << 8 << ' ';
65     ovl1(12);
66     BOOST_TEST(unscoped_var == 12);
67     ovl2(5.0);
68     BOOST_TEST(sp_variable == 5.0);
69     std::cerr << 9 << ' ';
70 
71 
72     auto var1 = sm.get_function<void(boost::variant<int, double> &)>("use_variant");
73     auto var2 = sm.get_function<void(boost::variant<double, int> &)>("use_variant");
74     std::cerr << 10 << ' ';
75     BOOST_TEST(var1 != nullptr);
76     BOOST_TEST(var2 != nullptr);
77     BOOST_TEST(reinterpret_cast<void*>(var1) != reinterpret_cast<void*>(var2));
78 
79     {
80          boost::variant<int, double> v1 = 232.22;
81          boost::variant<double, int> v2 = -1;
82     std::cerr << 11 << ' ';
83          var1(v1);
84          var2(v2);
85 
86          struct : boost::static_visitor<void>
87          {
88              void operator()(double) {BOOST_TEST(false);}
89              void operator()(int i) {BOOST_TEST(i == 42);}
90          } vis1;
91 
92          struct : boost::static_visitor<void>
93          {
94              void operator()(double d) {BOOST_TEST(d == 3.124);}
95              void operator()(int ) {BOOST_TEST(false);}
96          } vis2;
97 
98          boost::apply_visitor(vis1, v1);
99          boost::apply_visitor(vis2, v2);
100 
101     }
102     std::cerr << 12 << ' ';
103     /* now test the class stuff */
104 
105     //first we import and test the global variables
106 
107     auto& father_val = sm.get_variable<int>("some_space::father_value");
108     auto& static_val = sm.get_variable<int>("some_space::some_class::value");
109     BOOST_TEST(father_val == 12);
110     BOOST_TEST(static_val == -1);
111     std::cerr << 13 << ' ';
112     //now get the static function.
113     auto set_value = sm.get_function<void(const int &)>("some_space::some_class::set_value");
114     BOOST_TEST(set_value != nullptr);
115     std::cerr << 14 << ' ';
116     set_value(42);
117     BOOST_TEST(static_val == 42); //alright, static method works.
118 
119 
120     //alright, now import the class members
121     //first add the type alias.
122     sm.add_type_alias<override_class>("some_space::some_class");
123     std::cerr << 15 << ' ';
124     auto set = sm.get_mem_fn<override_class, void(int)>("set");
125 
126     std::cerr << 16 << ' ';
127     try {
128         sm.get_mem_fn<override_class, int()>("get");
129         BOOST_TEST(false);
130     } catch(boost::dll::fs::system_error &) {}
131     auto get = sm.get_mem_fn<const override_class, int()>("get");
132     std::cerr << 17 << ' ';
133     BOOST_TEST(get != nullptr);
134     BOOST_TEST(set != nullptr);
135     std::cerr << 18 << ' ';
136     auto func_dd  = sm.get_mem_fn<override_class,                double(double, double)>("func");
137     auto func_ii  = sm.get_mem_fn<override_class,                int(int, int)>         ("func");
138     auto func_iiv = sm.get_mem_fn<volatile override_class,       int(int, int)>         ("func");
139     auto func_ddc = sm.get_mem_fn<const volatile override_class, double(double, double)>("func");
140 
141     std::cerr << 19 << ' ';
142     BOOST_TEST(func_dd != nullptr);
143     BOOST_TEST(func_ii != nullptr);
144 
145     std::cerr << 20 << ' ';
146     auto ctor_v = sm.get_constructor<override_class()>();
147     auto ctor_i = sm.get_constructor<override_class(int)>();
148 
149     auto dtor   = sm.get_destructor<override_class>();
150     std::cerr << 21 << ' ';
151     //actually never used.
152     if (ctor_v.has_allocating())
153    {
154         //allocate
155         auto p = ctor_v.call_allocating();
156 
157         //assert it works
158         auto val = (p->*get)();
159         BOOST_TEST(val == 123);
160         //deallocate
161         dtor.call_deleting(p);
162         //now i cannot assert that it deletes, since it would crash.
163    }
164     //More tests to assure the correct this-ptr
165     std::cerr << 22 << ' ';
166    typedef override_class * override_class_p;
167    override_class_p &this_dll = sm.shared_lib().get<override_class_p>("this_");
168 
169     std::cerr << 23 << ' ';
170    //ok, now load the ctor/dtor
171    override_class oc;
172 
173    override_class_p this_exe = &oc;
174 
175     for (auto& i : oc.arr) {
176        i = 0;
177     }
178     std::cerr << 24 << ' ';
179 
180     BOOST_TEST((oc.*get)() == 0);           BOOST_TEST(this_dll == this_exe);
181 
182     ctor_i.call_standard(&oc, 12);          BOOST_TEST(this_dll == this_exe);
183 
184     BOOST_TEST(static_val == 12);
185     BOOST_TEST((oc.*get)() == 456);         BOOST_TEST(this_dll == this_exe);
186     (oc.*set)(42);
187     BOOST_TEST((oc.*get)() == 42);          BOOST_TEST(this_dll == this_exe);
188     std::cerr << 25 << ' ';
189 
190     BOOST_TEST((oc.*func_dd)(3,2)   == 6);  BOOST_TEST(this_dll == this_exe);
191     BOOST_TEST((oc.*func_ii)(1,2)   == 3);  BOOST_TEST(this_dll == this_exe);
192     BOOST_TEST((oc.*func_ddc)(10,2) == 5);  BOOST_TEST(this_dll == this_exe);
193     BOOST_TEST((oc.*func_iiv)(9,2)  == 7);  BOOST_TEST(this_dll == this_exe);
194     std::cerr << 26 << ' ';
195     dtor.call_standard(&oc);                BOOST_TEST(this_dll == this_exe);
196     BOOST_TEST(static_val == 0);
197 
198 // TODO: FIX!
199 #ifndef BOOST_TRAVISCI_BUILD
200     const auto& ti = sm.get_type_info<override_class>();
201     BOOST_TEST(ti.name() != nullptr);
202 #endif
203     std::cerr << 27 << ' ';
204     //test the ovls helper.
205     {
206         namespace ex = boost::dll::experimental;
207         auto &var = ex::get<double>(sm, "some_space::variable");
208         BOOST_TEST(&var == &sp_variable);
209 
210         auto fun = ex::get<void(int)>(sm, "overloaded");
211         BOOST_TEST(fun == ovl1);
212 
213         auto func_ii  = sm.get_mem_fn<override_class,                int(int, int)>         ("func");
214 
215         auto mem_fn = ex::get<override_class, int(int, int)>(sm, "func");
216 
217         BOOST_TEST(mem_fn == func_ii);
218     }
219 
220     std::cerr << 28 << ' ';
221     return boost::report_errors();
222 }
223 
224 #else
main()225 int main() {return 0;}
226 #endif
227