rice 4.0.4 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -0
  3. data/Rakefile +1 -1
  4. data/include/rice/rice.hpp +2596 -1771
  5. data/include/rice/stl.hpp +1580 -271
  6. data/lib/mkmf-rice.rb +5 -2
  7. data/lib/version.rb +1 -1
  8. data/rice/Arg.hpp +6 -6
  9. data/rice/Arg.ipp +8 -9
  10. data/rice/Constructor.hpp +2 -2
  11. data/rice/Data_Object.ipp +69 -15
  12. data/rice/Data_Object_defn.hpp +1 -15
  13. data/rice/Data_Type.ipp +56 -86
  14. data/rice/Data_Type_defn.hpp +14 -17
  15. data/rice/Director.hpp +0 -1
  16. data/rice/Enum.ipp +31 -22
  17. data/rice/Exception.ipp +2 -3
  18. data/rice/Exception_defn.hpp +5 -5
  19. data/rice/HandlerRegistration.hpp +15 -0
  20. data/rice/Return.hpp +5 -4
  21. data/rice/Return.ipp +8 -3
  22. data/rice/detail/ExceptionHandler.hpp +8 -0
  23. data/rice/detail/ExceptionHandler.ipp +28 -0
  24. data/rice/detail/{Exception_Handler_defn.hpp → ExceptionHandler_defn.hpp} +17 -21
  25. data/rice/detail/HandlerRegistry.hpp +51 -0
  26. data/rice/detail/HandlerRegistry.ipp +20 -0
  27. data/rice/detail/InstanceRegistry.hpp +34 -0
  28. data/rice/detail/InstanceRegistry.ipp +50 -0
  29. data/rice/detail/MethodInfo.ipp +1 -1
  30. data/rice/detail/NativeAttribute.hpp +26 -15
  31. data/rice/detail/NativeAttribute.ipp +76 -47
  32. data/rice/detail/NativeFunction.hpp +60 -13
  33. data/rice/detail/NativeFunction.ipp +103 -85
  34. data/rice/detail/NativeIterator.hpp +49 -0
  35. data/rice/detail/NativeIterator.ipp +102 -0
  36. data/rice/detail/NativeRegistry.hpp +31 -0
  37. data/rice/detail/{method_data.ipp → NativeRegistry.ipp} +20 -16
  38. data/rice/detail/Registries.hpp +26 -0
  39. data/rice/detail/Registries.ipp +23 -0
  40. data/rice/detail/RubyFunction.hpp +6 -11
  41. data/rice/detail/RubyFunction.ipp +10 -22
  42. data/rice/detail/Type.hpp +1 -1
  43. data/rice/detail/Type.ipp +2 -2
  44. data/rice/detail/TypeRegistry.hpp +8 -11
  45. data/rice/detail/TypeRegistry.ipp +3 -28
  46. data/rice/detail/Wrapper.hpp +0 -2
  47. data/rice/detail/Wrapper.ipp +73 -23
  48. data/rice/detail/cpp_protect.hpp +93 -0
  49. data/rice/detail/default_allocation_func.ipp +1 -1
  50. data/rice/detail/from_ruby.ipp +206 -2
  51. data/rice/detail/to_ruby.ipp +39 -5
  52. data/rice/detail/to_ruby_defn.hpp +1 -1
  53. data/rice/forward_declares.ipp +6 -0
  54. data/rice/global_function.hpp +0 -4
  55. data/rice/global_function.ipp +0 -6
  56. data/rice/rice.hpp +29 -24
  57. data/rice/stl.hpp +6 -1
  58. data/test/embed_ruby.cpp +0 -15
  59. data/test/test_Array.cpp +20 -24
  60. data/test/test_Class.cpp +8 -47
  61. data/test/test_Constructor.cpp +0 -2
  62. data/test/test_Data_Object.cpp +25 -11
  63. data/test/test_Data_Type.cpp +124 -28
  64. data/test/test_Director.cpp +12 -13
  65. data/test/test_Enum.cpp +65 -26
  66. data/test/test_Inheritance.cpp +9 -9
  67. data/test/test_Iterator.cpp +134 -5
  68. data/test/test_Keep_Alive.cpp +7 -7
  69. data/test/test_Memory_Management.cpp +1 -1
  70. data/test/test_Module.cpp +25 -62
  71. data/test/test_Object.cpp +66 -3
  72. data/test/test_Ownership.cpp +12 -13
  73. data/test/test_Self.cpp +12 -13
  74. data/test/test_Stl_Map.cpp +696 -0
  75. data/test/test_Stl_Optional.cpp +3 -3
  76. data/test/test_Stl_Pair.cpp +38 -2
  77. data/test/test_Stl_Reference_Wrapper.cpp +102 -0
  78. data/test/test_Stl_SmartPointer.cpp +5 -5
  79. data/test/test_Stl_Unordered_Map.cpp +697 -0
  80. data/test/test_Stl_Variant.cpp +301 -0
  81. data/test/test_Stl_Vector.cpp +200 -41
  82. data/test/test_Struct.cpp +3 -3
  83. data/test/test_To_From_Ruby.cpp +6 -0
  84. data/test/test_Tracking.cpp +239 -0
  85. data/test/unittest.hpp +13 -4
  86. metadata +23 -13
  87. data/rice/detail/Exception_Handler.hpp +0 -8
  88. data/rice/detail/Exception_Handler.ipp +0 -28
  89. data/rice/detail/Iterator.hpp +0 -23
  90. data/rice/detail/Iterator.ipp +0 -47
  91. data/rice/detail/function_traits.hpp +0 -124
  92. data/rice/detail/method_data.hpp +0 -29
  93. data/rice/detail/rice_traits.hpp +0 -116
  94. data/rice/ruby_try_catch.hpp +0 -86
@@ -0,0 +1,696 @@
1
+ #include <complex>
2
+ #include <memory>
3
+
4
+ #include "unittest.hpp"
5
+ #include "embed_ruby.hpp"
6
+ #include <rice/rice.hpp>
7
+ #include <rice/stl.hpp>
8
+
9
+ using namespace Rice;
10
+
11
+ TESTSUITE(Map);
12
+
13
+ SETUP(Map)
14
+ {
15
+ embed_ruby();
16
+ }
17
+
18
+ namespace
19
+ {
20
+
21
+ class MyClass
22
+ {
23
+ public:
24
+ std::map<std::string, std::string> stringMap()
25
+ {
26
+ std::map<std::string, std::string> result{ {"One", "1"}, {"Two", "2"}, {"Three", "3"} };
27
+ return result;
28
+ }
29
+ };
30
+ }
31
+
32
+ Class makeMapClass()
33
+ {
34
+ Class c = define_class<MyClass>("MyClass").
35
+ define_constructor(Constructor<MyClass>()).
36
+ define_method("stringMap", &MyClass::stringMap);
37
+
38
+ return c;
39
+ }
40
+
41
+ TESTCASE(StringMap)
42
+ {
43
+ Module m = define_module("Testing");
44
+
45
+ Class c = define_map<std::map<std::string, std::string>>("StringMap");
46
+
47
+ Object map = m.module_eval("$map = StringMap.new");
48
+ Object result = map.call("size");
49
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
50
+
51
+ m.module_eval("$map['a_key'] = 'a_value'");
52
+ result = map.call("size");
53
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
54
+
55
+ m.module_eval("$map.clear");
56
+ result = map.call("size");
57
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
58
+ }
59
+
60
+ TESTCASE(WrongType)
61
+ {
62
+ Module m = define_module("Testing");
63
+
64
+ Class c = define_map<std::map<std::string, std::string>>("StringMap");
65
+ Object map = m.module_eval("$map = StringMap.new");
66
+
67
+ ASSERT_EXCEPTION_CHECK(
68
+ Exception,
69
+ m.module_eval("$map[1] = 'abc'"),
70
+ ASSERT_EQUAL("wrong argument type Integer (expected String)", ex.what()));
71
+
72
+ ASSERT_EXCEPTION_CHECK(
73
+ Exception,
74
+ m.module_eval("$map['abc'] = true"),
75
+ ASSERT_EQUAL("wrong argument type true (expected String)", ex.what()));
76
+ }
77
+
78
+ TESTCASE(Empty)
79
+ {
80
+ Module m = define_module("Testing");
81
+
82
+ Class c = define_map<std::map<std::string, std::int32_t>>("IntMap");
83
+ Object map = c.call("new");
84
+
85
+ Object result = map.call("size");
86
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
87
+
88
+ result = map.call("empty?");
89
+ ASSERT_EQUAL(Qtrue, result.value());
90
+ }
91
+
92
+ TESTCASE(Include)
93
+ {
94
+ Module m = define_module("Testing");
95
+
96
+ Class c = define_map<std::map<std::string, std::int32_t>>("IntMap");
97
+ Object map = c.call("new");
98
+ map.call("[]=", "one", 1);
99
+ map.call("[]=", "two", 2);
100
+
101
+ Object result = map.call("include?", "two");
102
+ ASSERT_EQUAL(Qtrue, result.value());
103
+
104
+ result = map.call("include?", "three");
105
+ ASSERT_EQUAL(Qfalse, result.value());
106
+
107
+ result = map.call("[]", "three");
108
+ ASSERT_EQUAL(Qnil, result.value());
109
+ }
110
+
111
+ TESTCASE(Value)
112
+ {
113
+ Module m = define_module("Testing");
114
+
115
+ Class c = define_map<std::map<std::string, std::int32_t>>("IntMap");
116
+ Object map = c.call("new");
117
+ map.call("[]=", "one", 1);
118
+ map.call("[]=", "two", 2);
119
+
120
+ Object result = map.call("value?", 2);
121
+ ASSERT_EQUAL(Qtrue, result.value());
122
+
123
+ result = map.call("value?", 4);
124
+ ASSERT_EQUAL(Qfalse, result.value());
125
+ }
126
+
127
+ TESTCASE(ToString)
128
+ {
129
+ Module m = define_module("Testing");
130
+
131
+ Class c = define_map<std::map<std::string, std::int32_t>>("IntMap");
132
+ Object map = c.call("new");
133
+ map.call("[]=", "one", 1);
134
+ map.call("[]=", "two", 2);
135
+
136
+ Object result = map.call("to_s");
137
+ ASSERT_EQUAL("{one => 1, two => 2}", detail::From_Ruby<std::string>().convert(result));
138
+
139
+ map.call("clear");
140
+
141
+ result = map.call("to_s");
142
+ ASSERT_EQUAL("{}", detail::From_Ruby<std::string>().convert(result));
143
+ }
144
+
145
+ TESTCASE(Update)
146
+ {
147
+ Module m = define_module("Testing");
148
+
149
+ Class c = define_map<std::map<std::string, std::string>>("StringMap");
150
+ Object map = c.call("new");
151
+ map.call("[]=", "one", "original 1");
152
+ map.call("[]=", "two", "original 2");
153
+
154
+ Object result = map.call("size");
155
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
156
+
157
+ result = map.call("[]=", "two", "new 2");
158
+ ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
159
+
160
+ result = map.call("size");
161
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
162
+
163
+ result = map.call("[]", "two");
164
+ ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
165
+ }
166
+
167
+ TESTCASE(Modify)
168
+ {
169
+ Module m = define_module("Testing");
170
+
171
+ Class c = define_map<std::map<std::string, int64_t>>("Int64Map");
172
+ Object map = c.call("new");
173
+
174
+ Object result = map.call("[]=", "one", 3232323232);
175
+
176
+ result = map.call("size");
177
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
178
+
179
+ result = map.call("delete", "one");
180
+ ASSERT_EQUAL(3232323232, detail::From_Ruby<int64_t>().convert(result));
181
+
182
+ result = map.call("size");
183
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
184
+ }
185
+
186
+ TESTCASE(keysAndValues)
187
+ {
188
+ Module m = define_module("Testing");
189
+
190
+ Class c = define_map<std::map<std::string, int32_t>>("Int32Map");
191
+ Object map = c.call("new");
192
+
193
+ map.call("[]=", "one", 1);
194
+ map.call("[]=", "two", 2);
195
+ map.call("[]=", "three", 3);
196
+
197
+ // Keys returns a std::vector
198
+ Data_Object<std::vector<std::string>> keys = map.call("keys");
199
+ std::vector<std::string> expected_keys{ {"one", "three", "two"} };
200
+ ASSERT_EQUAL(3u, keys->size());
201
+ ASSERT_EQUAL(expected_keys[0], keys->operator[](0));
202
+ ASSERT_EQUAL(expected_keys[1], keys->operator[](1));
203
+ ASSERT_EQUAL(expected_keys[2], keys->operator[](2));
204
+
205
+ // Keys returns a std::vector
206
+ Data_Object<std::vector<std::int32_t>> values = map.call("values");
207
+ std::vector<std::int32_t> expected_values{ {1, 3, 2} };
208
+ ASSERT_EQUAL(3u, values->size());
209
+ ASSERT_EQUAL(expected_values[0], values->operator[](0));
210
+ ASSERT_EQUAL(expected_values[1], values->operator[](1));
211
+ ASSERT_EQUAL(expected_values[2], values->operator[](2));
212
+ }
213
+
214
+ TESTCASE(Copy)
215
+ {
216
+ Module m = define_module("Testing");
217
+
218
+ Class c = define_map<std::map<std::string, double>>("DoubleMap");
219
+ Object object = c.call("new");
220
+
221
+ object.call("[]=", "one", 11.1);
222
+ object.call("[]=", "two", 22.2);
223
+ std::map<std::string, double>& map = detail::From_Ruby<std::map<std::string, double>&>().convert(object);
224
+
225
+ Object result = object.call("copy");
226
+ std::map<std::string, double>& mapCopy = detail::From_Ruby<std::map<std::string, double>&>().convert(result);
227
+
228
+ ASSERT_EQUAL(map.size(), mapCopy.size());
229
+ ASSERT_EQUAL(map["one"], mapCopy["one"]);
230
+ ASSERT_EQUAL(map["two"], mapCopy["two"]);
231
+
232
+ mapCopy["three"] = 33.3;
233
+ ASSERT_NOT_EQUAL(map.size(), mapCopy.size());
234
+ }
235
+
236
+ TESTCASE(Iterate)
237
+ {
238
+ Module m = define_module("Testing");
239
+ Class c = define_map<std::map<std::string, int>>("IntMap");
240
+
241
+ std::string code = R"(map = IntMap.new
242
+ map["five"] = 5
243
+ map["six"] = 6
244
+ map["seven"] = 7
245
+
246
+ result = Hash.new
247
+ map.map do |pair|
248
+ result[pair.first] = 2 * pair.second
249
+ end
250
+ result)";
251
+
252
+ Hash result = m.module_eval(code);
253
+ ASSERT_EQUAL(3u, result.size());
254
+
255
+ std::string result_string = result.to_s().str();
256
+ ASSERT_EQUAL("{\"five\"=>10, \"seven\"=>14, \"six\"=>12}", result_string);
257
+ }
258
+
259
+ TESTCASE(ToEnum)
260
+ {
261
+ Module m = define_module("Testing");
262
+ Class c = define_map<std::map<std::string, int>>("IntMap");
263
+
264
+ std::string code = R"(map = IntMap.new
265
+ map["five"] = 5
266
+ map["six"] = 6
267
+ map["seven"] = 7
268
+
269
+ result = Hash.new
270
+ map.each.each do |pair|
271
+ result[pair.first] = 2 * pair.second
272
+ end
273
+ result)";
274
+
275
+ Hash result = m.module_eval(code);
276
+ ASSERT_EQUAL(3u, result.size());
277
+
278
+ std::string result_string = result.to_s().str();
279
+ ASSERT_EQUAL("{\"five\"=>10, \"seven\"=>14, \"six\"=>12}", result_string);
280
+ }
281
+
282
+ TESTCASE(ToEnumSize)
283
+ {
284
+ Module m = define_module("TestingModule");
285
+ Class c = define_map<std::map<std::string, int>>("IntMap");
286
+
287
+ std::string code = R"(map = IntMap.new
288
+ map["five"] = 5
289
+ map["six"] = 6
290
+ map["seven"] = 7
291
+ map["eight"] = 7
292
+ map)";
293
+
294
+ Object map = m.module_eval(code);
295
+ Object enumerable = map.call("each");
296
+ Object result = enumerable.call("size");
297
+
298
+ ASSERT_EQUAL(4, detail::From_Ruby<int>().convert(result));
299
+ }
300
+
301
+ namespace
302
+ {
303
+ class NotComparable
304
+ {
305
+ public:
306
+ NotComparable(uint32_t value) : value_(value)
307
+ {
308
+ };
309
+
310
+ NotComparable() = default;
311
+
312
+ uint32_t value_;
313
+ };
314
+ }
315
+
316
+ TESTCASE(NotComparable)
317
+ {
318
+ define_class<NotComparable>("NotComparable").
319
+ define_constructor(Constructor<NotComparable, uint32_t>());
320
+
321
+ Class c = define_map<std::map<std::string, NotComparable>>("NotComparableMap");
322
+
323
+ Object map = c.call("new");
324
+ map.call("[]=", "one", NotComparable(1));
325
+ map.call("[]=", "two", NotComparable(2));
326
+ map.call("[]=", "three", NotComparable(3));
327
+
328
+ Object result = map.call("include?", "two");
329
+ ASSERT_EQUAL(Qtrue, result.value());
330
+
331
+ result = map.call("value?", NotComparable(3));
332
+ ASSERT_EQUAL(Qfalse, result.value());
333
+ }
334
+
335
+ TESTCASE(NotPrintable)
336
+ {
337
+ define_class<NotComparable>("NotComparable").
338
+ define_constructor(Constructor<NotComparable, uint32_t>());
339
+
340
+ Class c = define_map<std::map<std::string, NotComparable>>("NotComparableMap");
341
+
342
+ Object map = c.call("new");
343
+ map.call("[]=", "one", NotComparable(1));
344
+ map.call("[]=", "two", NotComparable(2));
345
+ map.call("[]=", "three", NotComparable(3));
346
+
347
+ Object result = map.call("to_s");
348
+ ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
349
+ }
350
+
351
+ namespace
352
+ {
353
+ class Comparable
354
+ {
355
+ public:
356
+ Comparable() = default;
357
+ Comparable(uint32_t value) : value_(value)
358
+ {
359
+ };
360
+
361
+ bool operator==(const Comparable& other)
362
+ {
363
+ return this->value_ == other.value_;
364
+ }
365
+
366
+ uint32_t value_;
367
+ };
368
+
369
+ inline std::ostream& operator<<(std::ostream& stream, Comparable const& comparable)
370
+ {
371
+ stream << "Comparable(" << std::to_string(comparable.value_) << ")";
372
+ return stream;
373
+ }
374
+ }
375
+
376
+ TESTCASE(Comparable)
377
+ {
378
+ define_class<Comparable>("IsComparable").
379
+ define_constructor(Constructor<Comparable, uint32_t>());
380
+
381
+ Class c = define_map<std::map<std::string, Comparable>>("ComparableMap");
382
+
383
+ Object map = c.call("new");
384
+
385
+ map.call("[]=", "one", Comparable(1));
386
+ map.call("[]=", "two", Comparable(2));
387
+ map.call("[]=", "three", Comparable(3));
388
+
389
+ Object result = map.call("value?", Comparable(2));
390
+ ASSERT_EQUAL(Qtrue, result.value());
391
+ }
392
+
393
+ TESTCASE(Printable)
394
+ {
395
+ define_class<Comparable>("IsComparable").
396
+ define_constructor(Constructor<Comparable, uint32_t>());
397
+
398
+ Class c = define_map<std::map<std::string, Comparable>>("ComparableMap");
399
+
400
+ Object map = c.call("new");
401
+ map.call("[]=", "one", Comparable(1));
402
+ map.call("[]=", "two", Comparable(2));
403
+ map.call("[]=", "three", Comparable(3));
404
+
405
+ Object result = map.call("to_s");
406
+ ASSERT_EQUAL("{one => Comparable(1), three => Comparable(3), two => Comparable(2)}", detail::From_Ruby<std::string>().convert(result));
407
+ }
408
+
409
+ namespace
410
+ {
411
+ std::map<std::string, std::complex<double>> returnComplexMap()
412
+ {
413
+ std::complex<double> complex1(1, 1);
414
+ std::complex<double> complex2(2, 2);
415
+ std::complex<double> complex3(3, 3);
416
+
417
+ std::map<std::string, std::complex<double>> result;
418
+ result["one"] = complex1;
419
+ result["two"] = complex2;
420
+ result["three"] = complex3;
421
+ return result;
422
+ }
423
+
424
+ std::map<std::string, std::complex<double>> passComplexMap(std::map<std::string, std::complex<double>>& complexes)
425
+ {
426
+ return complexes;
427
+ }
428
+ }
429
+
430
+ TESTCASE(AutoRegisterReturn)
431
+ {
432
+ define_global_function("return_complex_map", &returnComplexMap);
433
+
434
+ Module m = define_module("Testing");
435
+ Object map = m.module_eval("return_complex_map");
436
+ ASSERT_EQUAL("Rice::Std::Map__basic_string__char_char_traits__char___allocator__char_____complex__double___less__basic_string__char_char_traits__char___allocator__char_______allocator__pair__basic_string__char_char_traits__char___allocator__char____Const_complex__double________",
437
+ map.class_name().str());
438
+
439
+ std::string code = R"(map = return_complex_map
440
+ complex = map['three']
441
+ complex == Complex(3, 3))";
442
+
443
+ Object result = m.module_eval(code);
444
+ ASSERT_EQUAL(Qtrue, result.value());
445
+
446
+ // Now register the map again
447
+ define_map<std::map<std::string, std::complex<double>>>("ComplexMap");
448
+ code = R"(map = ComplexMap.new)";
449
+ result = m.module_eval(code);
450
+ ASSERT(result.is_instance_of(map.class_of()));
451
+
452
+ // And again in the module
453
+ define_map_under<std::map<std::string, std::complex<double>>>(m, "ComplexMap2");
454
+ code = R"(map = Testing::ComplexMap2.new)";
455
+ result = m.module_eval(code);
456
+ ASSERT(result.is_instance_of(map.class_of()));
457
+ }
458
+
459
+ TESTCASE(AutoRegisterParameter)
460
+ {
461
+ define_global_function("pass_complex_map", &passComplexMap);
462
+
463
+ std::string code = R"(map = Rice::Std::Map__basic_string__char_char_traits__char___allocator__char_____complex__double___less__basic_string__char_char_traits__char___allocator__char_______allocator__pair__basic_string__char_char_traits__char___allocator__char____Const_complex__double________.new
464
+ map["four"] = Complex(4.0, 4.0)
465
+ map["five"] = Complex(5.0, 5.0)
466
+ pass_complex_map(map))";
467
+
468
+ Module m = define_module("Testing");
469
+ Object map = m.module_eval(code);
470
+
471
+ Object result = map.call("size");
472
+ ASSERT_EQUAL("Rice::Std::Map__basic_string__char_char_traits__char___allocator__char_____complex__double___less__basic_string__char_char_traits__char___allocator__char_______allocator__pair__basic_string__char_char_traits__char___allocator__char____Const_complex__double________",
473
+ map.class_name().str());
474
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
475
+
476
+ std::map<std::string, std::complex<double>> complexes = detail::From_Ruby<std::map<std::string, std::complex<double>>>().convert(map);
477
+ ASSERT_EQUAL(complexes["four"], std::complex<double>(4, 4));
478
+ ASSERT_EQUAL(complexes["five"], std::complex<double>(5, 5));
479
+ }
480
+
481
+ namespace
482
+ {
483
+ std::map<std::string, std::string> defaultMap(std::map<std::string, std::string> strings = {{"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"}})
484
+ {
485
+ return strings;
486
+ }
487
+ }
488
+
489
+ TESTCASE(DefaultValue)
490
+ {
491
+ define_map<std::map<std::string, std::string>>("StringMap");
492
+ define_global_function("default_map", &defaultMap, Arg("strings") = std::map<std::string, std::string>{ {"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"} });
493
+
494
+ Module m = define_module("Testing");
495
+ Object result = m.module_eval("default_map");
496
+ std::map<std::string, std::string> actual = detail::From_Ruby<std::map<std::string, std::string>>().convert(result);
497
+
498
+ std::map<std::string, std::string> expected{ {"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"} };
499
+
500
+ ASSERT_EQUAL(expected.size(), actual.size());
501
+ ASSERT_EQUAL(expected["one"], actual["one"]);
502
+ ASSERT_EQUAL(expected["two"], actual["two"]);
503
+ ASSERT_EQUAL(expected["three"], actual["three"]);
504
+ }
505
+
506
+ namespace
507
+ {
508
+ std::map<std::string, int> ints;
509
+ std::map<std::string, float> floats;
510
+ std::map<std::string, std::string> strings;
511
+
512
+ void hashToMap(std::map<std::string, int> aInts, std::map<std::string, float> aFloats, std::map<std::string, std::string> aStrings)
513
+ {
514
+ ints = aInts;
515
+ floats = aFloats;
516
+ strings = aStrings;
517
+ }
518
+
519
+ void hashToMapRefs(std::map<std::string, int>& aInts, std::map<std::string, float>& aFloats, std::map<std::string, std::string>& aStrings)
520
+ {
521
+ ints = aInts;
522
+ floats = aFloats;
523
+ strings = aStrings;
524
+ }
525
+
526
+ void hashToMapPointers(std::map<std::string, int>* aInts, std::map<std::string, float>* aFloats, std::map<std::string, std::string>* aStrings)
527
+ {
528
+ ints = *aInts;
529
+ floats = *aFloats;
530
+ strings = *aStrings;
531
+ }
532
+ }
533
+
534
+ TESTCASE(HashToMap)
535
+ {
536
+ define_global_function("hash_to_map", &hashToMap);
537
+
538
+ Module m = define_module("Testing");
539
+
540
+ std::string code = R"(hash_to_map({"seven" => 7,
541
+ "nine" => 9,
542
+ "million" => 1_000_000},
543
+ {"forty nine" => 49.0,
544
+ "seventy eight" => 78.0,
545
+ "nine hundred ninety nine" => 999.0},
546
+ {"one" => "one",
547
+ "two" => "two",
548
+ "three" => "three"}))";
549
+
550
+ m.module_eval(code);
551
+
552
+ ASSERT_EQUAL(3u, ints.size());
553
+ ASSERT_EQUAL(7, ints["seven"]);
554
+ ASSERT_EQUAL(9, ints["nine"]);
555
+ ASSERT_EQUAL(1'000'000, ints["million"]);
556
+
557
+ ASSERT_EQUAL(3u, floats.size());
558
+ ASSERT_EQUAL(49.0, floats["forty nine"]);
559
+ ASSERT_EQUAL(78.0, floats["seventy eight"]);
560
+ ASSERT_EQUAL(999.0, floats["nine hundred ninety nine"]);
561
+
562
+ ASSERT_EQUAL(3u, strings.size());
563
+ ASSERT_EQUAL("one", strings["one"]);
564
+ ASSERT_EQUAL("two", strings["two"]);
565
+ ASSERT_EQUAL("three", strings["three"]);
566
+ }
567
+
568
+ TESTCASE(HashToMapRefs)
569
+ {
570
+ define_global_function("hash_to_map_refs", &hashToMapRefs);
571
+
572
+ Module m = define_module("Testing");
573
+
574
+ std::string code = R"(hash_to_map_refs({"eight" => 8,
575
+ "ten" => 10,
576
+ "million one" => 1_000_001},
577
+ {"fifty" => 50.0,
578
+ "seventy nine" => 79.0,
579
+ "one thousand" => 1_000.0},
580
+ {"eleven" => "eleven",
581
+ "twelve" => "twelve",
582
+ "thirteen" => "thirteen"}))";
583
+ m.module_eval(code);
584
+
585
+ ASSERT_EQUAL(3u, ints.size());
586
+ ASSERT_EQUAL(8, ints["eight"]);
587
+ ASSERT_EQUAL(10, ints["ten"]);
588
+ ASSERT_EQUAL(1'000'001, ints["million one"]);
589
+
590
+ ASSERT_EQUAL(3u, floats.size());
591
+ ASSERT_EQUAL(50.0, floats["fifty"]);
592
+ ASSERT_EQUAL(79.0, floats["seventy nine"]);
593
+ ASSERT_EQUAL(1'000.0, floats["one thousand"]);
594
+
595
+ ASSERT_EQUAL(3u, strings.size());
596
+ ASSERT_EQUAL("eleven", strings["eleven"]);
597
+ ASSERT_EQUAL("twelve", strings["twelve"]);
598
+ ASSERT_EQUAL("thirteen", strings["thirteen"]);
599
+ }
600
+
601
+ TESTCASE(HashToMapPointers)
602
+ {
603
+ define_global_function("hash_to_map_pointers", &hashToMapPointers);
604
+
605
+ Module m = define_module("Testing");
606
+
607
+ std::string code = R"(hash_to_map_pointers({"nine" => 9,
608
+ "eleven" => 11,
609
+ "million two" => 1_000_002},
610
+ {"fifty one" => 51.0,
611
+ "eighty" => 80.0,
612
+ "one thousand one" => 1_001.0},
613
+ {"fourteen" => "fourteen",
614
+ "fifteen" => "fifteen",
615
+ "sixteen" => "sixteen"}))";
616
+
617
+ m.module_eval(code);
618
+
619
+ ASSERT_EQUAL(3u, ints.size());
620
+ ASSERT_EQUAL(9, ints["nine"]);
621
+ ASSERT_EQUAL(11, ints["eleven"]);
622
+ ASSERT_EQUAL(1'000'002, ints["million two"]);
623
+
624
+ ASSERT_EQUAL(3u, floats.size());
625
+ ASSERT_EQUAL(51.0, floats["fifty one"]);
626
+ ASSERT_EQUAL(80.0, floats["eighty"]);
627
+ ASSERT_EQUAL(1'001.0, floats["one thousand one"]);
628
+
629
+ ASSERT_EQUAL(3u, strings.size());
630
+ ASSERT_EQUAL("fourteen", strings["fourteen"]);
631
+ ASSERT_EQUAL("fifteen", strings["fifteen"]);
632
+ ASSERT_EQUAL("sixteen", strings["sixteen"]);
633
+ }
634
+
635
+ TESTCASE(HashToMapWrongTypes)
636
+ {
637
+ define_global_function("hash_to_map", &hashToMap);
638
+
639
+ Module m = define_module("Testing");
640
+
641
+ std::string code = R"(hash_to_map({"seven" => 7,
642
+ "nine" => 9,
643
+ "million" => 1_000_000},
644
+ {"forty nine" => 49.0,
645
+ "seventy eight" => 78.0,
646
+ "nine hundred ninety nine" => 999.0},
647
+ {"one" => 50.0,
648
+ "two" => 79.0,
649
+ "three" => 1000.0}))";
650
+
651
+ ASSERT_EXCEPTION_CHECK(
652
+ Exception,
653
+ m.module_eval(code),
654
+ ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
655
+ );
656
+ }
657
+
658
+ TESTCASE(HashToMapMixedTypes)
659
+ {
660
+ define_global_function("hash_to_map", &hashToMap);
661
+
662
+ Module m = define_module("Testing");
663
+
664
+ std::string code = R"(hash_to_map({"seven" => 7,
665
+ "nine" => "nine",
666
+ "million" => true},
667
+ {"forty nine" => 49.0,
668
+ "seventy eight" => 78.0,
669
+ "nine hundred ninety nine" => 999.0},
670
+ {"one" => "one",
671
+ "two" => "two",
672
+ "three" => "three"}))";
673
+
674
+ ASSERT_EXCEPTION_CHECK(
675
+ Exception,
676
+ m.module_eval(code),
677
+ ASSERT_EQUAL("no implicit conversion of String into Integer", ex.what())
678
+ );
679
+ }
680
+
681
+ TESTCASE(MapToHash)
682
+ {
683
+ Module m = define_module("Testing");
684
+ Class c = makeMapClass();
685
+
686
+ std::string code = R"(my_class = MyClass.new
687
+ map = my_class.stringMap
688
+ hash = map.to_h)";
689
+
690
+ Hash hash = m.module_eval(code);
691
+ ASSERT_EQUAL(3u, hash.size());
692
+
693
+ ASSERT_EQUAL("1", detail::From_Ruby<std::string>().convert(hash["One"].value()));
694
+ ASSERT_EQUAL("2", detail::From_Ruby<std::string>().convert(hash["Two"].value()));
695
+ ASSERT_EQUAL("3", detail::From_Ruby<std::string>().convert(hash["Three"].value()));
696
+ }