]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/cppbind/cppbind_test.cxx
nasal::Ghost: remove bogus warning.
[simgear.git] / simgear / nasal / cppbind / cppbind_test.cxx
1 #include <simgear/math/SGMath.hxx>
2
3 #include "Ghost.hxx"
4 #include "NasalHash.hxx"
5 #include "NasalString.hxx"
6 #include <simgear/structure/map.hxx>
7
8 #include <boost/shared_ptr.hpp>
9 #include <boost/weak_ptr.hpp>
10
11 #include <cstring>
12 #include <iostream>
13
14 #define VERIFY(a) \
15   if( !(a) ) \
16   { \
17     std::cerr << "failed: line " << __LINE__ << ": " << #a << std::endl; \
18     return 1; \
19   }
20
21 enum MyEnum
22 {
23   ENUM_FIRST,
24   ENUM_ANOTHER,
25   ENUM_LAST
26 };
27 struct Base
28 {
29   naRef member(const nasal::CallContext&) { return naNil(); }
30   virtual ~Base(){};
31
32   std::string getString() const { return ""; }
33   void setString(const std::string&) {}
34   void constVoidFunc() const {}
35   size_t test1Arg(const std::string& str) const { return str.length(); }
36   bool test2Args(const std::string& s, bool c) { return c && s.empty(); }
37
38   std::string var;
39   const std::string& getVar() const { return var; }
40   void setVar(const std::string v) { var = v; }
41
42   unsigned long getThis() const { return (unsigned long)this; }
43 };
44
45 void baseVoidFunc(Base& b) {}
46 void baseConstVoidFunc(const Base& b) {}
47 size_t baseFunc2Args(Base& b, int x, const std::string& s) { return x + s.size(); }
48 std::string testPtr(Base& b) { return b.getString(); }
49 void baseFuncCallContext(const Base&, const nasal::CallContext&) {}
50
51 struct Derived:
52   public Base
53 {
54   int _x;
55   int getX() const { return _x; }
56   void setX(int x) { _x = x; }
57 };
58 struct DoubleDerived:
59   public Derived
60 {
61
62 };
63
64 typedef boost::shared_ptr<Base> BasePtr;
65 typedef std::vector<BasePtr> BaseVec;
66
67 struct DoubleDerived2:
68   public Derived
69 {
70   const BasePtr& getBase() const{return _base;}
71   BasePtr _base;
72   BaseVec doSomeBaseWork(const BaseVec& v) { return v; }
73 };
74
75 class SGReferenceBasedClass:
76   public SGReferenced
77 {
78
79 };
80
81 typedef boost::shared_ptr<Derived> DerivedPtr;
82 typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
83 typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
84 typedef SGSharedPtr<SGReferenceBasedClass> SGRefBasedPtr;
85
86 typedef boost::weak_ptr<Derived> DerivedWeakPtr;
87
88 naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); }
89 naRef f_derivedGetX(naContext c, const Derived& d)
90 {
91   return nasal::to_nasal(c, d.getX());
92 }
93 naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
94
95 int main(int argc, char* argv[])
96 {
97   naContext c = naNewContext();
98   naRef r;
99
100   using namespace nasal;
101
102   r = to_nasal(c, ENUM_ANOTHER);
103   VERIFY( from_nasal<int>(c, r) == ENUM_ANOTHER );
104
105   r = to_nasal(c, "Test");
106   VERIFY( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
107   VERIFY( from_nasal<std::string>(c, r) == "Test" );
108
109   r = to_nasal(c, std::string("Test"));
110   VERIFY( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
111   VERIFY( from_nasal<std::string>(c, r) == "Test" );
112
113   r = to_nasal(c, 42);
114   VERIFY( naNumValue(r).num == 42 );
115   VERIFY( from_nasal<int>(c, r) == 42 );
116
117   r = to_nasal(c, 4.2f);
118   VERIFY( naNumValue(r).num == 4.2f );
119   VERIFY( from_nasal<float>(c, r) == 4.2f );
120
121   float test_data[3] = {0, 4, 2};
122   r = to_nasal(c, test_data);
123
124   SGVec2f vec(0,2);
125   r = to_nasal(c, vec);
126   VERIFY( from_nasal<SGVec2f>(c, r) == vec );
127
128   std::vector<int> std_vec;
129   r = to_nasal(c, std_vec);
130
131   r = to_nasal(c, "string");
132   try
133   {
134     from_nasal<int>(c, r);
135
136     std::cerr << "failed: Expected bad_nasal_cast to be thrown" << std::endl;
137     return 1;
138   }
139   catch(nasal::bad_nasal_cast&)
140   {}
141
142   Hash hash(c);
143   hash.set("vec", r);
144   hash.set("vec2", vec);
145   hash.set("name", "my-name");
146   hash.set("string", std::string("blub"));
147   hash.set("func", &f_freeFunction);
148
149   r = to_nasal(c, hash);
150   VERIFY( naIsHash(r) );
151
152   VERIFY( hash.get<std::string>("name") == "my-name" );
153   VERIFY( naIsString(hash.get("name")) );
154
155   Hash mod = hash.createHash("mod");
156   mod.set("parent", hash);
157
158
159   // 'func' is a C++ function registered to Nasal and now converted back to C++
160   boost::function<int (int)> f = hash.get<int (int)>("func");
161   VERIFY( f );
162   VERIFY( f(3) == 3 );
163
164   boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
165   VERIFY( fs );
166   VERIFY( fs(14) == "14" );
167
168   typedef boost::function<void (int)> FuncVoidInt;
169   FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
170   VERIFY( fvi );
171   fvi(123);
172
173   typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
174   FuncMultiArg fma = hash.get<FuncMultiArg>("func");
175   VERIFY( fma );
176   VERIFY( fma("test", 3, .5) == "test" );
177
178   typedef boost::function<naRef (naRef)> naRefMemFunc;
179   naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
180   VERIFY( fmem );
181   naRef ret = fmem(hash.get_naRef()),
182         hash_ref = hash.get_naRef();
183   VERIFY( memcmp(&ret, &hash_ref, sizeof(naRef)) == 0 );
184
185   // Check if nasal::Me gets passed as self/me and remaining arguments are
186   // passed on to function
187   typedef boost::function<int (Me, int)> MeIntFunc;
188   MeIntFunc fmeint = hash.get<MeIntFunc>("func");
189   VERIFY( fmeint(naNil(), 5) == 5 );
190
191   //----------------------------------------------------------------------------
192   // Test exposing classes to Nasal
193   //----------------------------------------------------------------------------
194
195   Ghost<BasePtr>::init("BasePtr")
196     .method("member", &Base::member)
197     .method("strlen", &Base::test1Arg)
198     .member("str", &Base::getString, &Base::setString)
199     .method("str_m", &Base::getString)
200     .method("void", &Base::constVoidFunc)
201     .member("var_r", &Base::getVar)
202     .member("var_w", &Base::setVar)
203     .member("var", &Base::getVar, &Base::setVar)
204     .method("void", &baseVoidFunc)
205     .method("void_c", &baseConstVoidFunc)
206     .method("int2args", &baseFunc2Args)
207     .method("bool2args", &Base::test2Args)
208     .method("str_ptr", &testPtr)
209     .method("this", &Base::getThis);
210   Ghost<DerivedPtr>::init("DerivedPtr")
211     .bases<BasePtr>()
212     .member("x", &Derived::getX, &Derived::setX)
213     .member("x_alternate", &f_derivedGetX)
214     .method("free_fn", &derivedFreeMember)
215     .method("free_member", &derivedFreeMember)
216     .method("baseDoIt", &baseFuncCallContext);
217   Ghost<DoubleDerivedPtr>::init("DoubleDerivedPtr")
218     .bases<DerivedPtr>();
219   Ghost<DoubleDerived2Ptr>::init("DoubleDerived2Ptr")
220     .bases< Ghost<DerivedPtr> >()
221     .member("base", &DoubleDerived2::getBase)
222     .method("doIt", &DoubleDerived2::doSomeBaseWork);
223
224   Ghost<DerivedWeakPtr>::init("DerivedWeakPtr");
225   Ghost<SGRefBasedPtr>::init("SGRefBasedPtr");
226
227   VERIFY( Ghost<BasePtr>::isInit() );
228   nasal::to_nasal(c, DoubleDerived2Ptr());
229
230   BasePtr d( new Derived );
231   naRef derived = to_nasal(c, d);
232   VERIFY( naIsGhost(derived) );
233   VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name );
234
235   // Get member function from ghost...
236   naRef thisGetter = naNil();
237   VERIFY( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
238   VERIFY( naIsFunc(thisGetter) );
239
240   // ...and check if it really gets passed the correct instance
241   typedef boost::function<unsigned long (Me)> MemFunc;
242   MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
243   VERIFY( fGetThis );
244   VERIFY( fGetThis(derived) == (unsigned long)d.get() );
245
246   BasePtr d2( new DoubleDerived );
247   derived = to_nasal(c, d2);
248   VERIFY( naIsGhost(derived) );
249   VERIFY( std::string("DoubleDerivedPtr") ==  naGhost_type(derived)->name );
250
251   BasePtr d3( new DoubleDerived2 );
252   derived = to_nasal(c, d3);
253   VERIFY( naIsGhost(derived) );
254   VERIFY( std::string("DoubleDerived2Ptr") ==  naGhost_type(derived)->name );
255
256   SGRefBasedPtr ref_based( new SGReferenceBasedClass );
257   naRef na_ref_based = to_nasal(c, ref_based.get());
258   VERIFY( naIsGhost(na_ref_based) );
259   VERIFY(    from_nasal<SGReferenceBasedClass*>(c, na_ref_based)
260           == ref_based.get() );
261   VERIFY( from_nasal<SGRefBasedPtr>(c, na_ref_based) == ref_based );
262
263   VERIFY( Ghost<BasePtr>::isBaseOf(derived) );
264   VERIFY( Ghost<DerivedPtr>::isBaseOf(derived) );
265   VERIFY( Ghost<DoubleDerived2Ptr>::isBaseOf(derived) );
266
267   VERIFY( from_nasal<BasePtr>(c, derived) == d3 );
268   VERIFY( from_nasal<BasePtr>(c, derived) != d2 );
269   VERIFY(    from_nasal<DerivedPtr>(c, derived)
270           == boost::dynamic_pointer_cast<Derived>(d3) );
271   VERIFY(    from_nasal<DoubleDerived2Ptr>(c, derived)
272           == boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
273   VERIFY( !from_nasal<DoubleDerivedPtr>(c, derived) );
274
275   std::map<std::string, BasePtr> instances;
276   VERIFY( naIsHash(to_nasal(c, instances)) );
277
278   std::map<std::string, DerivedPtr> instances_d;
279   VERIFY( naIsHash(to_nasal(c, instances_d)) );
280
281   std::map<std::string, int> int_map;
282   VERIFY( naIsHash(to_nasal(c, int_map)) );
283
284   std::map<std::string, std::vector<int> > int_vector_map;
285   VERIFY( naIsHash(to_nasal(c, int_vector_map)) );
286
287   simgear::StringMap dict =
288     simgear::StringMap("hello", "value")
289                       ("key2", "value2");
290   naRef na_dict = to_nasal(c, dict);
291   VERIFY( naIsHash(na_dict) );
292   VERIFY( Hash(na_dict, c).get<std::string>("key2") == "value2" );
293
294   // Check converting to Ghost if using Nasal hashes with actual ghost inside
295   // the hashes parents vector
296   std::vector<naRef> parents;
297   parents.push_back(hash.get_naRef());
298   parents.push_back(derived);
299
300   Hash obj(c);
301   obj.set("parents", parents);
302   VERIFY( from_nasal<BasePtr>(c, obj.get_naRef()) == d3 );
303
304   // Check recursive parents (aka parent-of-parent)
305   std::vector<naRef> parents2;
306   parents2.push_back(obj.get_naRef());
307   Hash derived_obj(c);
308   derived_obj.set("parents", parents2);
309   VERIFY( from_nasal<BasePtr>(c, derived_obj.get_naRef()) == d3 );
310
311   std::vector<naRef> nasal_objects;
312   nasal_objects.push_back( Ghost<BasePtr>::create(c, d) );
313   nasal_objects.push_back( Ghost<BasePtr>::create(c, d2) );
314   nasal_objects.push_back( Ghost<BasePtr>::create(c, d3) );
315   naRef obj_vec = to_nasal(c, nasal_objects);
316
317   std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
318   VERIFY( objects[0] == d );
319   VERIFY( objects[1] == d2 );
320   VERIFY( objects[2] == d3 );
321
322   //----------------------------------------------------------------------------
323   // Test nasal::CallContext
324   //----------------------------------------------------------------------------
325
326
327   int int_vec[] = {1,2,3};
328   std::map<std::string, std::string> map;
329   naRef args[] = {
330     to_nasal(c, std::string("test-arg")),
331     to_nasal(c, 4),
332     to_nasal(c, int_vec),
333     to_nasal(c, map)
334   };
335   CallContext cc(c, sizeof(args)/sizeof(args[0]), args);
336   VERIFY( cc.requireArg<std::string>(0) == "test-arg" );
337   VERIFY( cc.getArg<std::string>(0) == "test-arg" );
338   VERIFY( cc.getArg<std::string>(10) == "" );
339   VERIFY( cc.isString(0) );
340   VERIFY( !cc.isNumeric(0) );
341   VERIFY( !cc.isVector(0) );
342   VERIFY( !cc.isHash(0) );
343   VERIFY( !cc.isGhost(0) );
344   VERIFY( cc.isNumeric(1) );
345   VERIFY( cc.isVector(2) );
346   VERIFY( cc.isHash(3) );
347
348   naRef args_vec = nasal::to_nasal(c, args);
349   VERIFY( naIsVector(args_vec) );
350
351   //----------------------------------------------------------------------------
352   // Test nasal::String
353   //----------------------------------------------------------------------------
354
355   String string( to_nasal(c, "Test") );
356   VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
357   VERIFY( string.c_str() == std::string("Test") );
358   VERIFY( string.starts_with(string) );
359   VERIFY( string.starts_with(String(c, "T")) );
360   VERIFY( string.starts_with(String(c, "Te")) );
361   VERIFY( string.starts_with(String(c, "Tes")) );
362   VERIFY( string.starts_with(String(c, "Test")) );
363   VERIFY( !string.starts_with(String(c, "Test1")) );
364   VERIFY( !string.starts_with(String(c, "bb")) );
365   VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
366   VERIFY( string.ends_with(String(c, "t")) );
367   VERIFY( string.ends_with(String(c, "st")) );
368   VERIFY( string.ends_with(String(c, "est")) );
369   VERIFY( string.ends_with(String(c, "Test")) );
370   VERIFY( !string.ends_with(String(c, "1Test")) );
371   VERIFY( !string.ends_with(String(c, "abc")) );
372   VERIFY( !string.ends_with(String(c, "estasdasd")) );
373   VERIFY( string.find('e') == 1 );
374   VERIFY( string.find('9') == String::npos );
375   VERIFY( string.find_first_of(String(c, "st")) == 2 );
376   VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
377   VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
378   VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
379   VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
380   VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
381   VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
382
383   naFreeContext(c);
384
385   return 0;
386 }