b7rc4 checkin
[luabind.git] / test / test_lua_classes.cpp
blob11469178cf9d547051292e807a247ca89234955c
1 // Copyright (c) 2004 Daniel Wallin and 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"
24 #include <luabind/luabind.hpp>
25 #include <luabind/wrapper_base.hpp>
26 #include <luabind/adopt_policy.hpp>
27 #include <boost/shared_ptr.hpp>
29 namespace luabind {
31 template<class T>
32 T* get_pointer(boost::shared_ptr<T>& p) { return p.get(); }
34 template<class A>
35 boost::shared_ptr<const A>* get_const_holder(boost::shared_ptr<A>*)
37 return 0;
41 using namespace luabind;
43 namespace {
45 struct A : counted_type<A>
47 virtual ~A() {}
49 virtual std::string f()
50 { return "A:f()"; }
52 virtual std::string g() const
53 { return "A:g()"; }
56 struct A_wrap : A, wrap_base
58 std::string f()
60 return call_member<std::string>(this, "f");
63 static std::string default_f(A* p)
64 { return p->A::f(); }
66 std::string g() const
68 return call_member<std::string>(this, "g");
71 static std::string default_g(A const* p)
72 { return p->A::g(); }
75 struct B : A
77 virtual std::string f()
78 { return "B:f()"; }
81 struct B_wrap : B, wrap_base
83 virtual std::string f()
84 { return call_member<std::string>(this, "f"); }
86 static std::string default_f(B* p)
87 { return p->B::f(); }
89 virtual std::string g() const
90 { return call_member<std::string>(this, "g"); }
92 static std::string default_g(B const* p)
93 { return p->B::g(); }
97 struct base : counted_type<base>
99 virtual ~base() {}
101 virtual std::string f()
103 return "base:f()";
106 virtual std::string g() const { return ""; }
109 base* filter(base* p) { return p; }
111 struct base_wrap : base, wrap_base
113 virtual std::string f()
115 return call_member<std::string>(this, "f");
118 static std::string default_f(base* p)
120 return p->base::f();
123 virtual std::string g() const
125 return call_member<std::string>(this, "g");
129 struct T_ // vc6.5, don't name your types T!
131 int f(int) { return 1; }
134 struct U : T_
136 int g() { return 3; }
137 int f(int, int) { return 2; }
140 } // namespace unnamed
142 void test_lua_classes()
144 COUNTER_GUARD(A);
145 COUNTER_GUARD(base);
147 lua_state L;
149 module(L)
151 class_<A, A_wrap, boost::shared_ptr<A> >("A")
152 .def(constructor<>())
153 .def("f", &A::f, &A_wrap::default_f)
154 .def("g", &A::g, &A_wrap::default_g),
156 class_<B, A, B_wrap, boost::shared_ptr<A> >("B")
157 .def(constructor<>())
158 .def("f", &B::f, &B_wrap::default_f)
159 .def("g", &B::g, &B_wrap::default_g),
161 def("filter", &filter),
163 class_<base, base_wrap>("base")
164 .def(constructor<>())
165 .def("f", &base::f, &base_wrap::default_f)
166 .def("g", &base::g),
168 class_<T_>("T")
169 .def("f", &T_::f),
171 class_<U, T_>("U")
172 .def(constructor<>())
173 .def("f", &U::f)
174 .def("g", &U::g)
177 DOSTRING(L,
178 "u = U()\n"
179 "assert(u:f(0) == 1)\n"
180 "assert(u:f(0,0) == 2)\n"
181 "assert(u:g() == 3)\n");
183 DOSTRING(L,
184 "function base:fun()\n"
185 " return 4\n"
186 "end\n"
187 "ba = base()\n"
188 "assert(ba:fun() == 4)");
190 DOSTRING(L,
191 "class 'derived' (base)\n"
192 " function derived:__init() super() end\n"
193 " function derived:f()\n"
194 " return 'derived:f() : ' .. base.f(self)\n"
195 " end\n"
197 "class 'empty_derived' (base)\n"
198 " function empty_derived:__init() super() end\n"
200 "class 'C' (B)\n"
201 " function C:__init() super() end\n"
202 " function C:f() return 'C:f()' end\n"
204 "function make_derived()\n"
205 " return derived()\n"
206 "end\n"
208 "function make_empty_derived()\n"
209 " return empty_derived()\n"
210 "end\n"
212 "function adopt_ptr(x)\n"
213 " a = x\n"
214 "end\n");
216 DOSTRING(L,
217 "function gen_error()\n"
218 " assert(0 == 1)\n"
219 "end\n");
221 DOSTRING(L,
222 "a = A()\n"
223 "b = B()\n"
224 "c = C()\n"
226 "assert(c:f() == 'C:f()')\n"
227 "assert(b:f() == 'B:f()')\n"
228 "assert(a:f() == 'A:f()')\n"
229 "assert(b:g() == 'A:g()')\n"
230 "assert(c:g() == 'A:g()')\n"
232 "assert(C.f(c) == 'C:f()')\n"
233 "assert(B.f(c) == 'B:f()')\n"
234 "assert(A.f(c) == 'A:f()')\n"
235 "assert(A.g(c) == 'A:g()')\n");
237 #ifndef LUABIND_NO_EXCEPTONS
239 LUABIND_CHECK_STACK(L);
241 try { call_function<int>(L, "gen_error"); }
242 catch (luabind::error&)
244 bool result(
245 lua_tostring(L, -1) == std::string("[string \"function "
246 "gen_error()...\"]:2: assertion failed!"));
247 BOOST_CHECK(result);
248 lua_pop(L, 1);
253 A a;
255 DOSTRING(L, "function test_ref(x) end");
256 call_function<void>(L, "test_ref", boost::ref(a));
260 LUABIND_CHECK_STACK(L);
262 try { call_function<void>(L, "gen_error"); }
263 catch (luabind::error&)
265 bool result(
266 lua_tostring(L, -1) == std::string("[string \"function "
267 "gen_error()...\"]:2: assertion failed!"));
268 BOOST_CHECK(result);
269 lua_pop(L, 1);
274 LUABIND_CHECK_STACK(L);
276 try { call_function<void*>(L, "gen_error") [ adopt(result) ]; }
277 catch (luabind::error&)
279 bool result(
280 lua_tostring(L, -1) == std::string("[string \"function "
281 "gen_error()...\"]:2: assertion failed!"));
282 BOOST_CHECK(result);
283 lua_pop(L, 1);
287 #endif
289 base* ptr;
291 LUABIND_CHECK_STACK(L);
293 BOOST_CHECK_NO_THROW(
294 object a = get_globals(L)["ba"];
295 BOOST_CHECK(call_member<int>(a, "fun") == 4);
300 LUABIND_CHECK_STACK(L);
302 object make_derived = get_globals(L)["make_derived"];
303 BOOST_CHECK_NO_THROW(
304 call_function<void>(make_derived)
308 std::auto_ptr<base> own_ptr;
310 LUABIND_CHECK_STACK(L);
312 BOOST_CHECK_NO_THROW(
313 own_ptr = std::auto_ptr<base>(
314 call_function<base*>(L, "make_derived") [ adopt(result) ])
318 // make sure the derived lua-part is still referenced by
319 // the adopted c++ pointer
320 DOSTRING(L,
321 "collectgarbage()\n"
322 "collectgarbage()\n"
323 "collectgarbage()\n"
324 "collectgarbage()\n"
325 "collectgarbage()\n");
327 BOOST_CHECK_NO_THROW(
328 BOOST_CHECK(own_ptr->f() == "derived:f() : base:f()")
330 own_ptr = std::auto_ptr<base>();
332 // test virtual functions that are not overridden by lua
333 BOOST_CHECK_NO_THROW(
334 own_ptr = std::auto_ptr<base>(
335 call_function<base*>(L, "make_empty_derived") [ adopt(result) ])
337 BOOST_CHECK_NO_THROW(
338 BOOST_CHECK(own_ptr->f() == "base:f()")
340 BOOST_CHECK_NO_THROW(
341 call_function<void>(L, "adopt_ptr", own_ptr.get()) [ adopt(_1) ]
343 own_ptr.release();
345 // test virtual functions that are overridden by lua
346 BOOST_CHECK_NO_THROW(
347 ptr = call_function<base*>(L, "derived")
350 BOOST_CHECK_NO_THROW(
351 BOOST_CHECK(ptr->f() == "derived:f() : base:f()")
354 // test virtual function dispatch from within lua
355 DOSTRING(L,
356 "a = derived()\n"
357 "b = filter(a)\n"
358 "assert(b:f() == 'derived:f() : base:f()')\n");
360 // test back references
361 DOSTRING(L,
362 "a = derived()\n"
363 "assert(a == filter(a))\n");