Merge lp:~jarih/widelands/fix-lua-msvc into lp:widelands

Proposed by Jari Hautio
Status: Merged
Merged at revision: 5455
Proposed branch: lp:~jarih/widelands/fix-lua-msvc
Merge into: lp:widelands
Diff against target: 752 lines (+545/-60)
9 files modified
CMakeLists.txt (+10/-3)
src/CMakeLists.txt (+2/-0)
src/scripting/CMakeLists.txt (+6/-0)
src/scripting/luna.h (+2/-2)
src/scripting/luna_impl.h (+95/-55)
src/scripting/scripting.cc (+2/-0)
src/scripting/test/CMakeLists.txt (+51/-0)
src/scripting/test/scripting_test_main.cc (+23/-0)
src/scripting/test/test_luna.cc (+354/-0)
To merge this branch: bzr merge lp:~jarih/widelands/fix-lua-msvc
Reviewer Review Type Date Requested Status
SirVer Approve
Review via email: mp+30809@code.launchpad.net

Description of the change

Fixes issues with lua scripting luna interfacing in Visual Studio 2008 (Bug #590472). Both multiple inheritance and virtual base classes are now supported on linux/gcc and windows/msvc.

Basic principle in the fixes was to ensure that whenever something is reinterpred_cast:ed to void* and stored to lua tables, it's always casted to exactly same type when it's casted back from void*.

Luna Mmethod dispatching is fixed to retrive method pointer using correct type using additional template parameter for parent type in m_method_dispatch.

Implemented property dispatching system so that proerties are accessed wit correct type information. Instead of storing lightuserdata with pointer to property structure to metatable, metatable now contains a table with lightuserdata for getter and setter as well as cfunction for dispatching the property. Templated dispatching function stores type information for parent type so that when property is accessed, types are same is when it was stored.

Implemented unit test support to test luna behaviour. There were some tricks needed to prevent linking with widelands main.cc or SDL_main:
 - WL_MAIN_SRCS contained main.cc due to greedy globbing. This is fixed by removing main.cc after globbing.
 - SDL_LIBRARY contained SDL_main.lib, which had to be removed before adding SDL libraries to test executable.

Test executable is only included in the build if boost unit_test_framework library is found. This way widelands can be built without compiling boost libraries.

To test:
 - run CMake tests after build using for example "make test".
 - run scripting unit test scenario ts.wmf
 - With windows/visual studio 2008 game crashed before this fix when unit tests or ts.wmf was run.
 - On linux/mac this fix should not break anything.

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

Indeed. Didn't break anything on Mac OS X. Very nice Job, Jari! Applied and merged in r5455.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2010-05-21 09:04:50 +0000
3+++ CMakeLists.txt 2010-07-23 17:57:50 +0000
4@@ -104,11 +104,13 @@
5 set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
6
7 set (BUILD_SHARED_LIBS OFF)
8+# we only include Boost Headers to the main executable, no libraries
9+# unit_test_framework is for testing only
10+set (Boost_FIND_COMPONENTS unit_test_framework)
11 set (Boost_USE_STATIC_LIBS ON)
12 set (Boost_USE_MULTITHREADED ON)
13-find_package(Boost 1.35.0 REQUIRED)
14-include_directories(${Boost_INCLUDE_DIR})
15-target_link_libraries(widelands ${Boost_LIBRARIES})
16+set (Boost_DETAILED_FAILURE_MSG ON)
17+find_package(Boost 1.35.0 COMPONENTS unit_test_framework REQUIRED)
18
19 set (PARAMETER_COMPILERFLAG_OLDSTYLECAST_EXTENDED "-Wold-style-cast -isystem ${Boost_INCLUDE_DIR}")
20 set (PARAMETER_COMPILERFLAG_OLDSTYLECAST "-Wold-style-cast")
21@@ -176,6 +178,9 @@
22 add_definitions( -Dssize_t=size_t )
23 add_definitions( -Dmkdir=_mkdir )
24
25+ include_directories(${Boost_INCLUDE_DIR})
26+ # Automatic linking for boost requires setting lib dir
27+ LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
28
29 find_library(INTL_LIBRARY NAMES intl libintl)
30
31@@ -285,6 +290,8 @@
32 COMPONENT CoreVersionFile
33 )
34
35+enable_testing()
36+
37 include_directories(src ${CMAKE_CURRENT_BINARY_DIR}/src)
38
39 include(CheckIncludeFile)
40
41=== modified file 'src/CMakeLists.txt'
42--- src/CMakeLists.txt 2010-05-21 09:04:50 +0000
43+++ src/CMakeLists.txt 2010-07-23 17:57:50 +0000
44@@ -26,6 +26,8 @@
45 file(GLOB_RECURSE WL_SRCS_ALL *.cc)
46
47 file(GLOB WL_MAIN_SRCS *.cc)
48+file(GLOB WL_MAIN_CC main.cc)
49+list(REMOVE_ITEM WL_MAIN_SRCS ${WL_MAIN_CC})
50 add_library(widelands_main ${WL_MAIN_SRCS})
51
52 #file (GLOB WL_SRCS *.cc economy/*.cc scripting/*.cc)
53
54=== modified file 'src/scripting/CMakeLists.txt'
55--- src/scripting/CMakeLists.txt 2010-02-05 01:13:20 +0000
56+++ src/scripting/CMakeLists.txt 2010-07-23 17:57:50 +0000
57@@ -4,3 +4,9 @@
58
59 target_link_libraries(widelands_scripting ${LUA_LIBRARIES})
60
61+# Build tests only if unit test framework is available.
62+if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
63+ add_subdirectory(test)
64+else()
65+ message("Excluded unit tests for scripting because boost unit_test_framework was not found.")
66+endif()
67
68=== modified file 'src/scripting/luna.h'
69--- src/scripting/luna.h 2010-03-21 18:12:27 +0000
70+++ src/scripting/luna.h 2010-07-23 17:57:50 +0000
71@@ -110,7 +110,7 @@
72
73 m_create_metatable_for_class<T>(L);
74
75- m_register_properties_in_metatable<T>(L);
76+ m_register_properties_in_metatable<T,T>(L);
77 m_register_methods_in_metatable<T, T>(L);
78
79 if(!return_metatable)
80@@ -124,7 +124,7 @@
81 template <class T, class PT>
82 void add_parent(lua_State * L)
83 {
84- m_register_properties_in_metatable<PT>(L);
85+ m_register_properties_in_metatable<T,PT>(L);
86 m_register_methods_in_metatable<T, PT>(L);
87 }
88
89
90=== modified file 'src/scripting/luna_impl.h'
91--- src/scripting/luna_impl.h 2010-03-05 14:32:47 +0000
92+++ src/scripting/luna_impl.h 2010-07-23 17:57:50 +0000
93@@ -54,22 +54,45 @@
94 template <class T> T * * get_user_class(lua_State * const L, int narg);
95
96 template <class T>
97-PropertyType<T> const * m_lookup_property_in_metatable(lua_State * const L) {
98- // stack: table name
99-
100+int m_dispatch_property_in_metatable(lua_State * const L, bool setter) {
101+ // stack for getter: table name
102+ // stack for setter: table name value
103+ int ret = 0;
104 // Look up the key in the metatable
105- lua_getmetatable(L, 1); // table name mt
106- lua_pushvalue (L, 2); // table name mt name
107- lua_rawget (L, -2); // table name mt mt_val
108-
109- const PropertyType<T> * rv = 0;
110-
111- if (lua_islightuserdata(L, -1))
112- rv = static_cast<const PropertyType<T> *>(lua_touserdata(L, -1));
113-
114- lua_remove(L, -2); // table name mt_val
115-
116- return rv;
117+ lua_getmetatable(L, 1); // table name <value> mt
118+ lua_pushvalue (L, 2); // table name <value> mt name
119+ lua_rawget (L, -2); // table name <value> mt mt_val
120+ lua_remove(L, -2); // table name <value> mt_val
121+ if (lua_istable(L, -1))
122+ {
123+ // dispatcher
124+
125+ lua_pushstring(L, "dispatcher"); // table name <value> mt_val "dispatcher"
126+ lua_gettable(L, -2); // table name <value> mt_val dispatcher_val
127+ if (!lua_iscfunction(L, -1))
128+ {
129+ lua_pop(L, 2); // table name <value>
130+ return report_error(L, "invalid property without dispatcher function");
131+ }
132+ lua_CFunction dispatcher = lua_tocfunction(L, -1);
133+ lua_pop(L, 1); // table name <value> mt_val
134+
135+ // get property method to stack
136+ lua_pushstring(L, setter ? "setter" : "getter");
137+ lua_gettable(L, -2); // table name <value> mt_val getter_val/setter_val
138+ lua_remove(L, -2); // table name <value> getter_val/setter_val
139+ // dispatcher pops off getter/setter and returns whatever get/set property functions returns
140+ ret = dispatcher(L); // table name value
141+ } else {
142+ if (setter) {
143+ lua_rawset(L, 1);
144+ } else {
145+ // leave the value to stack
146+ ret = 1;
147+ }
148+ }
149+
150+ return ret;
151 }
152
153 /**
154@@ -94,42 +117,43 @@
155 }
156 lua_pop(L, 1); // table name
157
158- const PropertyType<T>* list = m_lookup_property_in_metatable<T>(L);
159- // stack: table name list
160-
161- // Not in metatable?, return it
162- if (!list) {
163- return 1;
164- }
165- lua_pop(L, 1); // table name
166-
167- T * * const obj = get_user_class<T>(L, 1);
168- // table name
169-
170- // push value on top of the stack for the method call
171- return ((*obj)->*(list->getter))(L);
172+ return m_dispatch_property_in_metatable<T>(L, false);
173 }
174
175 template <class T>
176 int m_property_setter(lua_State * const L) {
177 // stack: table name value
178- PropertyType<T> const * list = m_lookup_property_in_metatable<T>(L);
179- lua_pop(L, 1); // table name value
180- // table name value rv
181-
182- if (!list) {
183- // Not in metatable?
184- // do a normal set on the table
185- lua_rawset(L, 1);
186- return 0;
187+ return m_dispatch_property_in_metatable<T>(L, true);
188+}
189+
190+/**
191+ * This function calls a lua method in our given object. we can already be
192+ * sure that the called method is registered in our metatable, but we have to
193+ * make sure that the method is called correctly: obj.method(obj) or
194+ * obj:method(). We also check that we are not called with another object
195+ */
196+template <class T, class PT>
197+int m_property_dispatch(lua_State * const L) {
198+ // Check for invalid: obj.method()
199+ int const n = lua_gettop(L);
200+ if (!n)
201+ return report_error(L, "Property needs at least the object as argument!");
202+
203+ // Check for invalid: obj.method(plainOldDatatype)
204+ luaL_checktype(L, 1, LUA_TTABLE);
205+
206+ typedef int (PT::* const * ConstMethodPtr)(lua_State *);
207+ ConstMethodPtr pfunc = reinterpret_cast<ConstMethodPtr>(lua_touserdata(L, -1));
208+ lua_pop(L, 1);
209+
210+ T * * const obj = get_user_class<T>(L, 1);
211+
212+ if (!*pfunc)
213+ {
214+ return report_error(L, "The property is read-only!\n");
215 }
216-
217- T * * const obj = get_user_class<T>(L, 1);
218-
219- if (list->setter == 0)
220- return report_error(L, "The property '%s' is read-only!\n", list->name);
221-
222- return ((*obj)->*(list->setter))(L);
223+ // Call it on our instance
224+ return ((*obj)->*(*pfunc))(L);
225 }
226
227 /**
228@@ -138,7 +162,7 @@
229 * make sure that the method is called correctly: obj.method(obj) or
230 * obj:method(). We also check that we are not called with another object
231 */
232-template <class T>
233+template <class T, class PT>
234 int m_method_dispatch(lua_State * const L) {
235 // Check for invalid: obj.method()
236 int const n = lua_gettop(L);
237@@ -149,7 +173,7 @@
238 luaL_checktype(L, 1, LUA_TTABLE);
239
240 // Get the method pointer from the closure
241- typedef int (T::* const * ConstMethod)(lua_State *);
242+ typedef int (PT::* const * ConstMethod)(lua_State *);
243 ConstMethod func = reinterpret_cast<ConstMethod>
244 (lua_touserdata(L, lua_upvalueindex(1)));
245
246@@ -250,17 +274,33 @@
247 return metatable;
248 }
249
250-template <class T>
251+template <class T, class PT>
252 void m_register_properties_in_metatable
253 (lua_State * const L)
254 {
255- for (int i = 0; T::Properties[i].name; ++i) {
256+ for (int i = 0; PT::Properties[i].name; ++i) {
257 // metatable[prop_name] = Pointer to getter setter
258- lua_pushstring(L, T::Properties[i].name);
259- lua_pushlightuserdata
260- (L,
261- const_cast<void *>
262- (reinterpret_cast<void const *>(&T::Properties[i])));
263+ lua_pushstring(L, PT::Properties[i].name);
264+ lua_newtable(L);
265+ lua_pushstring(L, "getter");
266+ lua_pushlightuserdata
267+ (L,
268+ const_cast<void *>
269+ (reinterpret_cast<const void *>
270+ (&(PT::Properties[i].getter))));
271+ lua_settable(L, -3);
272+ lua_pushstring(L, "setter");
273+ lua_pushlightuserdata
274+ (L,
275+ const_cast<void *>
276+ (reinterpret_cast<const void *>
277+ (&(PT::Properties[i].setter))));
278+ lua_settable(L, -3);
279+
280+ lua_pushstring(L, "dispatcher");
281+ lua_pushcfunction(L, &(m_property_dispatch<T, PT>));
282+ lua_settable(L, -3);
283+
284 lua_settable(L, -3); // Metatable is directly before our pushed stuff
285 }
286 }
287@@ -279,7 +319,7 @@
288 (L,
289 const_cast<void *>
290 (reinterpret_cast<void const *>(&PT::Methods[i].method)));
291- lua_pushcclosure(L, &(m_method_dispatch<T>), 1);
292+ lua_pushcclosure(L, &(m_method_dispatch<T, PT>), 1);
293 lua_settable(L, -3); // Metatable is directly before our pushed stuff
294 }
295 }
296
297=== modified file 'src/scripting/scripting.cc'
298--- src/scripting/scripting.cc 2010-05-23 19:00:49 +0000
299+++ src/scripting/scripting.cc 2010-07-23 17:57:50 +0000
300@@ -225,6 +225,8 @@
301 }
302
303 // Push the instance of this class into the registry
304+ // MSVC2008 requires that stored and retrieved types are
305+ // same, so use LuaInterface* on both sides.
306 lua_pushlightuserdata(m_L, reinterpret_cast<void*>(dynamic_cast<LuaInterface*>(this)));
307 lua_setfield(m_L, LUA_REGISTRYINDEX, "lua_interface");
308
309
310=== added file 'src/scripting/test/CMakeLists.txt'
311--- src/scripting/test/CMakeLists.txt 1970-01-01 00:00:00 +0000
312+++ src/scripting/test/CMakeLists.txt 2010-07-23 17:57:50 +0000
313@@ -0,0 +1,51 @@
314+file(GLOB WL_SCRIPTING_TEST_SRCS *.cc)
315+
316+add_executable(test_widelands_scripting ${WL_SCRIPTING_TEST_SRCS} ../../build_info.cc)
317+
318+set(SDL_LIBRARY_NOMAIN ${SDL_LIBRARY})
319+list(REMOVE_ITEM SDL_LIBRARY_NOMAIN ${SDLMAIN_LIBRARY})
320+
321+target_link_libraries(test_widelands_scripting
322+ widelands_logic widelands_main widelands_ai widelands_scripting widelands_sound widelands_wui widelands_graphic widelands_economy widelands_map_io widelands_editor widelands_ui_fsmenu widelands_network widelands_game_io widelands_ui_basic widelands_profile widelands_io
323+ widelands_io_filesystem widelands_editor widelands_editor_tools widelands_editor_ui_menus
324+ ${Boost_LIBRARIES}
325+ ${PNG_LIBRARY}
326+ ${ZLIB_LIBRARY}
327+ ${JPEG_LIBRARY}
328+ ${TIFF_LIBRARY}
329+ ${SDL_LIBRARY_NOMAIN}
330+ ${SDLIMAGE_LIBRARY}
331+ ${SDLMIXER_LIBRARY}
332+ ${SDLNET_LIBRARY}
333+ ${SDLTTF_LIBRARY}
334+ ${LUA_LIBRARY}
335+ ${SDLGFX_LIBRARY}
336+ )
337+if (GGZ_CORE_FOUND)
338+ target_link_libraries(test_widelands_scripting ${GGZ_CORE_LIBRARY})
339+endif (GGZ_CORE_FOUND)
340+
341+if (APPLE)
342+ target_link_libraries(test_widelands_scripting ${INTL_LIBRARY})
343+endif (APPLE)
344+
345+if (WIN32)
346+if (DEFINED MSVC)
347+ target_link_libraries(test_widelands_scripting ${INTL_LIBRARY})
348+ target_link_libraries(test_widelands_scripting ws2_32)
349+ #GGZ on MSVC using 3rdparty bundle needs expat library
350+ #if expat is not found, then 3rdparty bundle is not in use, so just continue.
351+ if (GGZ_CORE_FOUND)
352+ find_library(EXPAT_LIBRARY libexpat)
353+ if (EXPAT_LIBRARY)
354+ target_link_libraries(test_widelands_scripting ${EXPAT_LIBRARY})
355+ endif (EXPAT_LIBRARY)
356+ endif (GGZ_CORE_FOUND)
357+else (DEFINED MSVC)
358+ target_link_libraries(test_widelands_scripting intl)
359+ target_link_libraries(test_widelands_scripting wsock32)
360+endif (DEFINED MSVC)
361+endif (WIN32)
362+
363+
364+add_test(test_widelands_scripting test_widelands_scripting)
365\ No newline at end of file
366
367=== added file 'src/scripting/test/scripting_test_main.cc'
368--- src/scripting/test/scripting_test_main.cc 1970-01-01 00:00:00 +0000
369+++ src/scripting/test/scripting_test_main.cc 2010-07-23 17:57:50 +0000
370@@ -0,0 +1,23 @@
371+/*
372+ * Copyright (C) 2007-2008 by the Widelands Development Team
373+ *
374+ * This program is free software; you can redistribute it and/or
375+ * modify it under the terms of the GNU General Public License
376+ * as published by the Free Software Foundation; either version 2
377+ * of the License, or (at your option) any later version.
378+ *
379+ * This program is distributed in the hope that it will be useful,
380+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
381+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
382+ * GNU General Public License for more details.
383+ *
384+ * You should have received a copy of the GNU General Public License
385+ * along with this program; if not, write to the Free Software
386+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
387+ *
388+ */
389+
390+#define BOOST_AUTO_TEST_MAIN
391+#define BOOST_TEST_MODULE Scripting
392+#include <boost/test/unit_test.hpp>
393+
394
395=== added file 'src/scripting/test/test_luna.cc'
396--- src/scripting/test/test_luna.cc 1970-01-01 00:00:00 +0000
397+++ src/scripting/test/test_luna.cc 2010-07-23 17:57:50 +0000
398@@ -0,0 +1,354 @@
399+#include <exception>
400+#include <boost/test/unit_test.hpp>
401+#include <boost/shared_ptr.hpp>
402+#include <lua.hpp>
403+#include "scripting/luna.h"
404+
405+#include "scripting/luna_impl.h"
406+
407+using namespace boost;
408+
409+#ifndef BEGIN_LUNA_PROPERTIES
410+#define BEGIN_LUNA_PROPERTIES(klass) \
411+ const PropertyType<klass> klass::Properties[] = {
412+
413+#define END_LUNA_PROPERTIES() {0, 0, 0}};
414+#endif
415+
416+class L_Class : public LunaClass
417+{
418+ int x;
419+ int prop;
420+public:
421+ LUNA_CLASS_HEAD(L_Class);
422+ const char * get_modulename() {return "test";}
423+ L_Class() :x(123), prop(246) {}
424+ virtual ~L_Class() {}
425+ L_Class(lua_State *L) :x(124), prop(248) {}
426+ virtual int test(lua_State *L)
427+ {
428+ lua_pushuint32(L, x);
429+ return 1;
430+ }
431+ virtual int get_prop1(lua_State*L)
432+ {
433+ lua_pushint32(L, prop);
434+ return 1;
435+ }
436+ virtual int get_propr(lua_State*L)
437+ {
438+ lua_pushint32(L, 0);
439+ return 1;
440+ }
441+ virtual int set_prop1(lua_State*L)
442+ {
443+ prop = lua_tointeger(L, -1);
444+ return 0;
445+ }
446+ virtual void __persist(lua_State * L) {}
447+ virtual void __unpersist(lua_State * L) {}
448+};
449+const char L_Class::className[] = "Class";
450+const MethodType<L_Class> L_Class::Methods[] = {
451+ METHOD(L_Class, test),
452+ {0, 0},
453+};
454+BEGIN_LUNA_PROPERTIES(L_Class)
455+ PROP_RO(L_Class, propr),
456+ PROP_RW(L_Class, prop1),
457+END_LUNA_PROPERTIES()
458+
459+class L_SubClass : public L_Class
460+{
461+ int y;
462+public:
463+ LUNA_CLASS_HEAD(L_SubClass);
464+ L_SubClass() :y(1230) {}
465+ L_SubClass(lua_State *L) : L_Class(L), y(1240) {}
466+ virtual int subtest(lua_State *L)
467+ {
468+ lua_pushuint32(L, y);
469+ return 1;
470+ }
471+ virtual void __persist(lua_State * L) {}
472+ virtual void __unpersist(lua_State * L) {}
473+};
474+const char L_SubClass::className[] = "SubClass";
475+const MethodType<L_SubClass> L_SubClass::Methods[] = {
476+ METHOD(L_SubClass, subtest),
477+ {0, 0},
478+};
479+BEGIN_LUNA_PROPERTIES(L_SubClass)
480+END_LUNA_PROPERTIES()
481+
482+class L_VirtualClass : public virtual L_Class
483+{
484+ int z;
485+public:
486+ LUNA_CLASS_HEAD(L_VirtualClass);
487+ L_VirtualClass() :z(12300) {}
488+ L_VirtualClass(lua_State *L) : L_Class(L), z(12400) {}
489+ virtual int virtualtest(lua_State *L)
490+ {
491+ lua_pushuint32(L, z);
492+ return 1;
493+ }
494+ virtual void __persist(lua_State * L) {}
495+ virtual void __unpersist(lua_State * L) {}
496+};
497+const char L_VirtualClass::className[] = "VirtualClass";
498+const MethodType<L_VirtualClass> L_VirtualClass::Methods[] = {
499+ METHOD(L_VirtualClass, virtualtest),
500+ {0, 0},
501+};
502+BEGIN_LUNA_PROPERTIES(L_VirtualClass)
503+END_LUNA_PROPERTIES()
504+
505+class L_Second
506+{
507+public:
508+ int get_second(lua_State *L) {lua_pushstring(L, "second"); return 1;}
509+ virtual int multitest(lua_State *L)
510+ {
511+ lua_pushstring(L, "secondfunc");
512+ return 1;
513+ }
514+};
515+
516+class L_MultiClass : public L_Class, public L_Second
517+{
518+ int z;
519+public:
520+ LUNA_CLASS_HEAD(L_MultiClass );
521+ L_MultiClass () :z(12300) {}
522+ L_MultiClass (lua_State *L) : L_Class(L), z(12400) {}
523+ virtual int virtualtest(lua_State *L)
524+ {
525+ lua_pushuint32(L, z);
526+ return 1;
527+ }
528+ virtual void __persist(lua_State * L) {}
529+ virtual void __unpersist(lua_State * L) {}
530+};
531+const char L_MultiClass::className[] = "MultiClass";
532+const MethodType<L_MultiClass> L_MultiClass::Methods[] = {
533+ METHOD(L_MultiClass, virtualtest),
534+ METHOD(L_Second, multitest),
535+ {0, 0},
536+};
537+BEGIN_LUNA_PROPERTIES(L_MultiClass)
538+ PROP_RO(L_MultiClass, second),
539+END_LUNA_PROPERTIES()
540+
541+const static struct luaL_reg wltest [] = {
542+ {0, 0}
543+};
544+const static struct luaL_reg wl [] = {
545+ {0, 0}
546+};
547+
548+BOOST_AUTO_TEST_CASE(test_luna_simple)
549+{
550+ const char * script1 =
551+ "print( 'test_luna simple class' )\n"
552+ "t = wl.test.Class()\n"
553+ "x = t:test()\n"
554+ "t.prop1 = 999\n"
555+ "p = t.prop1\n"
556+ "print( 'test(): ' .. x .. ' prop1: ' .. p )\n";
557+
558+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
559+ lua_State*L = L_ptr.get();
560+ luaL_openlibs(L);
561+
562+ luaL_register(L, "wl", wl);
563+ lua_pop(L, 1); // pop the table from the stack
564+ luaL_register(L, "wl.test", wltest);
565+ lua_pop(L, 1); // pop the table from the stack
566+ register_class<L_Class>(L, "test");
567+
568+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script1, strlen(script1), "testscript1"));
569+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
570+
571+}
572+BOOST_AUTO_TEST_CASE(test_luna_property_ro)
573+{
574+ const char * script1 =
575+ "print( 'test_luna readonly property' )\n"
576+ "t = wl.test.Class()\n"
577+ "p = t.propr\n"
578+ "t.propr = 1\n";
579+
580+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
581+ lua_State*L = L_ptr.get();
582+ luaL_openlibs(L);
583+
584+ luaL_register(L, "wl", wl);
585+ lua_pop(L, 1); // pop the table from the stack
586+ luaL_register(L, "wl.test", wltest);
587+ lua_pop(L, 1); // pop the table from the stack
588+ register_class<L_Class>(L, "test");
589+
590+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script1, strlen(script1), "testscript1"));
591+ // Should get LUA runtime error instead of for example crashing
592+ BOOST_CHECK_EQUAL(LUA_ERRRUN, lua_pcall(L, 0, 1, 0));
593+}
594+
595+BOOST_AUTO_TEST_CASE(test_luna_inheritance)
596+{
597+ const char * script2 =
598+ "print( 'test_luna simple inheritance' )\n"
599+ "t = wl.test.SubClass()\n"
600+ "x = t:test()\n"
601+ "p = t.prop1\n"
602+ "print( 'test(): ' .. x .. ' prop1: ' .. p )\n";
603+
604+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
605+ lua_State*L = L_ptr.get();
606+ luaL_openlibs(L);
607+
608+ luaL_register(L, "wl", wl);
609+ lua_pop(L, 1); // pop the table from the stack
610+ luaL_register(L, "wl.test", wltest);
611+ lua_pop(L, 1); // pop the table from the stack
612+
613+ // single inheritance
614+ register_class<L_SubClass>(L, "test", true);
615+ add_parent<L_SubClass, L_Class>(L);
616+ lua_pop(L, 1); // Pop the meta table
617+
618+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script2, strlen(script2), "testscript2"));
619+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
620+
621+}
622+
623+BOOST_AUTO_TEST_CASE(test_luna_virtualbase_method)
624+{
625+ const char * script3 =
626+ "print( 'test_luna virtual inheritance method call' )\n"
627+ "t = wl.test.VirtualClass()\n"
628+ "x = t:test()\n"
629+ "print( 'test(): ' .. x )\n";
630+
631+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
632+ lua_State*L = L_ptr.get();
633+ luaL_openlibs(L);
634+
635+ luaL_register(L, "wl", wl);
636+ lua_pop(L, 1); // pop the table from the stack
637+ luaL_register(L, "wl.test", wltest);
638+ lua_pop(L, 1); // pop the table from the stack
639+
640+ // virtual base class
641+ register_class<L_VirtualClass>(L, "test", true);
642+ add_parent<L_VirtualClass, L_Class>(L);
643+ lua_pop(L, 1); // Pop the meta table
644+
645+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script3, strlen(script3), "testscript3"));
646+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
647+}
648+
649+BOOST_AUTO_TEST_CASE(test_luna_virtualbase_property)
650+{
651+ const char * script4 =
652+ "print( 'test_luna virtual inheritance properties' )\n"
653+ "t = wl.test.VirtualClass()\n"
654+ "p = t.prop1\n"
655+ "print( 'prop1: ' .. p )\n";
656+
657+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
658+ lua_State*L = L_ptr.get();
659+ luaL_openlibs(L);
660+
661+ luaL_register(L, "wl", wl);
662+ lua_pop(L, 1); // pop the table from the stack
663+ luaL_register(L, "wl.test", wltest);
664+ lua_pop(L, 1); // pop the table from the stack
665+
666+ // virtual base class
667+ register_class<L_VirtualClass>(L, "test", true);
668+ add_parent<L_VirtualClass, L_Class>(L);
669+ lua_pop(L, 1); // Pop the meta table
670+
671+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script4, strlen(script4), "testscript4"));
672+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
673+}
674+
675+BOOST_AUTO_TEST_CASE(test_luna_multibase_method)
676+{
677+ const char * script5 =
678+ "print( 'test_luna virtual inheritance method call' )\n"
679+ "t = wl.test.MultiClass()\n"
680+ "x = t:test()\n"
681+ "y = t:multitest()\n"
682+ "print( 'test(): ' .. x .. ' multitest(): ' .. y)\n";
683+
684+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
685+ lua_State*L = L_ptr.get();
686+ luaL_openlibs(L);
687+
688+ luaL_register(L, "wl", wl);
689+ lua_pop(L, 1); // pop the table from the stack
690+ luaL_register(L, "wl.test", wltest);
691+ lua_pop(L, 1); // pop the table from the stack
692+
693+ // virtual base class
694+ register_class<L_MultiClass>(L, "test", true);
695+ add_parent<L_MultiClass, L_Class>(L);
696+ lua_pop(L, 1); // Pop the meta table
697+
698+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script5, strlen(script5), "testscript5"));
699+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
700+}
701+
702+BOOST_AUTO_TEST_CASE(test_luna_multibase_property_get)
703+{
704+ const char * script6 =
705+ "print( 'test_luna multiple inheritance properties' )\n"
706+ "t = wl.test.MultiClass()\n"
707+ "p1 = t.prop1\n"
708+ "p2 = t.second\n"
709+ "print( 'prop1: ' .. p1 .. ' second: ' .. p2 )\n";
710+
711+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
712+ lua_State*L = L_ptr.get();
713+ luaL_openlibs(L);
714+
715+ luaL_register(L, "wl", wl);
716+ lua_pop(L, 1); // pop the table from the stack
717+ luaL_register(L, "wl.test", wltest);
718+ lua_pop(L, 1); // pop the table from the stack
719+
720+ register_class<L_MultiClass>(L, "test", true);
721+ add_parent<L_MultiClass, L_Class>(L);
722+ lua_pop(L, 1); // Pop the meta table
723+
724+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script6, strlen(script6), "testscript6"));
725+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
726+}
727+
728+BOOST_AUTO_TEST_CASE(test_luna_multibase_property_set)
729+{
730+ const char * script6 =
731+ "print( 'test_luna multiple inheritance properties' )\n"
732+ "t = wl.test.MultiClass()\n"
733+ "t.prop1 = 123\n"
734+ "p1 = t.prop1\n"
735+ "print( 'prop1: ' .. p1 )\n";
736+
737+ shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
738+ lua_State*L = L_ptr.get();
739+ luaL_openlibs(L);
740+
741+ luaL_register(L, "wl", wl);
742+ lua_pop(L, 1); // pop the table from the stack
743+ luaL_register(L, "wl.test", wltest);
744+ lua_pop(L, 1); // pop the table from the stack
745+
746+ register_class<L_MultiClass>(L, "test", true);
747+ add_parent<L_MultiClass, L_Class>(L);
748+ lua_pop(L, 1); // Pop the meta table
749+
750+ BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script6, strlen(script6), "testscript6"));
751+ BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
752+}

Subscribers

People subscribed via source and target branches

to status/vote changes: