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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2010-05-21 09:04:50 +0000
+++ CMakeLists.txt 2010-07-23 17:57:50 +0000
@@ -104,11 +104,13 @@
104set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})104set (CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
105105
106set (BUILD_SHARED_LIBS OFF)106set (BUILD_SHARED_LIBS OFF)
107# we only include Boost Headers to the main executable, no libraries
108# unit_test_framework is for testing only
109set (Boost_FIND_COMPONENTS unit_test_framework)
107set (Boost_USE_STATIC_LIBS ON)110set (Boost_USE_STATIC_LIBS ON)
108set (Boost_USE_MULTITHREADED ON)111set (Boost_USE_MULTITHREADED ON)
109find_package(Boost 1.35.0 REQUIRED)112set (Boost_DETAILED_FAILURE_MSG ON)
110include_directories(${Boost_INCLUDE_DIR})113find_package(Boost 1.35.0 COMPONENTS unit_test_framework REQUIRED)
111target_link_libraries(widelands ${Boost_LIBRARIES})
112114
113set (PARAMETER_COMPILERFLAG_OLDSTYLECAST_EXTENDED "-Wold-style-cast -isystem ${Boost_INCLUDE_DIR}")115set (PARAMETER_COMPILERFLAG_OLDSTYLECAST_EXTENDED "-Wold-style-cast -isystem ${Boost_INCLUDE_DIR}")
114set (PARAMETER_COMPILERFLAG_OLDSTYLECAST "-Wold-style-cast")116set (PARAMETER_COMPILERFLAG_OLDSTYLECAST "-Wold-style-cast")
@@ -176,6 +178,9 @@
176 add_definitions( -Dssize_t=size_t )178 add_definitions( -Dssize_t=size_t )
177 add_definitions( -Dmkdir=_mkdir )179 add_definitions( -Dmkdir=_mkdir )
178180
181 include_directories(${Boost_INCLUDE_DIR})
182 # Automatic linking for boost requires setting lib dir
183 LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
179184
180 find_library(INTL_LIBRARY NAMES intl libintl)185 find_library(INTL_LIBRARY NAMES intl libintl)
181186
@@ -285,6 +290,8 @@
285 COMPONENT CoreVersionFile290 COMPONENT CoreVersionFile
286)291)
287292
293enable_testing()
294
288include_directories(src ${CMAKE_CURRENT_BINARY_DIR}/src)295include_directories(src ${CMAKE_CURRENT_BINARY_DIR}/src)
289296
290include(CheckIncludeFile)297include(CheckIncludeFile)
291298
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2010-05-21 09:04:50 +0000
+++ src/CMakeLists.txt 2010-07-23 17:57:50 +0000
@@ -26,6 +26,8 @@
26file(GLOB_RECURSE WL_SRCS_ALL *.cc)26file(GLOB_RECURSE WL_SRCS_ALL *.cc)
2727
28file(GLOB WL_MAIN_SRCS *.cc)28file(GLOB WL_MAIN_SRCS *.cc)
29file(GLOB WL_MAIN_CC main.cc)
30list(REMOVE_ITEM WL_MAIN_SRCS ${WL_MAIN_CC})
29add_library(widelands_main ${WL_MAIN_SRCS})31add_library(widelands_main ${WL_MAIN_SRCS})
3032
31#file (GLOB WL_SRCS *.cc economy/*.cc scripting/*.cc)33#file (GLOB WL_SRCS *.cc economy/*.cc scripting/*.cc)
3234
=== modified file 'src/scripting/CMakeLists.txt'
--- src/scripting/CMakeLists.txt 2010-02-05 01:13:20 +0000
+++ src/scripting/CMakeLists.txt 2010-07-23 17:57:50 +0000
@@ -4,3 +4,9 @@
44
5target_link_libraries(widelands_scripting ${LUA_LIBRARIES})5target_link_libraries(widelands_scripting ${LUA_LIBRARIES})
66
7# Build tests only if unit test framework is available.
8if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
9 add_subdirectory(test)
10else()
11 message("Excluded unit tests for scripting because boost unit_test_framework was not found.")
12endif()
713
=== modified file 'src/scripting/luna.h'
--- src/scripting/luna.h 2010-03-21 18:12:27 +0000
+++ src/scripting/luna.h 2010-07-23 17:57:50 +0000
@@ -110,7 +110,7 @@
110110
111 m_create_metatable_for_class<T>(L);111 m_create_metatable_for_class<T>(L);
112112
113 m_register_properties_in_metatable<T>(L);113 m_register_properties_in_metatable<T,T>(L);
114 m_register_methods_in_metatable<T, T>(L);114 m_register_methods_in_metatable<T, T>(L);
115115
116 if(!return_metatable)116 if(!return_metatable)
@@ -124,7 +124,7 @@
124template <class T, class PT>124template <class T, class PT>
125void add_parent(lua_State * L)125void add_parent(lua_State * L)
126{126{
127 m_register_properties_in_metatable<PT>(L);127 m_register_properties_in_metatable<T,PT>(L);
128 m_register_methods_in_metatable<T, PT>(L);128 m_register_methods_in_metatable<T, PT>(L);
129}129}
130130
131131
=== modified file 'src/scripting/luna_impl.h'
--- src/scripting/luna_impl.h 2010-03-05 14:32:47 +0000
+++ src/scripting/luna_impl.h 2010-07-23 17:57:50 +0000
@@ -54,22 +54,45 @@
54template <class T> T * * get_user_class(lua_State * const L, int narg);54template <class T> T * * get_user_class(lua_State * const L, int narg);
5555
56template <class T>56template <class T>
57PropertyType<T> const * m_lookup_property_in_metatable(lua_State * const L) {57int m_dispatch_property_in_metatable(lua_State * const L, bool setter) {
58 // stack: table name58 // stack for getter: table name
5959 // stack for setter: table name value
60 int ret = 0;
60 // Look up the key in the metatable61 // Look up the key in the metatable
61 lua_getmetatable(L, 1); // table name mt62 lua_getmetatable(L, 1); // table name <value> mt
62 lua_pushvalue (L, 2); // table name mt name63 lua_pushvalue (L, 2); // table name <value> mt name
63 lua_rawget (L, -2); // table name mt mt_val64 lua_rawget (L, -2); // table name <value> mt mt_val
6465 lua_remove(L, -2); // table name <value> mt_val
65 const PropertyType<T> * rv = 0;66 if (lua_istable(L, -1))
6667 {
67 if (lua_islightuserdata(L, -1))68 // dispatcher
68 rv = static_cast<const PropertyType<T> *>(lua_touserdata(L, -1));69
6970 lua_pushstring(L, "dispatcher"); // table name <value> mt_val "dispatcher"
70 lua_remove(L, -2); // table name mt_val71 lua_gettable(L, -2); // table name <value> mt_val dispatcher_val
7172 if (!lua_iscfunction(L, -1))
72 return rv;73 {
74 lua_pop(L, 2); // table name <value>
75 return report_error(L, "invalid property without dispatcher function");
76 }
77 lua_CFunction dispatcher = lua_tocfunction(L, -1);
78 lua_pop(L, 1); // table name <value> mt_val
79
80 // get property method to stack
81 lua_pushstring(L, setter ? "setter" : "getter");
82 lua_gettable(L, -2); // table name <value> mt_val getter_val/setter_val
83 lua_remove(L, -2); // table name <value> getter_val/setter_val
84 // dispatcher pops off getter/setter and returns whatever get/set property functions returns
85 ret = dispatcher(L); // table name value
86 } else {
87 if (setter) {
88 lua_rawset(L, 1);
89 } else {
90 // leave the value to stack
91 ret = 1;
92 }
93 }
94
95 return ret;
73}96}
7497
75/**98/**
@@ -94,42 +117,43 @@
94 }117 }
95 lua_pop(L, 1); // table name118 lua_pop(L, 1); // table name
96119
97 const PropertyType<T>* list = m_lookup_property_in_metatable<T>(L);120 return m_dispatch_property_in_metatable<T>(L, false);
98 // stack: table name list
99
100 // Not in metatable?, return it
101 if (!list) {
102 return 1;
103 }
104 lua_pop(L, 1); // table name
105
106 T * * const obj = get_user_class<T>(L, 1);
107 // table name
108
109 // push value on top of the stack for the method call
110 return ((*obj)->*(list->getter))(L);
111}121}
112122
113template <class T>123template <class T>
114int m_property_setter(lua_State * const L) {124int m_property_setter(lua_State * const L) {
115 // stack: table name value125 // stack: table name value
116 PropertyType<T> const * list = m_lookup_property_in_metatable<T>(L);126 return m_dispatch_property_in_metatable<T>(L, true);
117 lua_pop(L, 1); // table name value127}
118 // table name value rv128
119129/**
120 if (!list) {130 * This function calls a lua method in our given object. we can already be
121 // Not in metatable?131 * sure that the called method is registered in our metatable, but we have to
122 // do a normal set on the table132 * make sure that the method is called correctly: obj.method(obj) or
123 lua_rawset(L, 1);133 * obj:method(). We also check that we are not called with another object
124 return 0;134 */
135template <class T, class PT>
136int m_property_dispatch(lua_State * const L) {
137 // Check for invalid: obj.method()
138 int const n = lua_gettop(L);
139 if (!n)
140 return report_error(L, "Property needs at least the object as argument!");
141
142 // Check for invalid: obj.method(plainOldDatatype)
143 luaL_checktype(L, 1, LUA_TTABLE);
144
145 typedef int (PT::* const * ConstMethodPtr)(lua_State *);
146 ConstMethodPtr pfunc = reinterpret_cast<ConstMethodPtr>(lua_touserdata(L, -1));
147 lua_pop(L, 1);
148
149 T * * const obj = get_user_class<T>(L, 1);
150
151 if (!*pfunc)
152 {
153 return report_error(L, "The property is read-only!\n");
125 }154 }
126155 // Call it on our instance
127 T * * const obj = get_user_class<T>(L, 1);156 return ((*obj)->*(*pfunc))(L);
128
129 if (list->setter == 0)
130 return report_error(L, "The property '%s' is read-only!\n", list->name);
131
132 return ((*obj)->*(list->setter))(L);
133}157}
134158
135/**159/**
@@ -138,7 +162,7 @@
138 * make sure that the method is called correctly: obj.method(obj) or162 * make sure that the method is called correctly: obj.method(obj) or
139 * obj:method(). We also check that we are not called with another object163 * obj:method(). We also check that we are not called with another object
140 */164 */
141template <class T>165template <class T, class PT>
142int m_method_dispatch(lua_State * const L) {166int m_method_dispatch(lua_State * const L) {
143 // Check for invalid: obj.method()167 // Check for invalid: obj.method()
144 int const n = lua_gettop(L);168 int const n = lua_gettop(L);
@@ -149,7 +173,7 @@
149 luaL_checktype(L, 1, LUA_TTABLE);173 luaL_checktype(L, 1, LUA_TTABLE);
150174
151 // Get the method pointer from the closure175 // Get the method pointer from the closure
152 typedef int (T::* const * ConstMethod)(lua_State *);176 typedef int (PT::* const * ConstMethod)(lua_State *);
153 ConstMethod func = reinterpret_cast<ConstMethod>177 ConstMethod func = reinterpret_cast<ConstMethod>
154 (lua_touserdata(L, lua_upvalueindex(1)));178 (lua_touserdata(L, lua_upvalueindex(1)));
155179
@@ -250,17 +274,33 @@
250 return metatable;274 return metatable;
251}275}
252276
253template <class T>277template <class T, class PT>
254void m_register_properties_in_metatable278void m_register_properties_in_metatable
255 (lua_State * const L)279 (lua_State * const L)
256{280{
257 for (int i = 0; T::Properties[i].name; ++i) {281 for (int i = 0; PT::Properties[i].name; ++i) {
258 // metatable[prop_name] = Pointer to getter setter282 // metatable[prop_name] = Pointer to getter setter
259 lua_pushstring(L, T::Properties[i].name);283 lua_pushstring(L, PT::Properties[i].name);
260 lua_pushlightuserdata284 lua_newtable(L);
261 (L,285 lua_pushstring(L, "getter");
262 const_cast<void *>286 lua_pushlightuserdata
263 (reinterpret_cast<void const *>(&T::Properties[i])));287 (L,
288 const_cast<void *>
289 (reinterpret_cast<const void *>
290 (&(PT::Properties[i].getter))));
291 lua_settable(L, -3);
292 lua_pushstring(L, "setter");
293 lua_pushlightuserdata
294 (L,
295 const_cast<void *>
296 (reinterpret_cast<const void *>
297 (&(PT::Properties[i].setter))));
298 lua_settable(L, -3);
299
300 lua_pushstring(L, "dispatcher");
301 lua_pushcfunction(L, &(m_property_dispatch<T, PT>));
302 lua_settable(L, -3);
303
264 lua_settable(L, -3); // Metatable is directly before our pushed stuff304 lua_settable(L, -3); // Metatable is directly before our pushed stuff
265 }305 }
266}306}
@@ -279,7 +319,7 @@
279 (L,319 (L,
280 const_cast<void *>320 const_cast<void *>
281 (reinterpret_cast<void const *>(&PT::Methods[i].method)));321 (reinterpret_cast<void const *>(&PT::Methods[i].method)));
282 lua_pushcclosure(L, &(m_method_dispatch<T>), 1);322 lua_pushcclosure(L, &(m_method_dispatch<T, PT>), 1);
283 lua_settable(L, -3); // Metatable is directly before our pushed stuff323 lua_settable(L, -3); // Metatable is directly before our pushed stuff
284 }324 }
285}325}
286326
=== modified file 'src/scripting/scripting.cc'
--- src/scripting/scripting.cc 2010-05-23 19:00:49 +0000
+++ src/scripting/scripting.cc 2010-07-23 17:57:50 +0000
@@ -225,6 +225,8 @@
225 }225 }
226226
227 // Push the instance of this class into the registry227 // Push the instance of this class into the registry
228 // MSVC2008 requires that stored and retrieved types are
229 // same, so use LuaInterface* on both sides.
228 lua_pushlightuserdata(m_L, reinterpret_cast<void*>(dynamic_cast<LuaInterface*>(this)));230 lua_pushlightuserdata(m_L, reinterpret_cast<void*>(dynamic_cast<LuaInterface*>(this)));
229 lua_setfield(m_L, LUA_REGISTRYINDEX, "lua_interface");231 lua_setfield(m_L, LUA_REGISTRYINDEX, "lua_interface");
230232
231233
=== added file 'src/scripting/test/CMakeLists.txt'
--- src/scripting/test/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/scripting/test/CMakeLists.txt 2010-07-23 17:57:50 +0000
@@ -0,0 +1,51 @@
1file(GLOB WL_SCRIPTING_TEST_SRCS *.cc)
2
3add_executable(test_widelands_scripting ${WL_SCRIPTING_TEST_SRCS} ../../build_info.cc)
4
5set(SDL_LIBRARY_NOMAIN ${SDL_LIBRARY})
6list(REMOVE_ITEM SDL_LIBRARY_NOMAIN ${SDLMAIN_LIBRARY})
7
8target_link_libraries(test_widelands_scripting
9 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
10 widelands_io_filesystem widelands_editor widelands_editor_tools widelands_editor_ui_menus
11 ${Boost_LIBRARIES}
12 ${PNG_LIBRARY}
13 ${ZLIB_LIBRARY}
14 ${JPEG_LIBRARY}
15 ${TIFF_LIBRARY}
16 ${SDL_LIBRARY_NOMAIN}
17 ${SDLIMAGE_LIBRARY}
18 ${SDLMIXER_LIBRARY}
19 ${SDLNET_LIBRARY}
20 ${SDLTTF_LIBRARY}
21 ${LUA_LIBRARY}
22 ${SDLGFX_LIBRARY}
23 )
24if (GGZ_CORE_FOUND)
25 target_link_libraries(test_widelands_scripting ${GGZ_CORE_LIBRARY})
26endif (GGZ_CORE_FOUND)
27
28if (APPLE)
29 target_link_libraries(test_widelands_scripting ${INTL_LIBRARY})
30endif (APPLE)
31
32if (WIN32)
33if (DEFINED MSVC)
34 target_link_libraries(test_widelands_scripting ${INTL_LIBRARY})
35 target_link_libraries(test_widelands_scripting ws2_32)
36 #GGZ on MSVC using 3rdparty bundle needs expat library
37 #if expat is not found, then 3rdparty bundle is not in use, so just continue.
38 if (GGZ_CORE_FOUND)
39 find_library(EXPAT_LIBRARY libexpat)
40 if (EXPAT_LIBRARY)
41 target_link_libraries(test_widelands_scripting ${EXPAT_LIBRARY})
42 endif (EXPAT_LIBRARY)
43 endif (GGZ_CORE_FOUND)
44else (DEFINED MSVC)
45 target_link_libraries(test_widelands_scripting intl)
46 target_link_libraries(test_widelands_scripting wsock32)
47endif (DEFINED MSVC)
48endif (WIN32)
49
50
51add_test(test_widelands_scripting test_widelands_scripting)
0\ No newline at end of file52\ No newline at end of file
153
=== added file 'src/scripting/test/scripting_test_main.cc'
--- src/scripting/test/scripting_test_main.cc 1970-01-01 00:00:00 +0000
+++ src/scripting/test/scripting_test_main.cc 2010-07-23 17:57:50 +0000
@@ -0,0 +1,23 @@
1/*
2 * Copyright (C) 2007-2008 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20#define BOOST_AUTO_TEST_MAIN
21#define BOOST_TEST_MODULE Scripting
22#include <boost/test/unit_test.hpp>
23
024
=== added file 'src/scripting/test/test_luna.cc'
--- src/scripting/test/test_luna.cc 1970-01-01 00:00:00 +0000
+++ src/scripting/test/test_luna.cc 2010-07-23 17:57:50 +0000
@@ -0,0 +1,354 @@
1#include <exception>
2#include <boost/test/unit_test.hpp>
3#include <boost/shared_ptr.hpp>
4#include <lua.hpp>
5#include "scripting/luna.h"
6
7#include "scripting/luna_impl.h"
8
9using namespace boost;
10
11#ifndef BEGIN_LUNA_PROPERTIES
12#define BEGIN_LUNA_PROPERTIES(klass) \
13 const PropertyType<klass> klass::Properties[] = {
14
15#define END_LUNA_PROPERTIES() {0, 0, 0}};
16#endif
17
18class L_Class : public LunaClass
19{
20 int x;
21 int prop;
22public:
23 LUNA_CLASS_HEAD(L_Class);
24 const char * get_modulename() {return "test";}
25 L_Class() :x(123), prop(246) {}
26 virtual ~L_Class() {}
27 L_Class(lua_State *L) :x(124), prop(248) {}
28 virtual int test(lua_State *L)
29 {
30 lua_pushuint32(L, x);
31 return 1;
32 }
33 virtual int get_prop1(lua_State*L)
34 {
35 lua_pushint32(L, prop);
36 return 1;
37 }
38 virtual int get_propr(lua_State*L)
39 {
40 lua_pushint32(L, 0);
41 return 1;
42 }
43 virtual int set_prop1(lua_State*L)
44 {
45 prop = lua_tointeger(L, -1);
46 return 0;
47 }
48 virtual void __persist(lua_State * L) {}
49 virtual void __unpersist(lua_State * L) {}
50};
51const char L_Class::className[] = "Class";
52const MethodType<L_Class> L_Class::Methods[] = {
53 METHOD(L_Class, test),
54 {0, 0},
55};
56BEGIN_LUNA_PROPERTIES(L_Class)
57 PROP_RO(L_Class, propr),
58 PROP_RW(L_Class, prop1),
59END_LUNA_PROPERTIES()
60
61class L_SubClass : public L_Class
62{
63 int y;
64public:
65 LUNA_CLASS_HEAD(L_SubClass);
66 L_SubClass() :y(1230) {}
67 L_SubClass(lua_State *L) : L_Class(L), y(1240) {}
68 virtual int subtest(lua_State *L)
69 {
70 lua_pushuint32(L, y);
71 return 1;
72 }
73 virtual void __persist(lua_State * L) {}
74 virtual void __unpersist(lua_State * L) {}
75};
76const char L_SubClass::className[] = "SubClass";
77const MethodType<L_SubClass> L_SubClass::Methods[] = {
78 METHOD(L_SubClass, subtest),
79 {0, 0},
80};
81BEGIN_LUNA_PROPERTIES(L_SubClass)
82END_LUNA_PROPERTIES()
83
84class L_VirtualClass : public virtual L_Class
85{
86 int z;
87public:
88 LUNA_CLASS_HEAD(L_VirtualClass);
89 L_VirtualClass() :z(12300) {}
90 L_VirtualClass(lua_State *L) : L_Class(L), z(12400) {}
91 virtual int virtualtest(lua_State *L)
92 {
93 lua_pushuint32(L, z);
94 return 1;
95 }
96 virtual void __persist(lua_State * L) {}
97 virtual void __unpersist(lua_State * L) {}
98};
99const char L_VirtualClass::className[] = "VirtualClass";
100const MethodType<L_VirtualClass> L_VirtualClass::Methods[] = {
101 METHOD(L_VirtualClass, virtualtest),
102 {0, 0},
103};
104BEGIN_LUNA_PROPERTIES(L_VirtualClass)
105END_LUNA_PROPERTIES()
106
107class L_Second
108{
109public:
110 int get_second(lua_State *L) {lua_pushstring(L, "second"); return 1;}
111 virtual int multitest(lua_State *L)
112 {
113 lua_pushstring(L, "secondfunc");
114 return 1;
115 }
116};
117
118class L_MultiClass : public L_Class, public L_Second
119{
120 int z;
121public:
122 LUNA_CLASS_HEAD(L_MultiClass );
123 L_MultiClass () :z(12300) {}
124 L_MultiClass (lua_State *L) : L_Class(L), z(12400) {}
125 virtual int virtualtest(lua_State *L)
126 {
127 lua_pushuint32(L, z);
128 return 1;
129 }
130 virtual void __persist(lua_State * L) {}
131 virtual void __unpersist(lua_State * L) {}
132};
133const char L_MultiClass::className[] = "MultiClass";
134const MethodType<L_MultiClass> L_MultiClass::Methods[] = {
135 METHOD(L_MultiClass, virtualtest),
136 METHOD(L_Second, multitest),
137 {0, 0},
138};
139BEGIN_LUNA_PROPERTIES(L_MultiClass)
140 PROP_RO(L_MultiClass, second),
141END_LUNA_PROPERTIES()
142
143const static struct luaL_reg wltest [] = {
144 {0, 0}
145};
146const static struct luaL_reg wl [] = {
147 {0, 0}
148};
149
150BOOST_AUTO_TEST_CASE(test_luna_simple)
151{
152 const char * script1 =
153 "print( 'test_luna simple class' )\n"
154 "t = wl.test.Class()\n"
155 "x = t:test()\n"
156 "t.prop1 = 999\n"
157 "p = t.prop1\n"
158 "print( 'test(): ' .. x .. ' prop1: ' .. p )\n";
159
160 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
161 lua_State*L = L_ptr.get();
162 luaL_openlibs(L);
163
164 luaL_register(L, "wl", wl);
165 lua_pop(L, 1); // pop the table from the stack
166 luaL_register(L, "wl.test", wltest);
167 lua_pop(L, 1); // pop the table from the stack
168 register_class<L_Class>(L, "test");
169
170 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script1, strlen(script1), "testscript1"));
171 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
172
173}
174BOOST_AUTO_TEST_CASE(test_luna_property_ro)
175{
176 const char * script1 =
177 "print( 'test_luna readonly property' )\n"
178 "t = wl.test.Class()\n"
179 "p = t.propr\n"
180 "t.propr = 1\n";
181
182 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
183 lua_State*L = L_ptr.get();
184 luaL_openlibs(L);
185
186 luaL_register(L, "wl", wl);
187 lua_pop(L, 1); // pop the table from the stack
188 luaL_register(L, "wl.test", wltest);
189 lua_pop(L, 1); // pop the table from the stack
190 register_class<L_Class>(L, "test");
191
192 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script1, strlen(script1), "testscript1"));
193 // Should get LUA runtime error instead of for example crashing
194 BOOST_CHECK_EQUAL(LUA_ERRRUN, lua_pcall(L, 0, 1, 0));
195}
196
197BOOST_AUTO_TEST_CASE(test_luna_inheritance)
198{
199 const char * script2 =
200 "print( 'test_luna simple inheritance' )\n"
201 "t = wl.test.SubClass()\n"
202 "x = t:test()\n"
203 "p = t.prop1\n"
204 "print( 'test(): ' .. x .. ' prop1: ' .. p )\n";
205
206 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
207 lua_State*L = L_ptr.get();
208 luaL_openlibs(L);
209
210 luaL_register(L, "wl", wl);
211 lua_pop(L, 1); // pop the table from the stack
212 luaL_register(L, "wl.test", wltest);
213 lua_pop(L, 1); // pop the table from the stack
214
215 // single inheritance
216 register_class<L_SubClass>(L, "test", true);
217 add_parent<L_SubClass, L_Class>(L);
218 lua_pop(L, 1); // Pop the meta table
219
220 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script2, strlen(script2), "testscript2"));
221 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
222
223}
224
225BOOST_AUTO_TEST_CASE(test_luna_virtualbase_method)
226{
227 const char * script3 =
228 "print( 'test_luna virtual inheritance method call' )\n"
229 "t = wl.test.VirtualClass()\n"
230 "x = t:test()\n"
231 "print( 'test(): ' .. x )\n";
232
233 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
234 lua_State*L = L_ptr.get();
235 luaL_openlibs(L);
236
237 luaL_register(L, "wl", wl);
238 lua_pop(L, 1); // pop the table from the stack
239 luaL_register(L, "wl.test", wltest);
240 lua_pop(L, 1); // pop the table from the stack
241
242 // virtual base class
243 register_class<L_VirtualClass>(L, "test", true);
244 add_parent<L_VirtualClass, L_Class>(L);
245 lua_pop(L, 1); // Pop the meta table
246
247 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script3, strlen(script3), "testscript3"));
248 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
249}
250
251BOOST_AUTO_TEST_CASE(test_luna_virtualbase_property)
252{
253 const char * script4 =
254 "print( 'test_luna virtual inheritance properties' )\n"
255 "t = wl.test.VirtualClass()\n"
256 "p = t.prop1\n"
257 "print( 'prop1: ' .. p )\n";
258
259 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
260 lua_State*L = L_ptr.get();
261 luaL_openlibs(L);
262
263 luaL_register(L, "wl", wl);
264 lua_pop(L, 1); // pop the table from the stack
265 luaL_register(L, "wl.test", wltest);
266 lua_pop(L, 1); // pop the table from the stack
267
268 // virtual base class
269 register_class<L_VirtualClass>(L, "test", true);
270 add_parent<L_VirtualClass, L_Class>(L);
271 lua_pop(L, 1); // Pop the meta table
272
273 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script4, strlen(script4), "testscript4"));
274 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
275}
276
277BOOST_AUTO_TEST_CASE(test_luna_multibase_method)
278{
279 const char * script5 =
280 "print( 'test_luna virtual inheritance method call' )\n"
281 "t = wl.test.MultiClass()\n"
282 "x = t:test()\n"
283 "y = t:multitest()\n"
284 "print( 'test(): ' .. x .. ' multitest(): ' .. y)\n";
285
286 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
287 lua_State*L = L_ptr.get();
288 luaL_openlibs(L);
289
290 luaL_register(L, "wl", wl);
291 lua_pop(L, 1); // pop the table from the stack
292 luaL_register(L, "wl.test", wltest);
293 lua_pop(L, 1); // pop the table from the stack
294
295 // virtual base class
296 register_class<L_MultiClass>(L, "test", true);
297 add_parent<L_MultiClass, L_Class>(L);
298 lua_pop(L, 1); // Pop the meta table
299
300 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script5, strlen(script5), "testscript5"));
301 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
302}
303
304BOOST_AUTO_TEST_CASE(test_luna_multibase_property_get)
305{
306 const char * script6 =
307 "print( 'test_luna multiple inheritance properties' )\n"
308 "t = wl.test.MultiClass()\n"
309 "p1 = t.prop1\n"
310 "p2 = t.second\n"
311 "print( 'prop1: ' .. p1 .. ' second: ' .. p2 )\n";
312
313 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
314 lua_State*L = L_ptr.get();
315 luaL_openlibs(L);
316
317 luaL_register(L, "wl", wl);
318 lua_pop(L, 1); // pop the table from the stack
319 luaL_register(L, "wl.test", wltest);
320 lua_pop(L, 1); // pop the table from the stack
321
322 register_class<L_MultiClass>(L, "test", true);
323 add_parent<L_MultiClass, L_Class>(L);
324 lua_pop(L, 1); // Pop the meta table
325
326 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script6, strlen(script6), "testscript6"));
327 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
328}
329
330BOOST_AUTO_TEST_CASE(test_luna_multibase_property_set)
331{
332 const char * script6 =
333 "print( 'test_luna multiple inheritance properties' )\n"
334 "t = wl.test.MultiClass()\n"
335 "t.prop1 = 123\n"
336 "p1 = t.prop1\n"
337 "print( 'prop1: ' .. p1 )\n";
338
339 shared_ptr<lua_State> L_ptr(lua_open(),&lua_close);
340 lua_State*L = L_ptr.get();
341 luaL_openlibs(L);
342
343 luaL_register(L, "wl", wl);
344 lua_pop(L, 1); // pop the table from the stack
345 luaL_register(L, "wl.test", wltest);
346 lua_pop(L, 1); // pop the table from the stack
347
348 register_class<L_MultiClass>(L, "test", true);
349 add_parent<L_MultiClass, L_Class>(L);
350 lua_pop(L, 1); // Pop the meta table
351
352 BOOST_CHECK_EQUAL(0, luaL_loadbuffer(L, script6, strlen(script6), "testscript6"));
353 BOOST_CHECK_EQUAL(0, lua_pcall(L, 0, 1, 0));
354}

Subscribers

People subscribed via source and target branches

to status/vote changes: