v8toolkit  0.0.1
Utility library for embedding V8 Javascript engine in a c++ program
v8_class_wrapper-test.cpp
Go to the documentation of this file.
1 #include "testing.h"
2 
3 
4 
6  EXPECT_EQ(demangle<int>(), "int");
7  EXPECT_EQ(demangle<const int>(), "const int");
8  EXPECT_EQ(demangle<volatile int>(), "volatile int");
9  EXPECT_EQ(demangle<const volatile int >(), "const volatile int");
10 
11 }
12 
13 
14 TEST_F(JavaScriptFixture, NumberTypes) {
15  this->create_context();
16 
17  (*c)([&]{
18  EXPECT_EQ(CastToNative<bool>()(*i, CastToJS<bool>()(*i, true)), true);
19  EXPECT_EQ(CastToNative<bool>()(*i, CastToJS<bool>()(*i, false)), false);
20  EXPECT_EQ(CastToNative<char>()(*i, CastToJS<char>()(*i, 5)), 5);
24 
28  EXPECT_EQ(CastToNative<int>()(*i, CastToJS<int>()(*i, 5)), 5);
30  EXPECT_EQ(CastToNative<long>()(*i, CastToJS<long>()(*i, 5)), 5);
34 
35  EXPECT_EQ(CastToNative<float>()(*i, CastToJS<float>()(*i, 5.5)), 5.5);
36  EXPECT_EQ(CastToNative<double>()(*i, CastToJS<double>()(*i, 5.5)), 5.5);
38  });
39 }
40 
42  this->create_context();
43 
44  bool function_called = false;
45  c->add_function("wants_by_value", [&](bool b, char c, int i, float f){
46  function_called = true;
47  EXPECT_TRUE(b);
48  EXPECT_EQ(c, 2);
49  EXPECT_EQ(i, 3);
50  EXPECT_EQ(f, 4.5);
51  });
52  c->run("wants_by_value(true, 2, 3, 4.5)");
53  EXPECT_TRUE(function_called);
54 
55  function_called = false;
56  c->add_function("wants_by_value", [&](bool const & b, char const & c, int const & i, float const & f){
57  function_called = true;
58  EXPECT_FALSE(b);
59  EXPECT_EQ(c, 5);
60  EXPECT_EQ(i, 6);
61  EXPECT_EQ(f, 7.5);
62  });
63  c->run("wants_by_value(false, 5, 6, 7.5)");
64  EXPECT_TRUE(function_called);
65 
66 }
67 
68 TEST_F(JavaScriptFixture, CallingFunctionsWithUnwrappedTypes) {
69  bool takes_float_called = false;
70  bool takes_float_pointer_called = false;
71  i->add_function("takes_float", [&](float f){takes_float_called = true; EXPECT_EQ(f, 5.5);});
72  i->add_function("takes_float_pointer", [&](float * pf){takes_float_pointer_called = true; EXPECT_EQ(*pf, 6.5);});
73  i->add_function("takes_const_float", [&](float const f){takes_float_called = true; EXPECT_EQ(f, 7.5);});
74  i->add_function("takes_const_float_pointer", [&](float const * pf){takes_float_pointer_called = true; EXPECT_EQ(*pf, 8.5);});
75  this->create_context();
76 
77  (*c)([&] {
78  c->run("takes_float(5.5);");
79  c->run("takes_float_pointer(6.5);");
80  c->run("takes_const_float(7.5);");
81  c->run("takes_const_float_pointer(8.5);");
82 
83  });
84  EXPECT_TRUE(takes_float_called);
85  EXPECT_TRUE(takes_float_pointer_called);
86 }
87 
88 TEST_F(JavaScriptFixture, StringTypes) {
89  this->create_context();
90 
91  (*c)([&] {
92 
93  EXPECT_EQ(CastToNative<std::string>()(*i, CastToJS<std::string>()(*i, "test string")), "test string");
94 
95  // These return unique_ptr<char[]> because otherwise there wouldn't be any memory for the char * to point tos
96  EXPECT_STREQ(CastToNative<char *>()(*i, CastToJS<char const *>()(*i, "test string")).get(), "test string");
97  EXPECT_STREQ(CastToNative<char const *>()(*i, CastToJS<char const *>()(*i, "test string")).get(), "test string");
98  });
99 }
100 
101 
102 template<class T>
104  static bool deleted;
105  void operator()(T * t) {
106  this->deleted = true;
107  delete t;
108  }
109 };
110 
111 template<class T>
112 bool FlaggedDeleter<T>::deleted = false;
113 
114 TEST_F(JavaScriptFixture, UniquePointer_UnwrappedTypes) {
115  this->create_context();
116  (*c)([&] {
117  {
119  auto upi = unique_ptr<std::string, FlaggedDeleter<std::string>>(new std::string("test string"));
120  auto object = CastToJS<decltype(upi)>()(*i, std::move(upi));
121 
122 
123  // CastToJS should have taken ownership of the unique_ptr and deleted its memory because it's
124  // an unwrapped type
126 
127  // string should have been moved out of
128  EXPECT_STREQ(CastToNative<std::string>()(*i, object).c_str(), "test string");
129 
130  }
131  {
133  auto upi = unique_ptr<std::string, FlaggedDeleter<std::string>>(new std::string("test string"));
134  auto && rrupi = upi;
135  auto object = CastToJS<decltype(upi)>()(*i, std::move(rrupi));
136 
137 
138 
139  // CastToJS should have taken ownership of the unique_ptr and deleted its memory because it's
140  // an unwrapped type
142 
143  // string should have been moved out of
144  EXPECT_STREQ(CastToNative<std::string>()(*i, object).c_str(), "test string");
145 
146  }
147  {
148  {
150  auto upi = unique_ptr<std::string, FlaggedDeleter<std::string>>(new std::string("test string"));
151  auto object = CastToJS<decltype(upi) & >()(*i, std::move(upi));
152 
153  // string should NOT have been moved out of
154  EXPECT_STREQ(upi->c_str(), "test string");
155  EXPECT_STREQ(CastToNative<std::string>()(*i, object).c_str(), "test string");
156 
157 
158  // sending in unique_ptr by lvalue ref shouldn't do anything to the unique_ptr
160  }
161  // the unique_ptr goes out of scope and deletes as normal
163 
164  }
165  });
166 }
167 
168 
169 
171 
172  this->create_context();
173 
174  (*c)([&] {
175  {
176  std::vector<std::string> v{"hello", "there", "this", "is", "a", "vector"};
177  c->add_variable("v", CastToJS<decltype(v)>()(*i, v));
178  c->run("assert_contents(v, ['hello', 'there', 'this', 'is', 'a', 'vector'])");
179  }
180  {
181  std::vector<std::string> const cv{"hello", "there", "this", "is", "a", "vector"};
182  c->add_variable("cv", CastToJS<decltype(cv)>()(*i, cv));
183  c->run("assert_contents(cv, ['hello', 'there', 'this', 'is', 'a', 'vector'])");
184  }
185  {
186  // non-wrapped element type, so the original vector remains - no new object of the Element type to move
187  // them into.
188  std::vector<std::string> v{"hello", "there", "this", "is", "a", "vector"};
189  c->add_variable("v", CastToJS<decltype(v)>()(*i, std::move(v)));
190  c->run("assert_contents(v, ['hello', 'there', 'this', 'is', 'a', 'vector'])");
191  }
192 
193 
194 
195 
196  // vector
197  {
198  auto js_vector = c->run("[`a`, `b`, `c`]");
199  auto vector = CastToNative<std::vector<std::string>>()(*i, js_vector.Get(*i));
200  EXPECT_EQ(vector.size(), 3);
201  EXPECT_EQ(vector[2], "c");
202  }
203  // const vector
204  {
205  auto js_vector = c->run("[`a`, `b`, `c`]");
206  auto vector = CastToNative<std::vector<std::string> const>()(*i, js_vector.Get(*i));
207  EXPECT_EQ(vector.size(), 3);
208  EXPECT_EQ(vector[2], "c");
209  }
210 
211  });
212 }
213 
214 
216 
217  this->create_context();
218 
219  (*c)([&] {
220 
221  // CastToJS std::set
222  {
223  std::set<int> v{1, 2, 3};
224  c->add_variable("v", CastToJS<decltype(v)>()(*i, v));
225  auto sum = c->run("let sum = 0; for (let e of v) {sum += e} sum;");
226  EXPECT_EQ(CastToNative<int>()(*i, sum.Get(*i)), 6);
227 
228  }
229  // CastToJS const std::set
230  {
231  std::set<std::string> const v{"d", "e", "f"};
232  c->add_variable("v", CastToJS<decltype(v)>()(*i, v));
233  c->run("let o1 = {}; for (let e of v) {o1[e]=1;} EXPECT_EQJS(o1, {d: 1, e: 1, f: 1});");
234  EXPECT_NE(v.find("d"), v.end());
235  EXPECT_NE(v.find("e"), v.end());
236  EXPECT_NE(v.find("f"), v.end());
237 
238  }
239  // CastToJS std::set &&
240  {
241  std::set<std::string> v{"g", "h", "i"};
242  c->add_variable("v", CastToJS<decltype(v)>()(*i, std::move(v)));
243  c->run("let o2 = {}; for (let e of v) {o2[e]=1;} EXPECT_EQJS(o2, {g: 1, h: 1, i: 1});");
244  EXPECT_NE(v.find("g"), v.end());
245  EXPECT_NE(v.find("h"), v.end());
246  EXPECT_NE(v.find("i"), v.end());
247  }
248 
249 
250  // CastToNative set
251  {
252  auto js_set = c->run("[`a`, `b`, `c`]");
253  auto set = CastToNative<std::set<std::string>>()(*i, js_set.Get(*i));
254  EXPECT_EQ(set.size(), 3);
255  EXPECT_NE(set.find("a"), set.end());
256  EXPECT_NE(set.find("b"), set.end());
257  EXPECT_NE(set.find("c"), set.end());
258  }
259  // CastToNative const set
260  {
261  auto js_set = c->run("[`a`, `b`, `c`]");
262  auto set = CastToNative<std::set<std::string> const>()(*i, js_set.Get(*i));
263  EXPECT_EQ(set.size(), 3);
264  EXPECT_NE(set.find("a"), set.end());
265  EXPECT_NE(set.find("b"), set.end());
266  EXPECT_NE(set.find("c"), set.end());
267  }
268 
269  });
270 }
271 
272 
273 
275 
276  this->create_context();
277 
278  (*c)([&] {
279  // cast map to js
280  {
281  std::map<std::string, int> m{{"a", 1}, {"b", 2},{"c", 3}};
282  c->add_variable("m", CastToJS<decltype(m)>()(*i, m));
283  c->run("assert_contents(m, {a: 1, b: 2, c: 3})");
284  }
285  // cast const map to js
286  {
287  std::map<std::string, int> const cm{{"a", 1}, {"b", 2}, {"c", 3}};
288  c->add_variable("cm", CastToJS<decltype(cm)>()(*i, cm));
289  c->run("assert_contents(cm, {a: 1, b: 2, c: 3})");
290  }
291  // cast const map to js
292  {
293  std::map<std::string, int> m{{"a", 1}, {"b", 2},{"c", 3}};
294  c->add_variable("m", CastToJS<decltype(m)>()(*i, std::move(m)));
295  c->run("assert_contents(m, {a: 1, b: 2, c: 3})");
296  }
297 
298  {
299  auto js_object = c->run("new Object({a: 1, b: 2, c: 3});");
300  auto map = CastToNative<std::map<std::string, int>>()(*i, js_object.Get(*i));
301  EXPECT_EQ(map.size(), 3);
302  EXPECT_EQ(map["a"], 1);
303  EXPECT_EQ(map["b"], 2);
304  EXPECT_EQ(map["c"], 3);
305  }
306  {
307  auto js_object = c->run("new Object({a: 1, b: 2, c: 3});");
308  auto map = CastToNative<std::map<std::string, int> const>()(*i, js_object.Get(*i));
309  EXPECT_EQ(map.size(), 3);
310  EXPECT_EQ(map["a"], 1);
311  EXPECT_EQ(map["b"], 2);
312  EXPECT_EQ(map["c"], 3);
313  }
314 
315  });
316 }
317 
318 
319 /**
320  * Move each of these into its own test for its container type
321  */
322 TEST_F(JavaScriptFixture, ContainerTypes) {
323 
324  this->create_context();
325 
326  (*c)([&] {
327 
328  std::list<float> l{1.5, 2.5, 3.5, 4.5};
329  c->add_variable("l", CastToJS<decltype(l)>()(*i, l));
330  c->run("assert_contents(l, [1.5, 2.5, 3.5, 4.5]);");
331 
332  std::map<std::string, int> m{{"one", 1},{"two", 2},{"three", 3}};
333  c->add_variable("m", CastToJS<decltype(m)>()(*i, m));
334  c->run("assert_contents(m, {'one': 1, 'two': 2, 'three': 3});");
335 
336  std::map<std::string, int> m2{{"four", 4},{"five", 5},{"six", 6}};
337  c->add_variable("m2", CastToJS<decltype(m2)>()(*i, m2));
338  c->run("assert_contents(m2, {'four': 4, 'five': 5, 'six': 6});");
339 
340  std::deque<long> d{7000000000, 8000000000, 9000000000};
341  c->add_variable("d", CastToJS<decltype(d)>()(*i, d));
342  c->run("assert_contents(d, [7000000000, 8000000000, 9000000000]);");
343 
344  std::multimap<string, int> mm{{"a",1},{"a",2},{"a",3},{"b",4},{"c",5},{"c",6}};
345  c->add_variable("mm", CastToJS<decltype(mm)>()(*i, mm));
346  c->run("assert_contents(mm, {a: [1, 2, 3], b: [4], c: [5, 6]});");
347  auto js_mm = c->run("mm");
348  auto reconstituted_mm = CastToNative<decltype(mm)>()(*i, js_mm.Get(*i));
349  assert(reconstituted_mm.size() == 6);
350  assert(reconstituted_mm.count("a") == 3);
351  assert(reconstituted_mm.count("b") == 1);
352  assert(reconstituted_mm.count("c") == 2);
353 
354  std::array<int, 3> a{{1,2,3}};
355  c->add_variable("a", CastToJS<decltype(a)>()(*i, a));
356  c->run("assert_contents(a, [1, 2, 3]);");
357 
358  std::map<std::string, std::vector<int>> composite = {{"a",{1,2,3}},{"b",{4,5,6}},{"c",{7,8,9}}};
359  c->add_variable("composite", CastToJS<decltype(composite)>()(*i, composite));
360  c->run("assert_contents(composite, {'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]});");
361 
362  {
363  std::string tuple_string("Hello");
364  auto tuple = make_tuple(1, 2.2, tuple_string);
365  c->expose_variable("tuple", tuple);
366  c->run("assert_contents(tuple, [1, 2.2, 'Hello'])");
367  }
368  // printf("Done testing STL container casts\n");
369 
370  });
371 
372 
373 }
374 
375 // Make sure the hierarchy of shared_ptr's to dependencies is maintained apprioriately and everything
376 // is cleaned up once there isn't anything else using them
377 TEST_F(JavaScriptFixture, ObjectLifetimes) {
378 
379  std::weak_ptr<v8toolkit::Isolate> weak_isolate_pointer;
380  std::weak_ptr<v8toolkit::Script> weak_script_pointer;
381  {
382  decltype(std::declval<ScriptPtr>()->run_async()) future;
383  {
384  ScriptPtr s;
385  {
386  ContextPtr c;
387  {
388  auto i = Platform::create_isolate();
389  weak_isolate_pointer = i->weak_from_this();
390  c = i->create_context();
391  } // isolate goes out of scope
392  EXPECT_FALSE(weak_isolate_pointer.expired());
393  (*c)([&]() {
394  s = c->compile("5");
395  });
396  weak_script_pointer = s->weak_from_this();
397  } // Context goes out of scope
398  EXPECT_FALSE(weak_isolate_pointer.expired());
399  EXPECT_FALSE(weak_script_pointer.expired());
400  future = s->run_async();
401  } // script goes out of scope
402  EXPECT_FALSE(weak_isolate_pointer.expired());
403  EXPECT_FALSE(weak_script_pointer.expired());
404  future.get();
405  } // future goes out of scope and everything is cleaned up
406  EXPECT_TRUE(weak_isolate_pointer.expired()); // Everything should be gone now
407  EXPECT_TRUE(weak_script_pointer.expired());
408 
409 }
410 
411 
412 
413 
414 
415 TEST_F(JavaScriptFixture, StdFunctionCasts) {
416 
417  this->create_context();
418 
419 
420 
421  (*c)([&] {
422  bool wants_function_was_called = false;
423  c->add_function("wants_function", [&](std::function<bool(int * pi, float & rf)> function) {
424  int i;
425  float f;
426 
427  wants_function_was_called = true;
428 
429  i = 1;
430  f = 1;
431  EXPECT_TRUE(function(&i, f));
432  i = 2;
433  f = 3;
434  EXPECT_FALSE(function(&i, f));
435  });
436  int javascript_function_call_count = 0;
437  c->expose_variable("javascript_function_call_count", javascript_function_call_count);
438  c->run("wants_function(function(i, j){javascript_function_call_count++; return i == j;});");
439 
440  EXPECT_TRUE(wants_function_was_called);
441  EXPECT_EQ(javascript_function_call_count, 2);
442  });
443 }
444 
445 
446 
447 
448 
450 
451  this->create_context();
452 
453 
454 
455  (*c)([&] {
456 
457  });
458 }
459 
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
::std::string string
Definition: gtest-port.h:1097
tuple make_tuple()
Definition: gtest-tuple.h:675
#define EXPECT_STREQ(s1, s2)
Definition: gtest.h:1995
std::shared_ptr< Context > ContextPtr
Definition: javascript.h:367
std::shared_ptr< Script > ScriptPtr
Definition: javascript.h:26
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
const T & move(const T &t)
Definition: gtest-port.h:1317
TEST_F(JavaScriptFixture, Helpers)
std::shared_ptr< Context > create_context()
Definition: javascript.cpp:285