Teach adopt() to hold the adopted pointer in custom pointer type.
[luabind.git] / test / test_lua_classes.cpp
blob92cfb30cd5ac4dc00bb6a4b39dbf0589b309f98d
1 // Copyright (c) 2005 Daniel Wallin, Arvid Norberg
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the "Software"),
5 // to deal in the Software without restriction, including without limitation
6 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 // and/or sell copies of the Software, and to permit persons to whom the
8 // Software is furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included
11 // in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
14 // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
15 // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
17 // SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
18 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
23 #include "test.hpp"
25 #include <luabind/luabind.hpp>
26 #include <luabind/wrapper_base.hpp>
27 #include <luabind/adopt_policy.hpp>
28 #include <boost/shared_ptr.hpp>
30 namespace luabind {
32 #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
33 template<class T>
34 T* get_pointer(boost::shared_ptr<T> const& p) { return p.get(); }
35 #endif
39 using namespace luabind;
41 struct A : counted_type<A>
43 virtual ~A() {}
45 virtual std::string f()
46 { return "A:f()"; }
48 virtual std::string g() const
49 { return "A:g()"; }
52 struct A_wrap : A, wrap_base
54 std::string f()
56 return call_member<std::string>(this, "f");
59 static std::string default_f(A* p)
60 { return p->A::f(); }
62 std::string g() const
64 return call_member<std::string>(this, "g");
67 static std::string default_g(A const* p)
68 { return p->A::g(); }
71 struct B : A
73 virtual std::string f()
74 { return "B:f()"; }
77 struct B_wrap : B, wrap_base
79 virtual std::string f()
80 { return call_member<std::string>(this, "f"); }
82 static std::string default_f(B* p)
83 { return p->B::f(); }
85 virtual std::string g() const
86 { return call_member<std::string>(this, "g"); }
88 static std::string default_g(B const* p)
89 { return p->B::g(); }
93 struct base : counted_type<base>
95 virtual ~base() {}
97 virtual std::string f()
99 return "base:f()";
102 virtual std::string g() const { return ""; }
105 base* filter(base* p) { return p; }
107 struct base_wrap : base, wrap_base
109 virtual std::string f()
111 return call_member<std::string>(this, "f");
114 static std::string default_f(base* p)
116 return p->base::f();
119 virtual std::string g() const
121 return call_member<std::string>(this, "g");
125 struct T_ // vc6.5, don't name your types T!
127 int f(int) { return 1; }
130 struct U : T_
132 int g() { return 3; }
133 int f(int, int) { return 2; }
136 void test_main(lua_State* L)
138 module(L)
140 class_<A, A_wrap, boost::shared_ptr<A> >("A")
141 .def(constructor<>())
142 .def("f", &A::f, &A_wrap::default_f)
143 .def("g", &A::g, &A_wrap::default_g),
145 class_<B, A, B_wrap, boost::shared_ptr<A> >("B")
146 .def(constructor<>())
147 .def("f", &B::f, &B_wrap::default_f)
148 .def("g", &B::g, &B_wrap::default_g),
150 def("filter", &filter),
152 class_<base, base_wrap>("base")
153 .def(constructor<>())
154 .def("f", &base::f, &base_wrap::default_f)
155 .def("g", &base::g),
157 class_<T_>("T")
158 .def("f", &T_::f),
160 class_<U, T_>("U")
161 .def(constructor<>())
162 .def("f", &T_::f)
163 .def("f", &U::f)
164 .def("g", &U::g)
167 DOSTRING(L,
168 "u = U()\n"
169 "assert(u:f(0) == 1)\n"
170 "assert(u:f(0,0) == 2)\n"
171 "assert(u:g() == 3)\n");
173 DOSTRING(L,
174 "u = U()\n"
175 "assert(u:f(0) == 1)\n"
176 "assert(u:f(0,0) == 2)\n"
177 "assert(u:g() == 3)\n");
179 DOSTRING(L,
180 "function base:fun()\n"
181 " return 4\n"
182 "end\n"
183 "ba = base()\n"
184 "assert(ba:fun() == 4)");
186 DOSTRING(L,
187 "class 'derived' (base)\n"
188 " function derived:__init() base.__init(self) end\n"
189 " function derived:f()\n"
190 " return 'derived:f() : ' .. base.f(self)\n"
191 " end\n"
193 "class 'empty_derived' (base)\n"
194 " function empty_derived:__init() base.__init(self) end\n"
196 "class 'C' (B)\n"
197 " function C:__init() B.__init(self) end\n"
198 " function C:f() return 'C:f()' end\n"
200 "function make_derived()\n"
201 " return derived()\n"
202 "end\n"
204 "function make_empty_derived()\n"
205 " return empty_derived()\n"
206 "end\n"
208 "function adopt_ptr(x)\n"
209 " a = x\n"
210 "end\n");
212 DOSTRING(L,
213 "function gen_error()\n"
214 " assert(0 == 1)\n"
215 "end\n");
217 DOSTRING(L,
218 "a = A()\n"
219 "b = B()\n"
220 "c = C()\n"
222 "assert(c:f() == 'C:f()')\n"
223 "assert(b:f() == 'B:f()')\n"
224 "assert(a:f() == 'A:f()')\n"
225 "assert(b:g() == 'A:g()')\n"
226 "assert(c:g() == 'A:g()')\n"
228 "assert(C.f(c) == 'C:f()')\n"
229 "assert(B.f(c) == 'B:f()')\n"
230 "assert(A.f(c) == 'A:f()')\n"
231 "assert(A.g(c) == 'A:g()')\n");
233 #ifndef LUABIND_NO_EXCEPTONS
235 LUABIND_CHECK_STACK(L);
237 try { call_function<int>(L, "gen_error"); }
238 catch (luabind::error&)
240 bool result(
241 lua_tostring(L, -1) == std::string("[string \"function "
242 "gen_error()...\"]:2: assertion failed!"));
243 TEST_CHECK(result);
244 lua_pop(L, 1);
249 A a;
251 DOSTRING(L, "function test_ref(x) end");
252 call_function<void>(L, "test_ref", boost::ref(a));
256 LUABIND_CHECK_STACK(L);
258 try { call_function<void>(L, "gen_error"); }
259 catch (luabind::error&)
261 bool result(
262 lua_tostring(L, -1) == std::string("[string \"function "
263 "gen_error()...\"]:2: assertion failed!"));
264 TEST_CHECK(result);
265 lua_pop(L, 1);
270 LUABIND_CHECK_STACK(L);
272 try { call_function<void>(L, "gen_error") [ adopt(result) ]; }
273 catch (luabind::error&)
275 bool result(
276 lua_tostring(L, -1) == std::string("[string \"function "
277 "gen_error()...\"]:2: assertion failed!"));
278 TEST_CHECK(result);
279 lua_pop(L, 1);
283 #endif
285 base* ptr;
287 LUABIND_CHECK_STACK(L);
289 TEST_NOTHROW(
290 object a = globals(L)["ba"];
291 TEST_CHECK(call_member<int>(a, "fun") == 4);
296 LUABIND_CHECK_STACK(L);
298 object make_derived = globals(L)["make_derived"];
299 TEST_NOTHROW(
300 call_function<void>(make_derived)
304 std::auto_ptr<base> own_ptr;
306 LUABIND_CHECK_STACK(L);
308 TEST_NOTHROW(
309 own_ptr = std::auto_ptr<base>(
310 call_function<base*>(L, "make_derived") [ adopt(result) ])
314 // make sure the derived lua-part is still referenced by
315 // the adopted c++ pointer
316 DOSTRING(L,
317 "collectgarbage()\n"
318 "collectgarbage()\n"
319 "collectgarbage()\n"
320 "collectgarbage()\n"
321 "collectgarbage()\n");
323 TEST_NOTHROW(
324 TEST_CHECK(own_ptr->f() == "derived:f() : base:f()")
326 own_ptr = std::auto_ptr<base>();
328 // test virtual functions that are not overridden by lua
329 TEST_NOTHROW(
330 own_ptr = std::auto_ptr<base>(
331 call_function<base*>(L, "make_empty_derived") [ adopt(result) ])
333 TEST_NOTHROW(
334 TEST_CHECK(own_ptr->f() == "base:f()")
336 TEST_NOTHROW(
337 call_function<void>(L, "adopt_ptr", own_ptr.get()) [ adopt(_1) ]
339 own_ptr.release();
341 // test virtual functions that are overridden by lua
342 TEST_NOTHROW(
343 ptr = call_function<base*>(L, "derived")
346 TEST_NOTHROW(
347 TEST_CHECK(ptr->f() == "derived:f() : base:f()")
350 // test virtual function dispatch from within lua
351 DOSTRING(L,
352 "a = derived()\n"
353 "b = filter(a)\n"
354 "assert(b:f() == 'derived:f() : base:f()')\n");
356 // test back references
357 DOSTRING(L,
358 "a = derived()\n"
359 "assert(a == filter(a))\n");