ChaiScript / ChaiScript
1
// All of these are necessary because of catch.hpp. It's OK, they'll be
2
// caught in other cpp files if chaiscript causes them
3

4

5
#ifdef _MSC_VER
6
#pragma warning(push)
7
#pragma warning(disable : 4062 4242 4566 4640 4702 6330 28251)
8
#endif
9

10

11
#ifdef __GNUC__
12
#pragma GCC diagnostic push
13
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
14
#pragma GCC diagnostic ignored "-Wparentheses"
15
// This one is necessary for the const return non-reference test
16
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
17
#endif
18

19

20
#include <chaiscript/chaiscript.hpp>
21
#include <chaiscript/chaiscript_basic.hpp>
22
#include <chaiscript/utility/utility.hpp>
23
#include <chaiscript/dispatchkit/bootstrap_stl.hpp>
24

25
#include "../static_libs/chaiscript_parser.hpp"
26
#include "../static_libs/chaiscript_stdlib.hpp"
27

28

29

30
#define CATCH_CONFIG_MAIN
31

32
#include <clocale>
33

34
#include "catch.hpp"
35

36
// lambda_tests
37 1
TEST_CASE("C++11 Lambdas Can Be Registered")
38
{
39

40
  // We cannot deduce the type of a lambda expression, you must either wrap it
41
  // in an std::function or provide the signature
42 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
43

44 1
  chai.add(chaiscript::fun([]()->std::string { return "hello"; } ), "f1");
45

46
  // wrap
47 1
  chai.add(chaiscript::fun(std::function<std::string ()>([] { return "world"; } )), "f2");
48

49 1
  CHECK(chai.eval<std::string>("f1()") == "hello");
50 1
  CHECK(chai.eval<std::string>("f2()") == "world");
51
}
52

53

54
// dynamic_object tests
55 1
TEST_CASE("Dynamic_Object attributes can be shared with C++")
56
{
57 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
58

59 1
  chai("attr bob::z; def bob::bob() { this.z = 10 }; auto x = bob()");
60

61 1
  chaiscript::dispatch::Dynamic_Object &mydo = chai.eval<chaiscript::dispatch::Dynamic_Object &>("x");
62

63 1
  CHECK(mydo.get_type_name() == "bob");
64

65 1
  CHECK(chaiscript::boxed_cast<int>(mydo.get_attr("z")) == 10);
66

67 1
  chai("x.z = 15");
68

69 1
  CHECK(chaiscript::boxed_cast<int>(mydo.get_attr("z")) == 15);
70

71 1
  int &z = chaiscript::boxed_cast<int&>(mydo.get_attr("z"));
72

73 1
  CHECK(z == 15);
74

75 1
  z = 20;
76
  
77 1
  CHECK(z == 20);
78 1
  CHECK(chaiscript::boxed_cast<int>(chai("x.z")) == 20);
79
}
80

81

82 1
TEST_CASE("Function objects can be created from chaiscript functions")
83
{
84

85 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
86

87 1
  chai.eval("def func() { print(\"Hello World\"); } ");
88

89 1
  std::function<void ()> f = chai.eval<std::function<void ()> >("func");
90 1
  f();
91

92 1
  CHECK(chai.eval<std::function<std::string (int)> >("to_string")(6) == "6");
93 1
  CHECK(chai.eval<std::function<std::string (const chaiscript::Boxed_Value &)> >("to_string")(chaiscript::var(6)) == "6");
94
}
95

96

97 1
TEST_CASE("ChaiScript can be created and destroyed on heap")
98
{
99 1
  auto *chai = new chaiscript::ChaiScript_Basic(create_chaiscript_stdlib(),create_chaiscript_parser());
100 1
  delete chai;
101
}
102

103

104
///////// Arithmetic Conversions
105

106
// Tests to make sure that type conversions happen only when they should
107 1
void arithmetic_conversions_f1(int)
108
{
109
}
110

111 0
void arithmetic_conversions_f4(std::string)
112
{
113
}
114

115 1
void arithmetic_conversions_f2(int)
116
{
117
}
118

119 1
void arithmetic_conversions_f3(double)
120
{
121
}
122

123 1
void arithmetic_conversions_f_func_return(const std::function<unsigned int (unsigned long)> &f)
124
{
125
  // test the ability to return an unsigned with auto conversion
126 1
  f(4);
127
}
128

129 1
TEST_CASE("Test automatic arithmetic conversions")
130
{
131 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
132

133 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f1), "f1");
134 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f2), "f2");
135 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f3), "f2");
136 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f1), "f3");
137 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f4), "f3");
138

139 1
  chai.add(chaiscript::fun(&arithmetic_conversions_f_func_return), "func_return");
140

141
  // no overloads
142 1
  chai.eval("f1(0)");
143 1
  chai.eval("f1(0l)");
144 1
  chai.eval("f1(0ul)");
145 1
  chai.eval("f1(0ll)");
146 1
  chai.eval("f1(0ull)");
147 1
  chai.eval("f1(0.0)");
148 1
  chai.eval("f1(0.0f)");
149 1
  chai.eval("f1(0.0l)");
150

151
  // expected overloads
152 1
  chai.eval("f2(1)");
153 1
  chai.eval("f2(1.0)");
154

155
  // 1 non-arithmetic overload
156 1
  chai.eval("f2(1.0)");
157

158
  // various options for returning with conversions from chaiscript
159 1
  chai.eval("func_return(fun(x) { return 5u; })");
160 1
  chai.eval("func_return(fun(x) { return 5; })");
161 1
  chai.eval("func_return(fun(x) { return 5.0f; })");
162

163
  CHECK_THROWS(chai.eval("f2(1.0l)"));
164
}
165

166

167
/////// Exception handling
168

169

170 1
TEST_CASE("Generic exception handling with C++")
171
{
172 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
173

174
  try {
175
    chai.eval("throw(runtime_error(\"error\"));");
176 0
    REQUIRE(false);
177 1
  } catch (const chaiscript::Boxed_Value &bv) {
178 1
    const std::exception &e = chai.boxed_cast<const std::exception &>(bv);
179 1
    CHECK(e.what() == std::string("error"));
180
  }
181
}
182

183 1
TEST_CASE("Throw an int")
184
{
185 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
186

187
  try {
188
    chai.eval("throw(1)", chaiscript::exception_specification<int>());
189 0
    REQUIRE(false);
190 1
  } catch (int e) {
191 1
    CHECK(e == 1);
192
  }
193
}
194

195 1
TEST_CASE("Throw int or double")
196
{
197 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
198

199
  try {
200
    chai.eval("throw(1.0)", chaiscript::exception_specification<int, double>());
201 0
    REQUIRE(false);
202 1
  } catch (const double e) {
203 1
    CHECK(e == Approx(1.0));
204
  }
205
}
206

207 1
TEST_CASE("Deduction of pointer return types")
208
{
209 1
  int val = 5;
210 1
  int *val_ptr = &val;
211 1
  auto &val_ptr_ref = val_ptr;
212 1
  const auto &val_ptr_const_ref = val_ptr;
213

214 1
  auto get_val_ptr = [&]() -> int * { return val_ptr; };
215 1
  auto get_val_const_ptr = [&]() -> int const * { return val_ptr; };
216 1
  auto get_val_ptr_ref = [&]() -> int *& { return val_ptr_ref; };
217 1
  auto get_val_ptr_const_ref = [&]() -> int * const & { return val_ptr_const_ref; };
218
//  auto get_val_const_ptr_const_ref = [ref=std::cref(val_ptr)]() -> int const * const & { return ref.get(); };
219

220 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(), create_chaiscript_parser());
221 1
  chai.add(chaiscript::fun(get_val_ptr), "get_val_ptr");
222 1
  chai.add(chaiscript::fun(get_val_const_ptr), "get_val_const_ptr");
223 1
  chai.add(chaiscript::fun(get_val_ptr_ref), "get_val_ptr_ref");
224 1
  chai.add(chaiscript::fun(get_val_ptr_const_ref), "get_val_ptr_const_ref");
225
//  chai.add(chaiscript::fun(get_val_const_ptr_const_ref), "get_val_const_ptr_const_ref");
226

227 1
  CHECK(chai.eval<int *>("get_val_ptr()") == &val);
228 1
  CHECK(*chai.eval<int *>("get_val_ptr()") == val);
229 1
  CHECK(chai.eval<int const *>("get_val_const_ptr()") == &val);
230 1
  CHECK(*chai.eval<int const *>("get_val_const_ptr()") == val);
231

232
  // note that we cannot maintain the references here,
233
  // chaiscript internals cannot handle that, effectively pointer to pointer
234 1
  CHECK(chai.eval<int *>("get_val_ptr_ref()") == &val);
235 1
  CHECK(*chai.eval<int *>("get_val_ptr_ref()") == val);
236 1
  CHECK(chai.eval<int *>("get_val_ptr_const_ref()") == &val);
237 1
  CHECK(*chai.eval<int *>("get_val_ptr_const_ref()") == val);
238
//  CHECK(chai.eval<int const *>("get_val_const_ptr_const_ref()") == &val);
239
}
240

241

242 1
TEST_CASE("Throw a runtime_error")
243
{
244 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
245

246
  try {
247
    chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
248 0
    REQUIRE(false);
249 0
  } catch (const double) {
250 0
    REQUIRE(false);
251 0
  } catch (int) {
252 0
    REQUIRE(false);
253 0
  } catch (float) {
254 0
    REQUIRE(false);
255 0
  } catch (const std::string &) {
256 0
    REQUIRE(false);
257 1
  } catch (const std::exception &) {
258 1
    REQUIRE(true);
259
  }
260
}
261

262 1
TEST_CASE("Throw unhandled type")
263
{
264 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
265

266
  try {
267
    chai.eval("throw(\"error\")", chaiscript::exception_specification<int, double, float, const std::exception &>());
268 0
    REQUIRE(false);
269 0
  } catch (double) {
270 0
    REQUIRE(false);
271 0
  } catch (int) {
272 0
    REQUIRE(false);
273 0
  } catch (float) {
274 0
    REQUIRE(false);
275 0
  } catch (const std::exception &) {
276 0
    REQUIRE(false);
277 1
  } catch (const chaiscript::Boxed_Value &) {
278 1
    REQUIRE(true);
279
  }
280
}
281

282

283
///////////// Tests to make sure no arity, dispatch or guard errors leak up past eval
284

285

286 0
int expected_eval_errors_test_one(const int &)
287
{
288 0
  return 1;
289
}
290

291 1
TEST_CASE("No unexpected exceptions leak")
292
{
293 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
294 1
  chai.add(chaiscript::fun(&expected_eval_errors_test_one), "test_fun");
295

296 1
  chai.eval("def guard_fun(i) : i.get_type_info().is_type_arithmetic() {} ");
297

298
  //// Dot notation
299

300
  // non-existent function
301
  CHECK_THROWS_AS(chai.eval("\"test\".test_one()"), chaiscript::exception::eval_error);
302
  // wrong parameter type
303
  CHECK_THROWS_AS(chai.eval("\"test\".test_fun()"), chaiscript::exception::eval_error);
304

305
  // wrong number of parameters
306
  CHECK_THROWS_AS(chai.eval("\"test\".test_fun(1)"), chaiscript::exception::eval_error);
307

308
  // guard failure
309
  CHECK_THROWS_AS(chai.eval("\"test\".guard_fun()"), chaiscript::exception::eval_error);
310

311

312
  // regular notation
313

314
  // non-existent function
315
  CHECK_THROWS_AS(chai.eval("test_one(\"test\")"), chaiscript::exception::eval_error);
316

317
  // wrong parameter type
318
  CHECK_THROWS_AS(chai.eval("test_fun(\"test\")"), chaiscript::exception::eval_error);
319

320
  // wrong number of parameters
321
  CHECK_THROWS_AS(chai.eval("test_fun(\"test\")"), chaiscript::exception::eval_error);
322

323
  // guard failure
324
  CHECK_THROWS_AS(chai.eval("guard_fun(\"test\")"), chaiscript::exception::eval_error);
325

326

327
  // index operator
328
  CHECK_THROWS_AS(chai.eval("var a = [1,2,3]; a[\"bob\"];"), chaiscript::exception::eval_error);
329

330
  // unary operator
331
  CHECK_THROWS_AS(chai.eval("++\"bob\""), chaiscript::exception::eval_error);
332

333
  // binary operator
334
  CHECK_THROWS_AS(chai.eval("\"bob\" + 1"), chaiscript::exception::eval_error);
335

336

337
}
338

339

340
//////// Tests to make sure that the order in which function dispatches occur is correct
341

342
#include <chaiscript/utility/utility.hpp>
343

344 1
int function_ordering_test_one(const int &)
345
{
346 1
  return 1;
347
}
348

349 1
int function_ordering_test_two(int &)
350
{
351 1
  return 2;
352
}
353

354 1
TEST_CASE("Function ordering")
355
{
356 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
357 1
  chai.eval("def test_fun(x) { return 3; }");
358 1
  chai.eval("def test_fun(x) : x == \"hi\" { return 4; }");
359
//  chai.eval("def test_fun(x) { return 5; }");
360 1
  chai.add(chaiscript::fun(&function_ordering_test_one), "test_fun");
361 1
  chai.add(chaiscript::fun(&function_ordering_test_two), "test_fun");
362

363 1
  CHECK(chai.eval<int>("test_fun(1)") == 1);
364 1
  CHECK(chai.eval<int>("auto i = 1; test_fun(i)") == 2);
365 1
  CHECK(chai.eval<int>("test_fun(\"bob\")") == 3);
366 1
  CHECK(chai.eval<int>("test_fun(\"hi\")") == 4);
367
}
368

369

370

371

372 1
int functor_cast_test_call(const std::function<int (int)> &f, int val)
373
{
374 1
  return f(val);
375
}
376

377 1
TEST_CASE("Functor cast")
378
{
379

380 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
381

382 1
  chai.add(chaiscript::fun(&functor_cast_test_call), "test_call");
383

384 1
  chai.eval("def func(i) { return i * 6; };");
385 1
  int d = chai.eval<int>("test_call(func, 3)");
386

387 1
  CHECK(d == 3 * 6);
388
}
389

390 1
TEST_CASE("Non-ASCII characters in the middle of string")
391
{
392 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
393
  CHECK_THROWS_AS(chai.eval<std::string>("prin\xeft \"Hello World\""), chaiscript::exception::eval_error);
394
}
395

396 1
TEST_CASE("Non-ASCII characters in the beginning of string")
397
{
398 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
399
    CHECK_THROWS_AS(chai.eval<std::string>("\xefprint \"Hello World\""), chaiscript::exception::eval_error);
400
}
401

402 1
TEST_CASE("Non-ASCII characters in the end of string")
403
{
404 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
405
    CHECK_THROWS_AS(chai.eval<std::string>("print \"Hello World\"\xef"), chaiscript::exception::eval_error);
406
}
407

408 1
TEST_CASE("BOM in string")
409
{
410 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
411
    CHECK_THROWS_AS(chai.eval<std::string>("\xef\xbb\xbfprint \"Hello World\""), chaiscript::exception::eval_error);
412
}
413

414 1
int set_state_test_myfun()
415
{
416 1
  return 2;
417
}
418

419 1
TEST_CASE("Set and restore chai state")
420
{
421 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
422

423
  // save the initial state of globals and locals
424 1
  auto firststate = chai.get_state();
425 1
  std::map<std::string, chaiscript::Boxed_Value> locals = chai.get_locals();
426

427
  // add some new globals and locals
428 1
  chai.add(chaiscript::var(1), "i");
429

430 1
  chai.add(chaiscript::fun(&set_state_test_myfun), "myfun");
431

432

433 1
  CHECK(chai.eval<int>("myfun()") == 2);
434

435 1
  CHECK(chai.eval<int>("i") == 1);
436

437 1
  chai.set_state(firststate);
438

439
  // set state should have reverted the state of the functions and dropped
440
  // the 'myfun'
441

442
  CHECK_THROWS_AS(chai.eval<int>("myfun()"), chaiscript::exception::eval_error);
443

444
  // set state should not affect the local variables
445 1
  CHECK(chai.eval<int>("i") == 1);
446

447
  // After resetting the locals we expect the 'i' to be gone
448 1
  chai.set_locals(locals);
449

450
  CHECK_THROWS_AS(chai.eval<int>("i"), chaiscript::exception::eval_error);
451
}
452

453

454
//// Short comparisons
455

456
class Short_Comparison_Test {
457
 public:
458 1
  Short_Comparison_Test() : value_(5) {}
459

460 1
  short get_value() const { return value_; }
461

462
  short value_;
463
};
464

465 1
TEST_CASE("Short comparison with int")
466
{
467 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
468 1
  chai.add(chaiscript::user_type<Short_Comparison_Test>(), "Test");
469 1
  chai.add(chaiscript::constructor<Short_Comparison_Test()>(), "Test");
470

471 1
  chai.add(chaiscript::fun(&Short_Comparison_Test::get_value), "get_value");
472

473 1
  chai.eval("auto &t = Test();");
474

475 1
  CHECK(chai.eval<bool>("t.get_value() == 5"));
476
}
477

478

479

480

481
///// Test lookup of type names
482

483

484
class Type_Name_MyClass
485
{
486
};
487

488 1
TEST_CASE("Test lookup of type names")
489
{
490 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
491 1
  auto type = chaiscript::user_type<Type_Name_MyClass>();
492 1
  chai.add(type, "MyClass");
493

494 1
  CHECK(chai.get_type_name(type) == "MyClass");
495 1
  CHECK(chai.get_type_name<Type_Name_MyClass>() == "MyClass");
496
}
497

498

499
/////// make sure many chaiscript objects can exist simultaneously 
500

501

502 1
int simultaneous_chaiscript_do_something(int i)
503
{
504 1
  return i + 2;
505
}
506

507 1
int simultaneous_chaiscript_do_something_else(int i)
508
{
509 1
  return i * 2;
510
}
511

512

513

514 1
TEST_CASE("Simultaneous ChaiScript tests")
515
{
516 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
517 1
  chai.add(chaiscript::fun(&simultaneous_chaiscript_do_something), "do_something");
518 1
  chai.add(chaiscript::var(1), "i");
519

520 1
  for (int i = 0; i < 10; ++i)
521
  {
522 1
    chaiscript::ChaiScript_Basic chai2(create_chaiscript_stdlib(),create_chaiscript_parser());
523 1
    chai2.add(chaiscript::fun(&simultaneous_chaiscript_do_something_else), "do_something_else");
524

525 1
    CHECK(chai.eval<int>("do_something(" + std::to_string(i) + ")") == i + 2);
526 1
    CHECK(chai2.eval<int>("do_something_else(" + std::to_string(i) + ")") == i * 2);
527

528
    CHECK_THROWS_AS(chai2.eval("do_something(1)"), chaiscript::exception::eval_error);
529
    CHECK_THROWS_AS(chai2.eval("i"), chaiscript::exception::eval_error);
530 1
    CHECK_NOTHROW(chai2.eval("do_something_else(1)"));
531
  }
532
}
533

534

535

536
/////////////// test utility functions
537

538
class Utility_Test
539
{
540
  public:
541 0
    void function() {}
542 1
    std::string function2() { return "Function2"; }
543 0
    void function3() {}
544 1
    std::string functionOverload(double) { return "double"; }
545 1
    std::string functionOverload(int) { return "int"; }
546
};
547

548 1
TEST_CASE("Utility_Test utility class wrapper")
549
{
550

551 1
  chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
552

553
  using namespace chaiscript;
554

555
  /// \todo fix overload resolution for fun<>
556 1
  chaiscript::utility::add_class<Utility_Test>(*m,
557
      "Utility_Test",
558
      { constructor<Utility_Test ()>(),
559
        constructor<Utility_Test (const Utility_Test &)>() },
560 1
      { {fun(&Utility_Test::function), "function"},
561 1
        {fun(&Utility_Test::function2), "function2"},
562 1
        {fun(&Utility_Test::function3), "function3"},
563 1
        {fun(static_cast<std::string(Utility_Test::*)(double)>(&Utility_Test::functionOverload)), "functionOverload" },
564 1
        {fun(static_cast<std::string(Utility_Test::*)(int)>(&Utility_Test::functionOverload)), "functionOverload" },
565 1
        {fun(static_cast<Utility_Test & (Utility_Test::*)(const Utility_Test &)>(&Utility_Test::operator=)), "=" }
566
 
567
        }
568 1
      );
569

570

571 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
572 1
  chai.add(m);
573

574 1
  CHECK(chai.eval<std::string>("auto t = Utility_Test(); t.function2(); ") == "Function2");
575 1
  CHECK(chai.eval<std::string>("auto t2 = Utility_Test(); t2.functionOverload(1); ") == "int");
576 1
  CHECK(chai.eval<std::string>("auto t3 = Utility_Test(); t3.functionOverload(1.1); ") == "double");
577 1
  chai.eval("t = Utility_Test();");
578

579
}
580

581

582
enum Utility_Test_Numbers
583
{
584
  ONE,
585
  TWO,
586
  THREE
587
};
588

589 1
void do_something_with_enum_vector(const std::vector<Utility_Test_Numbers> &v)
590
{
591 1
  CHECK(v.size() == 3);
592 1
  CHECK(v[0] == ONE);
593 1
  CHECK(v[1] == THREE);
594 1
  CHECK(v[2] == TWO);
595
}
596

597 1
TEST_CASE("Utility_Test utility class wrapper for enum")
598
{
599

600 1
  chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
601

602
  using namespace chaiscript;
603

604 1
  chaiscript::utility::add_class<Utility_Test_Numbers>(*m,
605
      "Utility_Test_Numbers",
606
      { { ONE, "ONE" },
607
        { TWO, "TWO" },
608
        { THREE, "THREE" }
609

610
        }
611 1
      );
612

613

614 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
615 1
  chai.add(m);
616

617 1
  CHECK(chai.eval<Utility_Test_Numbers>("ONE ") == 0);
618 1
  CHECK(chai.eval<Utility_Test_Numbers>("TWO ") == 1);
619 1
  CHECK(chai.eval<Utility_Test_Numbers>("THREE ") == 2);
620

621 1
  CHECK(chai.eval<bool>("ONE == 0"));
622

623 1
  chai.add(chaiscript::fun(&do_something_with_enum_vector), "do_something_with_enum_vector");
624 1
  chai.add(chaiscript::vector_conversion<std::vector<Utility_Test_Numbers>>());
625 1
  CHECK_NOTHROW(chai.eval("var a = [ONE, TWO, THREE]"));
626 1
  CHECK_NOTHROW(chai.eval("do_something_with_enum_vector([ONE, THREE, TWO])"));
627 1
  CHECK_NOTHROW(chai.eval("[ONE]"));
628

629 1
  const auto v = chai.eval<std::vector<Utility_Test_Numbers>>("a");
630 1
  CHECK(v.size() == 3);
631 1
  CHECK(v.at(1) == TWO);
632

633 1
  CHECK(chai.eval<bool>("ONE == ONE"));
634 1
  CHECK(chai.eval<bool>("ONE != TWO"));
635 1
  CHECK_NOTHROW(chai.eval("var o = ONE; o = TWO"));
636

637

638
}
639

640

641
////// Object copy count test
642

643
class Object_Copy_Count_Test
644
{
645
  public:
646 1
    Object_Copy_Count_Test()
647
    {
648 1
      std::cout << "Object_Copy_Count_Test()\n";
649 1
      ++constructcount();
650
    }
651

652 0
    Object_Copy_Count_Test(const Object_Copy_Count_Test &)
653
    {
654 0
      std::cout << "Object_Copy_Count_Test(const Object_Copy_Count_Test &)\n";
655 0
      ++copycount();
656
    }
657

658 1
    Object_Copy_Count_Test(Object_Copy_Count_Test &&)
659
    {
660 1
      std::cout << "Object_Copy_Count_Test(Object_Copy_Count_Test &&)\n";
661 1
      ++movecount();
662
    }
663

664 1
    ~Object_Copy_Count_Test()
665
    {
666 1
      std::cout << "~Object_Copy_Count_Test()\n";
667 1
      ++destructcount();
668
    }
669

670 1
    static int& constructcount()
671
    {
672
      static int c = 0;
673 1
      return c;
674
    }
675

676 1
    static int& copycount()
677
    {
678
      static int c = 0;
679 1
      return c;
680
    }
681

682 1
    static int& movecount()
683
    {
684
      static int c = 0;
685 1
      return c;
686
    }
687

688 1
    static int& destructcount()
689
    {
690
      static int c = 0;
691 1
      return c;
692
    }
693
};
694

695 1
Object_Copy_Count_Test object_copy_count_create()
696
{
697 1
  return Object_Copy_Count_Test();
698
}
699

700 1
TEST_CASE("Object copy counts")
701
{
702 1
  chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
703

704 1
  m->add(chaiscript::user_type<Object_Copy_Count_Test>(), "Object_Copy_Count_Test");
705 1
  m->add(chaiscript::constructor<Object_Copy_Count_Test()>(), "Object_Copy_Count_Test");
706 1
  m->add(chaiscript::constructor<Object_Copy_Count_Test(const Object_Copy_Count_Test &)>(), "Object_Copy_Count_Test");
707 1
  m->add(chaiscript::fun(&object_copy_count_create), "create");
708

709 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
710 1
  chai.add(m);
711

712 1
  chai.eval(" { auto i = create(); } ");
713

714 1
  CHECK(Object_Copy_Count_Test::copycount() == 0);
715 1
  CHECK(Object_Copy_Count_Test::constructcount() == 1);
716 1
  CHECK(Object_Copy_Count_Test::destructcount() == 2);
717 1
  CHECK(Object_Copy_Count_Test::movecount() == 1);
718
}
719

720

721
///////////////////// Object lifetime test 1
722

723

724
class Object_Lifetime_Test
725
{
726
  public:
727 1
    Object_Lifetime_Test()
728
    {
729 1
      ++count();
730
    }
731

732 1
    Object_Lifetime_Test(const Object_Lifetime_Test &)
733
    {
734 1
      ++count();
735
    }
736

737 1
    ~Object_Lifetime_Test()
738
    {
739 1
      --count();
740
    }
741

742 1
    static int& count()
743
    {
744
      static int c = 0;
745 1
      return c;
746
    }
747
};
748

749 1
TEST_CASE("Object lifetime tests")
750
{
751 1
  chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
752

753 1
  m->add(chaiscript::user_type<Object_Lifetime_Test>(), "Object_Lifetime_Test");
754 1
  m->add(chaiscript::constructor<Object_Lifetime_Test()>(), "Object_Lifetime_Test");
755 1
  m->add(chaiscript::constructor<Object_Lifetime_Test(const Object_Lifetime_Test &)>(), "Object_Lifetime_Test");
756 1
  m->add(chaiscript::fun(&Object_Lifetime_Test::count), "count");
757

758 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
759 1
  chai.add(m);
760

761 1
  CHECK(chai.eval<int>("count()") == 0);
762 1
  CHECK(chai.eval<int>("auto i = 0; { auto t = Object_Lifetime_Test(); } return i;") == 0);
763 1
  CHECK(chai.eval<int>("i = 0; { auto t = Object_Lifetime_Test(); i = count(); } return i;") == 1);
764 1
  CHECK(chai.eval<int>("i = 0; { auto t = Object_Lifetime_Test(); { auto t2 = Object_Lifetime_Test(); i = count(); } } return i;") == 2);
765 1
  CHECK(chai.eval<int>("i = 0; { auto t = Object_Lifetime_Test(); { auto t2 = Object_Lifetime_Test(); } i = count(); } return i;") == 1);
766 1
  CHECK(chai.eval<int>("i = 0; { auto t = Object_Lifetime_Test(); { auto t2 = Object_Lifetime_Test(); }  } i = count(); return i;") == 0);
767
}
768

769

770

771
//// Object lifetime tests 2
772

773
template<typename T>
774
struct Object_Lifetime_Vector2
775
{
776 0
  Object_Lifetime_Vector2() : x(0), y(0) {}
777 1
  Object_Lifetime_Vector2(T px, T py) : x(px), y(py) {}
778 1
  Object_Lifetime_Vector2(const Object_Lifetime_Vector2& cp) : x(cp.x), y(cp.y) {}
779

780 0
  Object_Lifetime_Vector2& operator+=(const Object_Lifetime_Vector2& vec_r)
781
  {
782 0
    x += vec_r.x;
783 0
    y += vec_r.y;
784 0
    return *this;
785
  }
786

787 0
  Object_Lifetime_Vector2 operator+(const Object_Lifetime_Vector2& vec_r)
788
  {
789 0
    return Object_Lifetime_Vector2(*this += vec_r);
790
  }
791

792 0
  Object_Lifetime_Vector2 &operator=(const Object_Lifetime_Vector2& ver_r)
793
  {
794 0
    x = ver_r.x;
795 0
    y = ver_r.y;
796 0
    return *this;
797
  }
798

799

800
  T x;
801
  T y;
802
};
803

804 1
Object_Lifetime_Vector2<float> Object_Lifetime_Vector2_GetValue()
805
{
806 1
  return Object_Lifetime_Vector2<float>(10,15);
807
}
808

809 1
TEST_CASE("Object lifetime test 2")
810
{
811 1
  chaiscript::ChaiScript_Basic _script(create_chaiscript_stdlib(),create_chaiscript_parser());
812

813
  //Registering stuff
814 1
  _script.add(chaiscript::user_type<Object_Lifetime_Vector2<float>>(), "Object_Lifetime_Vector2f");
815 1
  _script.add(chaiscript::constructor<Object_Lifetime_Vector2<float> ()>(), "Object_Lifetime_Vector2f");
816 1
  _script.add(chaiscript::constructor<Object_Lifetime_Vector2<float> (float, float)>(), "Object_Lifetime_Vector2f");
817 1
  _script.add(chaiscript::constructor<Object_Lifetime_Vector2<float> (const Object_Lifetime_Vector2<float>&)>(), "Object_Lifetime_Vector2f");
818 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2<float>::x), "x");
819 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2<float>::y), "y");
820 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2<float>::operator +), "+");
821 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2<float>::operator +=), "+=");
822 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2<float>::operator =), "=");
823 1
  _script.add(chaiscript::fun(&Object_Lifetime_Vector2_GetValue), "getValue");
824

825 1
  _script.eval(R"(
826
    var test = 0.0
827
    var test2 = Object_Lifetime_Vector2f(10,10)
828

829
    test = getValue().x
830
    print(test)
831
    print(test2.x)
832
    )");
833

834 1
  CHECK(_script.eval<std::string>("to_string(test)") == "10");
835 1
  CHECK(_script.eval<std::string>("to_string(test2.x)") == "10");
836

837
}
838

839

840

841

842
///// Non-polymorphic base class conversions
843
class Non_Poly_Base {};
844
class Non_Poly_Derived : public Non_Poly_Base {};
845 1
int myfunction(Non_Poly_Base *)
846
{
847 1
  return 2;
848
}
849

850 1
TEST_CASE("Test Derived->Base with non-polymorphic classes")
851
{
852 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
853 1
  chai.add(chaiscript::base_class<Non_Poly_Base, Non_Poly_Derived>());
854
  Non_Poly_Derived d;
855 1
  chai.add(chaiscript::var(&d), "d");
856 1
  chai.add(chaiscript::fun(&myfunction), "myfunction");
857 1
  CHECK(chai.eval<int>("myfunction(d)") == 2);
858
}
859

860

861
struct TestCppVariableScope
862
{
863 0
  void print()
864
  {
865 0
    std::cout << "Printed" << std::endl;
866
  }
867
};
868

869 1
TEST_CASE("Variable Scope When Calling From C++")
870
{
871 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
872 1
  chai.add(chaiscript::user_type<TestCppVariableScope>(), "Test");
873 1
  chai.add(chaiscript::constructor<TestCppVariableScope()>(), "Test");
874 1
  chai.add(chaiscript::fun(&TestCppVariableScope::print), "print");
875 1
  chai.eval(R"(var t := Test();
876

877
      def func()
878
      {
879
        t.print();
880
      }
881

882
      )");
883

884
  CHECK_THROWS(chai.eval("func()"));
885

886 1
  chai.eval("dump_object(t)");
887

888 1
  auto func = chai.eval<std::function<void()>>("func");
889
  CHECK_THROWS(func());
890
}
891

892 1
TEST_CASE("Variable Scope When Calling From C++ 2")
893
{
894 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
895 1
  chai.eval("var obj = 2;");
896 1
  auto func = chai.eval<std::function<void()>>("fun(){ return obj; }");
897
  CHECK_THROWS(func());
898
}
899

900 1
void ulonglong(unsigned long long i) {
901 1
  std::cout << i << '\n';
902
}
903

904

905 1
void longlong(long long i) {
906 1
  std::cout << i << '\n';
907
}
908

909 1
TEST_CASE("Test long long dispatch")
910
{
911 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
912 1
  chai.add(chaiscript::fun(&longlong), "longlong");
913 1
  chai.add(chaiscript::fun(&ulonglong), "ulonglong");
914 1
  chai.eval("longlong(15)");
915 1
  chai.eval("ulonglong(15)");
916
}
917

918

919
struct Returned_Converted_Config
920
{
921
  int num_iterations;
922
  int something_else;
923
  std::string a_string;
924
  std::function<int (const std::string &)> a_function;
925
};
926

927

928

929 1
TEST_CASE("Return of converted type from script")
930
{
931 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
932

933 1
  chai.add(chaiscript::constructor<Returned_Converted_Config ()>(), "Returned_Converted_Config");
934 1
  chai.add(chaiscript::fun(&Returned_Converted_Config::num_iterations), "num_iterations");
935 1
  chai.add(chaiscript::fun(&Returned_Converted_Config::something_else), "something_else");
936 1
  chai.add(chaiscript::fun(&Returned_Converted_Config::a_string), "a_string");
937 1
  chai.add(chaiscript::fun(&Returned_Converted_Config::a_function), "a_function");
938 1
  chai.add(chaiscript::vector_conversion<std::vector<Returned_Converted_Config>>());
939

940
  auto c = chai.eval<std::vector<Returned_Converted_Config>>(R"(
941
    var c = Returned_Converted_Config();
942

943
    c.num_iterations = 5;
944
    c.something_else = c.num_iterations * 2;
945
    c.a_string = "string";
946
    c.a_function = fun(s) { s.size(); }
947

948
    print("making vector");
949
    var v = [];
950
    print("adding config item");
951
    v.push_back_ref(c);
952
    print("returning vector");
953
    v;
954

955 1
  )");
956

957

958 1
  std::cout << typeid(decltype(c)).name() << std::endl;
959

960 1
  std::cout << "Info: " << c.size() << " " << &c[0] << std::endl;
961

962 1
  std::cout << "num_iterations " << c[0].num_iterations << '\n'
963 1
            << "something_else " << c[0].something_else << '\n'
964 1
            << "a_string " << c[0].a_string << '\n'
965 1
            << "a_function " << c[0].a_function("bob") << '\n';
966

967 1
  chai.add(chaiscript::user_type<Returned_Converted_Config>(), "Returned_Converted_Config");
968
}
969

970

971 1
int get_value_a(const std::map<std::string, int> &t_m)
972
{
973 1
  return t_m.at("a");
974
}
975

976

977 1
TEST_CASE("Map conversions")
978
{
979 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
980 1
  chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
981 1
  chai.add(chaiscript::fun(&get_value_a), "get_value_a");
982

983 1
  const auto c = chai.eval<int>(R"(
984
    var m = ["a": 42];
985
    get_value_a(m);
986 1
  )");
987

988 1
  CHECK(c == 42);
989
}
990

991

992 1
TEST_CASE("Parse floats with non-posix locale")
993
{
994
#ifdef CHAISCRIPT_MSVC
995
  std::setlocale(LC_ALL, "en-ZA");
996
#else
997 1
  std::setlocale(LC_ALL, "en_ZA.utf8");
998
#endif
999 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1000 1
  const double parsed = chai.eval<double>("print(1.3); 1.3");
1001 1
  CHECK(parsed == Approx(1.3));
1002 1
  const std::string str = chai.eval<std::string>("to_string(1.3)");
1003 1
  CHECK(str == "1.3");
1004
}
1005

1006

1007

1008 1
bool FindBitmap(int &ox, int &oy, long) {
1009 1
  ox = 1; 
1010 1
  oy = 2; 
1011 1
  return true;
1012
}
1013

1014 1
TEST_CASE("Mismatched numeric types only convert necessary params")
1015
{
1016 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1017

1018 1
  chai.add(chaiscript::fun(&FindBitmap), "FindBitmap");
1019 1
  int x = 0;
1020 1
  int y = 0;
1021 1
  chai.add(chaiscript::var(&x), "x");
1022 1
  chai.add(chaiscript::var(&y), "y");
1023 1
  chai.eval( "if ( FindBitmap ( x, y, 0) ) { print(\"found at \" + to_string(x) + \", \" + to_string(y))}" );
1024 1
  CHECK(x == 1);
1025 1
  CHECK(y == 2);
1026

1027
}
1028

1029 1
TEST_CASE("type_conversion to bool")
1030
{
1031 1
  auto module = std::make_shared<chaiscript::Module>();
1032
  struct T {
1033 0
    operator bool() const { return true; }
1034
  };
1035 1
  module->add(chaiscript::type_conversion<T, bool>());
1036
}
1037

1038 1
TEST_CASE("Make sure ChaiScript object still compiles / executes")
1039
{
1040 1
  chaiscript::ChaiScript chai;
1041
}
1042

1043
struct Count_Tracer
1044
{
1045
  int count = 0;
1046
  template<typename T>
1047 1
    void trace(const chaiscript::detail::Dispatch_State &, const chaiscript::eval::AST_Node_Impl<T> *)
1048
    {
1049 1
      ++count;
1050
    }
1051
};
1052

1053

1054 1
TEST_CASE("Test count tracer")
1055
{
1056
  typedef chaiscript::parser::ChaiScript_Parser< chaiscript::eval::Tracer<Count_Tracer>, chaiscript::optimizer::Optimizer_Default >  Parser_Type;
1057

1058 1
  chaiscript::ChaiScript_Basic chai(chaiscript::Std_Lib::library(),
1059 1
      std::make_unique<Parser_Type>());
1060

1061
  Parser_Type &parser = dynamic_cast<Parser_Type &>(chai.get_parser());
1062

1063 1
  const auto count = parser.get_tracer().count;
1064

1065 1
  chai.eval("");
1066

1067 1
  CHECK(parser.get_tracer().count > count);
1068
}
1069

1070

1071 1
TEST_CASE("Test stdlib options")
1072
{
1073 1
  const auto test_has_external_scripts = [](chaiscript::ChaiScript_Basic &chai) { 
1074 1
    CHECK_NOTHROW(chai.eval("`use`"));
1075 1
    CHECK_NOTHROW(chai.eval("`eval_file`"));
1076 1
  };
1077

1078 1
  const auto test_no_external_scripts = [](chaiscript::ChaiScript_Basic &chai) { 
1079
    CHECK_THROWS(chai.eval("`use`"));
1080
    CHECK_THROWS(chai.eval("`eval_file`"));
1081 1
  };
1082

1083 1
  const auto test_has_load_modules = [](chaiscript::ChaiScript_Basic &chai) { 
1084 1
    CHECK_NOTHROW(chai.eval("`load_module`"));
1085 1
  };
1086

1087 1
  const auto test_no_load_modules = [](chaiscript::ChaiScript_Basic &chai) { 
1088
    CHECK_THROWS(chai.eval("`load_module`"));
1089 1
  };
1090

1091 1
  SECTION( "Defaults" ) {
1092 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1093 1
    test_has_external_scripts(chai);
1094 1
    test_has_load_modules(chai);
1095
  }
1096

1097 1
  SECTION( "Load_Modules, External_Scripts" ) {
1098 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1099 1
        {chaiscript::Options::Load_Modules, chaiscript::Options::External_Scripts} );
1100 1
    test_has_external_scripts(chai);
1101 1
    test_has_load_modules(chai);
1102
  }
1103

1104 1
  SECTION( "No_Load_Modules, No_External_Scripts" ) {
1105 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1106 1
        {chaiscript::Options::No_Load_Modules, chaiscript::Options::No_External_Scripts} );
1107 1
    test_no_external_scripts(chai);
1108 1
    test_no_load_modules(chai);
1109
  }
1110

1111 1
  SECTION( "No_Load_Modules, Load_Modules" ) {
1112 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1113 1
        {chaiscript::Options::No_Load_Modules, chaiscript::Options::Load_Modules} );
1114 1
    test_no_external_scripts(chai);
1115 1
    test_no_load_modules(chai);
1116
  }
1117

1118 1
  SECTION( "No_External_Scripts, External_Scripts" ) {
1119 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1120 1
        {chaiscript::Options::No_External_Scripts, chaiscript::Options::External_Scripts} );
1121 1
    test_no_external_scripts(chai);
1122 1
    test_no_load_modules(chai);
1123
  }
1124

1125 1
  SECTION( "No_External_Scripts, Load_Modules" ) {
1126 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1127 1
        {chaiscript::Options::No_External_Scripts, chaiscript::Options::Load_Modules} );
1128 1
    test_no_external_scripts(chai);
1129 1
    test_has_load_modules(chai);
1130
  }
1131

1132 1
  SECTION( "External_Scripts, No_Load_Modules" ) {
1133 1
    chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser(), {}, {}, 
1134 1
        {chaiscript::Options::External_Scripts, chaiscript::Options::No_Load_Modules} );
1135 1
    test_has_external_scripts(chai);
1136 1
    test_no_load_modules(chai);
1137
  }
1138
}
1139

1140

1141 0
void uservalueref(int &&)
1142
{
1143
}
1144

1145 1
void usemoveonlytype(std::unique_ptr<int> &&)
1146
{
1147
}
1148

1149

1150 1
TEST_CASE("Pass r-value reference to func")
1151
{
1152 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1153

1154 1
  chai.add(chaiscript::fun(&uservalueref), "uservalueref");
1155 1
  chai.add(chaiscript::fun(&usemoveonlytype), "usemoveonlytype");
1156

1157 1
  chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
1158 1
  chai.eval("usemoveonlytype(iptr)");
1159
}
1160

1161 1
TEST_CASE("Use unique_ptr")
1162
{
1163 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1164

1165 1
  chai.add(chaiscript::fun([](int &i){ ++i; }), "inci");
1166 1
  chai.add(chaiscript::fun([](int i){ ++i; }), "copyi");
1167 1
  chai.add(chaiscript::fun([](int *i){ ++(*i); }), "derefi");
1168 1
  chai.add(chaiscript::fun([](const std::unique_ptr<int> &i){ ++(*i); }), "constrefuniqptri");
1169 1
  chai.add(chaiscript::fun([](std::unique_ptr<int> &i){ ++(*i); }), "refuniqptri");
1170 1
  chai.add(chaiscript::fun([](std::unique_ptr<int> &&i){ ++(*i); }), "rvaluniqptri");
1171 1
  chai.add(chaiscript::var(std::make_unique<int>(1)), "iptr");
1172

1173

1174 1
  CHECK(chai.eval<int>("iptr") == 1);
1175 1
  chai.eval("inci(iptr)");
1176 1
  CHECK(chai.eval<int>("iptr") == 2);
1177 1
  chai.eval("copyi(iptr)");
1178 1
  CHECK(chai.eval<int>("iptr") == 2);
1179 1
  chai.eval("derefi(iptr)");
1180 1
  CHECK(chai.eval<int>("iptr") == 3);
1181 1
  chai.eval("constrefuniqptri(iptr)");
1182 1
  CHECK(chai.eval<int>("iptr") == 4);
1183 1
  chai.eval("refuniqptri(iptr)");
1184 1
  CHECK(chai.eval<int>("iptr") == 5);
1185 1
  chai.eval("rvaluniqptri(iptr)");
1186 1
  CHECK(chai.eval<int>("iptr") == 6);
1187
}
1188

1189

1190
class Unique_Ptr_Test_Class
1191
{
1192
  public:
1193 1
    Unique_Ptr_Test_Class() = default;
1194
    Unique_Ptr_Test_Class(const Unique_Ptr_Test_Class&) = default;
1195
    Unique_Ptr_Test_Class(Unique_Ptr_Test_Class &&) = default;
1196
    Unique_Ptr_Test_Class &operator=(const Unique_Ptr_Test_Class&) = default;
1197
    Unique_Ptr_Test_Class &operator=(Unique_Ptr_Test_Class&&) = default;
1198 1
    virtual ~Unique_Ptr_Test_Class() = default;
1199

1200 1
    int getI() const {return 5;}
1201
};
1202

1203

1204 1
std::unique_ptr<Unique_Ptr_Test_Class> make_Unique_Ptr_Test_Class()
1205
{
1206 1
  return std::make_unique<Unique_Ptr_Test_Class>();
1207
}
1208

1209 1
TEST_CASE("Call methods through unique_ptr")
1210
{
1211 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1212

1213 1
  chai.add(chaiscript::var(std::make_unique<Unique_Ptr_Test_Class>()), "uptr");
1214 1
  chai.add(chaiscript::fun(make_Unique_Ptr_Test_Class), "make_Unique_Ptr_Test_Class");
1215 1
  chai.add(chaiscript::fun(&Unique_Ptr_Test_Class::getI), "getI");
1216 1
  CHECK(chai.eval<int>("uptr.getI()") == 5);
1217 1
  CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Class(); uptr2.getI()") == 5);
1218
}
1219

1220

1221
class Unique_Ptr_Test_Base_Class
1222
{
1223
  public:
1224 1
    int getI() const {return 5;}
1225
};
1226

1227
class Unique_Ptr_Test_Derived_Class : public Unique_Ptr_Test_Base_Class
1228
{};
1229

1230 1
std::unique_ptr<Unique_Ptr_Test_Derived_Class> make_Unique_Ptr_Test_Derived_Class()
1231
{
1232 1
  return std::make_unique<Unique_Ptr_Test_Derived_Class>();
1233
}
1234

1235 1
TEST_CASE("Call methods on base class through unique_ptr<derived>")
1236
{
1237 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1238

1239 1
  chai.add(chaiscript::var(std::make_unique<Unique_Ptr_Test_Derived_Class>()), "uptr");
1240 1
  chai.add(chaiscript::fun(make_Unique_Ptr_Test_Derived_Class), "make_Unique_Ptr_Test_Derived_Class");
1241 1
  chai.add(chaiscript::fun(&Unique_Ptr_Test_Base_Class::getI), "getI");
1242 1
  chai.add(chaiscript::base_class<Unique_Ptr_Test_Base_Class, Unique_Ptr_Test_Derived_Class>());
1243 1
  CHECK(chai.eval<int>("uptr.getI()") == 5);
1244 1
  CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Derived_Class(); uptr2.getI()") == 5);
1245
}
1246

1247

1248
class A
1249
{
1250
  public:
1251 1
    A() = default;
1252
    A(const A&) = default;
1253
    A(A &&) = default;
1254
    A &operator=(const A&) = default;
1255
    A &operator=(A&&) = default;
1256 1
    virtual ~A() = default;
1257
};
1258

1259
class B : public A
1260
{
1261
  public:
1262 1
    B() = default;
1263
};
1264

1265 1
TEST_CASE("Test typed chaiscript functions to perform conversions")
1266
{
1267 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1268

1269
  //-------------------------------------------------------------------------
1270

1271 1
  chai.add(chaiscript::user_type<A>(), "A");
1272

1273 1
  chai.add(chaiscript::user_type<B>(), "B");
1274 1
  chai.add(chaiscript::base_class<A, B>());
1275

1276 1
  chai.add(chaiscript::fun([](const B &)
1277
        {
1278 1
        }), "CppFunctWithBArg");
1279

1280 1
  chai.add(chaiscript::fun([]() -> std::shared_ptr<A> 
1281
        {
1282 1
        return (std::shared_ptr<A>(new B()));
1283 1
        }), "Create");
1284

1285 1
  chai.eval(R"(
1286
            var inst = Create() // A*
1287

1288
            // it prints "A"
1289
            inst.type_name().print() 
1290

1291
            // Ok it is casted using conversion
1292
            CppFunctWithBArg(inst)
1293

1294
            // Define a function with B as argument
1295
            def ChaiFuncWithBArg(B inst)
1296
            {
1297
                    print("ok")
1298
            }
1299

1300
            // don't work
1301
            ChaiFuncWithBArg(inst)
1302
            )");
1303
}
1304

1305
struct Reference_MyClass
1306
{
1307 1
  Reference_MyClass(double& t_x) : x(t_x) {}
1308
  double& x;
1309
};
1310

1311 1
TEST_CASE("Test reference member being registered")
1312
{
1313 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1314
  // Note, C++ will not allow us to do this:
1315
  // chai.add(chaiscript::fun(&Reference_MyClass::x) , "x");
1316 1
  chai.add(chaiscript::fun([](Reference_MyClass &r) -> decltype(auto) { return (r.x); }), "x");
1317
  chai.add(chaiscript::fun([](const Reference_MyClass &r) -> decltype(auto) { return (r.x); }), "x");
1318
  double d;
1319 1
  chai.add(chaiscript::var(Reference_MyClass(d)), "ref");
1320 1
  chai.eval("ref.x = 2.3");
1321 1
  CHECK(d == Approx(2.3));
1322
}
1323

1324 1
TEST_CASE("Test unicode matches C++")
1325
{
1326 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1327 1
  CHECK(u8"\U000000AC" == chai.eval<std::string>(R"("\U000000AC")"));
1328 1
  CHECK("\xF0\x9F\x8D\x8C" == chai.eval<std::string>(R"("\xF0\x9F\x8D\x8C")"));
1329 1
  CHECK(u8"\U0001F34C" == chai.eval<std::string>(R"("\U0001F34C")"));
1330 1
  CHECK(u8"\u2022" == chai.eval<std::string>(R"("\u2022")"));
1331

1332
}
1333

1334

1335 1
const int add_3(const int &i)
1336
{
1337 1
  return i + 3;
1338
}
1339

1340 1
TEST_CASE("Test returning by const non-reference")
1341
{
1342 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1343
  // Note, C++ will not allow us to do this:
1344
  // chai.add(chaiscript::fun(&Reference_MyClass::x) , "x");
1345 1
  chai.add(chaiscript::fun(&add_3), "add_3");
1346 1
  auto v = chai.eval<int>("add_3(12)");
1347 1
  CHECK(v == 15);
1348
}
1349

1350

1351
struct MyException : std::runtime_error
1352
{
1353
  using std::runtime_error::runtime_error;
1354
  int value = 5;
1355
};
1356

1357 1
void throws_a_thing()
1358
{
1359 1
  throw MyException("Hello World");
1360
}
1361

1362 1
TEST_CASE("Test throwing and catching custom exception")
1363
{
1364 1
  chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
1365 1
  chai.add(chaiscript::user_type<MyException>(), "MyException");
1366 1
  chai.add(chaiscript::base_class<std::runtime_error, MyException>()); // be sure to register base class relationship
1367 1
  chai.add(chaiscript::fun(&throws_a_thing), "throws_a_thing");
1368 1
  chai.add(chaiscript::fun(&MyException::value), "value");
1369

1370 1
  const auto s = chai.eval<std::string>("fun(){ try { throws_a_thing(); } catch (MyException ex) { return ex.what(); } }()");
1371 1
  CHECK(s == "Hello World");
1372

1373
  // this has an explicit clone to prevent returning a pointer to the `value` from inside of MyException
1374 1
  const auto i = chai.eval<int>("fun(){ try { throws_a_thing(); } catch (MyException ex) { var v = clone(ex.value); print(v); return v; } }()");
1375 1
  CHECK(i == 5);
1376
}
1377

1378

1379 1
TEST_CASE("Test ability to get 'use' function from default construction")
1380
{
1381 1
  chaiscript::ChaiScript chai;
1382 1
  const auto use_function = chai.eval<std::function<chaiscript::Boxed_Value (const std::string &)>>("use");
1383
}
1384

1385 1
TEST_CASE("Throw an exception when trying to add same conversion twice")
1386
{
1387
  struct my_int {
1388
      int value;
1389 0
      my_int(int val): value(val) {};
1390
  };
1391

1392 1
  chaiscript::ChaiScript chai;
1393
  chai.add(chaiscript::type_conversion<int, my_int>([](int x) {
1394 0
      std::cout << "My_int type conversion 1\n";
1395 0
      return my_int(x);
1396 1
  }));
1397
  CHECK_THROWS_AS(chai.add(chaiscript::type_conversion<int, my_int>([](int x) {
1398
      std::cout << "My_int type conversion 2\n";
1399
      return my_int(x);
1400
  })), chaiscript::exception::conversion_error);
1401

1402
}
1403

1404

Read our documentation on viewing source code .

Loading