rice 4.5.0 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/CMakeLists.txt +31 -0
  4. data/CMakePresets.json +75 -0
  5. data/COPYING +3 -2
  6. data/FindRuby.cmake +437 -0
  7. data/Rakefile +5 -4
  8. data/include/rice/rice.hpp +5436 -3201
  9. data/include/rice/stl.hpp +2355 -1269
  10. data/lib/make_rice_headers.rb +79 -0
  11. data/lib/mkmf-rice.rb +4 -0
  12. data/lib/rice/version.rb +3 -0
  13. data/lib/rice.rb +1 -0
  14. data/lib/rubygems/builder.rb +11 -0
  15. data/lib/rubygems/cmake_builder.rb +113 -0
  16. data/lib/rubygems_plugin.rb +9 -0
  17. data/rice/Arg.hpp +7 -1
  18. data/rice/Arg.ipp +11 -2
  19. data/rice/Buffer.hpp +123 -0
  20. data/rice/Buffer.ipp +599 -0
  21. data/rice/Constructor.ipp +3 -3
  22. data/rice/Data_Object.hpp +2 -3
  23. data/rice/Data_Object.ipp +188 -188
  24. data/rice/Data_Type.hpp +4 -5
  25. data/rice/Data_Type.ipp +42 -26
  26. data/rice/Enum.hpp +0 -1
  27. data/rice/Enum.ipp +26 -23
  28. data/rice/Init.hpp +8 -0
  29. data/rice/Init.ipp +8 -0
  30. data/rice/MemoryView.ipp +1 -41
  31. data/rice/Return.hpp +1 -1
  32. data/rice/Return.ipp +6 -0
  33. data/rice/cpp_api/Array.hpp +209 -0
  34. data/rice/cpp_api/Array.ipp +304 -0
  35. data/rice/cpp_api/Builtin_Object.hpp +31 -0
  36. data/rice/cpp_api/Builtin_Object.ipp +37 -0
  37. data/rice/cpp_api/Class.hpp +70 -0
  38. data/rice/cpp_api/Class.ipp +97 -0
  39. data/rice/cpp_api/Encoding.hpp +32 -0
  40. data/rice/cpp_api/Encoding.ipp +59 -0
  41. data/rice/cpp_api/Hash.hpp +194 -0
  42. data/rice/cpp_api/Hash.ipp +257 -0
  43. data/rice/cpp_api/Identifier.hpp +46 -0
  44. data/rice/cpp_api/Identifier.ipp +31 -0
  45. data/rice/cpp_api/Module.hpp +72 -0
  46. data/rice/cpp_api/Module.ipp +101 -0
  47. data/rice/cpp_api/Object.hpp +272 -0
  48. data/rice/cpp_api/Object.ipp +235 -0
  49. data/rice/cpp_api/String.hpp +74 -0
  50. data/rice/cpp_api/String.ipp +120 -0
  51. data/rice/cpp_api/Struct.hpp +113 -0
  52. data/rice/cpp_api/Struct.ipp +92 -0
  53. data/rice/cpp_api/Symbol.hpp +46 -0
  54. data/rice/cpp_api/Symbol.ipp +93 -0
  55. data/rice/cpp_api/shared_methods.hpp +134 -0
  56. data/rice/detail/MethodInfo.hpp +1 -9
  57. data/rice/detail/MethodInfo.ipp +5 -72
  58. data/rice/detail/Native.hpp +3 -2
  59. data/rice/detail/Native.ipp +32 -4
  60. data/rice/detail/NativeAttributeGet.hpp +3 -2
  61. data/rice/detail/NativeAttributeGet.ipp +8 -2
  62. data/rice/detail/NativeAttributeSet.hpp +3 -2
  63. data/rice/detail/NativeAttributeSet.ipp +8 -2
  64. data/rice/detail/NativeCallbackFFI.ipp +1 -1
  65. data/rice/detail/NativeFunction.hpp +17 -6
  66. data/rice/detail/NativeFunction.ipp +168 -64
  67. data/rice/detail/NativeIterator.hpp +3 -2
  68. data/rice/detail/NativeIterator.ipp +8 -2
  69. data/rice/detail/RubyType.hpp +2 -5
  70. data/rice/detail/RubyType.ipp +50 -5
  71. data/rice/detail/Type.hpp +3 -1
  72. data/rice/detail/Type.ipp +61 -31
  73. data/rice/detail/Wrapper.hpp +68 -33
  74. data/rice/detail/Wrapper.ipp +103 -113
  75. data/rice/detail/from_ruby.hpp +5 -4
  76. data/rice/detail/from_ruby.ipp +737 -365
  77. data/rice/detail/to_ruby.ipp +1092 -186
  78. data/rice/global_function.ipp +1 -1
  79. data/rice/libc/file.hpp +11 -0
  80. data/rice/libc/file.ipp +32 -0
  81. data/rice/rice.hpp +23 -16
  82. data/rice/stl/complex.hpp +6 -0
  83. data/rice/stl/complex.ipp +93 -0
  84. data/rice/stl/exception.hpp +11 -0
  85. data/rice/stl/exception.ipp +29 -0
  86. data/rice/stl/exception_ptr.hpp +6 -0
  87. data/rice/stl/exception_ptr.ipp +27 -0
  88. data/rice/stl/map.hpp +12 -0
  89. data/rice/stl/map.ipp +469 -0
  90. data/rice/stl/monostate.hpp +6 -0
  91. data/rice/stl/monostate.ipp +80 -0
  92. data/rice/stl/multimap.hpp +14 -0
  93. data/rice/stl/multimap.ipp +448 -0
  94. data/rice/stl/optional.hpp +6 -0
  95. data/rice/stl/optional.ipp +118 -0
  96. data/rice/stl/pair.hpp +13 -0
  97. data/rice/stl/pair.ipp +155 -0
  98. data/rice/stl/reference_wrapper.hpp +6 -0
  99. data/rice/stl/reference_wrapper.ipp +41 -0
  100. data/rice/stl/set.hpp +12 -0
  101. data/rice/stl/set.ipp +495 -0
  102. data/rice/stl/shared_ptr.hpp +28 -0
  103. data/rice/stl/shared_ptr.ipp +224 -0
  104. data/rice/stl/string.hpp +6 -0
  105. data/rice/stl/string.ipp +158 -0
  106. data/rice/stl/string_view.hpp +6 -0
  107. data/rice/stl/string_view.ipp +65 -0
  108. data/rice/stl/tuple.hpp +6 -0
  109. data/rice/stl/tuple.ipp +128 -0
  110. data/rice/stl/type_index.hpp +6 -0
  111. data/rice/stl/type_index.ipp +30 -0
  112. data/rice/stl/type_info.hpp +6 -0
  113. data/rice/stl/type_info.ipp +29 -0
  114. data/rice/stl/unique_ptr.hpp +22 -0
  115. data/rice/stl/unique_ptr.ipp +139 -0
  116. data/rice/stl/unordered_map.hpp +12 -0
  117. data/rice/stl/unordered_map.ipp +469 -0
  118. data/rice/stl/variant.hpp +6 -0
  119. data/rice/stl/variant.ipp +242 -0
  120. data/rice/stl/vector.hpp +12 -0
  121. data/rice/stl/vector.ipp +590 -0
  122. data/rice/stl.hpp +7 -3
  123. data/rice/traits/attribute_traits.hpp +26 -0
  124. data/rice/traits/function_traits.hpp +95 -0
  125. data/rice/traits/method_traits.hpp +47 -0
  126. data/rice/traits/rice_traits.hpp +160 -0
  127. data/rice.gemspec +85 -0
  128. data/test/embed_ruby.cpp +3 -0
  129. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  130. data/test/test_Array.cpp +6 -3
  131. data/test/test_Attribute.cpp +34 -1
  132. data/test/test_Buffer.cpp +285 -0
  133. data/test/test_Callback.cpp +2 -3
  134. data/test/test_Data_Object.cpp +88 -34
  135. data/test/test_Data_Type.cpp +106 -65
  136. data/test/test_Director.cpp +7 -3
  137. data/test/test_Enum.cpp +5 -2
  138. data/test/test_File.cpp +1 -1
  139. data/test/test_From_Ruby.cpp +181 -114
  140. data/test/test_Iterator.cpp +1 -1
  141. data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
  142. data/test/test_Keep_Alive.cpp +7 -18
  143. data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
  144. data/test/test_Module.cpp +13 -6
  145. data/test/test_Native_Registry.cpp +0 -1
  146. data/test/test_Overloads.cpp +180 -5
  147. data/test/test_Ownership.cpp +100 -57
  148. data/test/test_Proc.cpp +0 -1
  149. data/test/test_Self.cpp +4 -4
  150. data/test/test_Stl_Map.cpp +37 -39
  151. data/test/test_Stl_Multimap.cpp +693 -0
  152. data/test/test_Stl_Pair.cpp +8 -8
  153. data/test/test_Stl_Reference_Wrapper.cpp +4 -2
  154. data/test/test_Stl_Set.cpp +790 -0
  155. data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
  156. data/test/test_Stl_Tuple.cpp +116 -0
  157. data/test/test_Stl_Type.cpp +1 -1
  158. data/test/test_Stl_UniquePtr.cpp +202 -0
  159. data/test/test_Stl_Unordered_Map.cpp +28 -34
  160. data/test/test_Stl_Variant.cpp +217 -89
  161. data/test/test_Stl_Vector.cpp +209 -83
  162. data/test/test_To_Ruby.cpp +373 -1
  163. data/test/test_Type.cpp +85 -14
  164. data/test/test_global_functions.cpp +17 -4
  165. metadata +94 -10
  166. data/rice/detail/TupleIterator.hpp +0 -14
@@ -0,0 +1,693 @@
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
+ #include <ruby/version.h>
9
+
10
+ using namespace Rice;
11
+
12
+ TESTSUITE(Multimap);
13
+
14
+ SETUP(Multimap)
15
+ {
16
+ embed_ruby();
17
+ }
18
+
19
+ TEARDOWN(Multimap)
20
+ {
21
+ rb_gc_start();
22
+ }
23
+
24
+ namespace
25
+ {
26
+ class MyClass
27
+ {
28
+ public:
29
+ std::multimap<std::string, std::string> stringMultimap()
30
+ {
31
+ std::multimap<std::string, std::string> result{ {"One", "1"}, {"Two", "2"}, {"Three", "3"} };
32
+ return result;
33
+ }
34
+ };
35
+ }
36
+
37
+ Class makeMultimapClass()
38
+ {
39
+ Class c = define_class<MyClass>("MyClass").
40
+ define_constructor(Constructor<MyClass>()).
41
+ define_method("stringMultimap", &MyClass::stringMultimap);
42
+
43
+ return c;
44
+ }
45
+
46
+ TESTCASE(StringMultimap)
47
+ {
48
+ Module m = define_module("Testing");
49
+
50
+ Class c = define_multimap<std::string, std::string>("StringMultimap");
51
+
52
+ Object multimap = m.module_eval("$multimap = Std::StringMultimap.new");
53
+ Object result = multimap.call("size");
54
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
55
+
56
+ m.module_eval("$multimap.insert('a_key', 'a_value')");
57
+ result = multimap.call("size");
58
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
59
+
60
+ m.module_eval("$multimap.clear");
61
+ result = multimap.call("size");
62
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
63
+ }
64
+
65
+ TESTCASE(WrongType)
66
+ {
67
+ Module m = define_module("Testing");
68
+
69
+ Class c = define_multimap<std::string, std::string>("StringMultimap");
70
+ Object multimap = m.module_eval("$multimap = Std::StringMultimap.new");
71
+
72
+ ASSERT_EXCEPTION_CHECK(
73
+ Exception,
74
+ m.module_eval("$multimap.insert(1, 'abc')"),
75
+ ASSERT_EQUAL("wrong argument type Integer (expected String)", ex.what()));
76
+
77
+ ASSERT_EXCEPTION_CHECK(
78
+ Exception,
79
+ m.module_eval("$multimap.insert('abc', true)"),
80
+ ASSERT_EQUAL("wrong argument type true (expected String)", ex.what()));
81
+ }
82
+
83
+ TESTCASE(Empty)
84
+ {
85
+ Module m = define_module("Testing");
86
+
87
+ Class c = define_multimap<std::string, std::int32_t>("IntMultimap");
88
+ Object multimap = c.call("new");
89
+
90
+ Object result = multimap.call("size");
91
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
92
+
93
+ result = multimap.call("empty?");
94
+ ASSERT_EQUAL(Qtrue, result.value());
95
+ }
96
+
97
+ TESTCASE(Include)
98
+ {
99
+ Module m = define_module("Testing");
100
+
101
+ Class c = define_multimap<std::string, std::int32_t>("IntMultimap");
102
+ Object multimap = c.call("new");
103
+ multimap.call("insert", "one", 1);
104
+ multimap.call("insert", "two", 2);
105
+
106
+ Object result = multimap.call("include?", "two");
107
+ ASSERT_EQUAL(Qtrue, result.value());
108
+
109
+ result = multimap.call("include?", "three");
110
+ ASSERT_EQUAL(Qfalse, result.value());
111
+
112
+ Array array = multimap.call("[]", "three");
113
+ ASSERT_EQUAL(0, array.size());
114
+ }
115
+
116
+ TESTCASE(Value)
117
+ {
118
+ Module m = define_module("Testing");
119
+
120
+ Class c = define_multimap<std::string, std::int32_t>("IntMultimap");
121
+ Object multimap = c.call("new");
122
+ multimap.call("insert", "one", 1);
123
+ multimap.call("insert", "two", 2);
124
+
125
+ Object result = multimap.call("value?", 2);
126
+ ASSERT_EQUAL(Qtrue, result.value());
127
+
128
+ result = multimap.call("value?", 4);
129
+ ASSERT_EQUAL(Qfalse, result.value());
130
+ }
131
+
132
+ TESTCASE(ToString)
133
+ {
134
+ Module m = define_module("Testing");
135
+
136
+ Class c = define_multimap<std::string, std::int32_t>("IntMultimap");
137
+ Object multimap = c.call("new");
138
+ multimap.call("insert", "one", 1);
139
+ multimap.call("insert", "two", 2);
140
+
141
+ Object result = multimap.call("to_s");
142
+ ASSERT_EQUAL("<Multimap≺string‚ int≻:{one => 1, two => 2}>", detail::From_Ruby<std::string>().convert(result));
143
+
144
+ multimap.call("clear");
145
+
146
+ result = multimap.call("to_s");
147
+ ASSERT_EQUAL("<Multimap≺string‚ int≻:{}>", detail::From_Ruby<std::string>().convert(result));
148
+ }
149
+
150
+ TESTCASE(Update)
151
+ {
152
+ Module m = define_module("Testing");
153
+
154
+ Class c = define_multimap<std::string, std::string>("StringMultimap");
155
+ Object multimap = c.call("new");
156
+ multimap.call("insert", "one", "original 1");
157
+ multimap.call("insert", "two", "original 2");
158
+
159
+ Object result = multimap.call("size");
160
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
161
+
162
+ result = multimap.call("insert", "two", "new 2");
163
+ ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
164
+
165
+ result = multimap.call("size");
166
+ ASSERT_EQUAL(3, detail::From_Ruby<int32_t>().convert(result));
167
+
168
+ Array array = multimap.call("[]", "two");
169
+ ASSERT_EQUAL(2, array.size());
170
+ ASSERT_EQUAL("original 2", String(array[0]).c_str());
171
+ ASSERT_EQUAL("new 2", String(array[1]).c_str());
172
+ }
173
+
174
+ TESTCASE(Modify)
175
+ {
176
+ Module m = define_module("Testing");
177
+
178
+ Class c = define_multimap<std::string, int64_t>("Int64Multimap");
179
+ Object multimap = c.call("new");
180
+
181
+ Object result = multimap.call("insert", "one", 3232323232);
182
+
183
+ result = multimap.call("size");
184
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
185
+
186
+ result = multimap.call("delete", "one");
187
+ ASSERT_EQUAL(3232323232, detail::From_Ruby<int64_t>().convert(result));
188
+
189
+ result = multimap.call("size");
190
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
191
+ }
192
+
193
+ TESTCASE(keysAndValues)
194
+ {
195
+ Module m = define_module("Testing");
196
+
197
+ Class c = define_multimap<std::string, int32_t>("Int32Multimap");
198
+ Object multimap = c.call("new");
199
+
200
+ multimap.call("insert", "one", 1);
201
+ multimap.call("insert", "two", 2);
202
+ multimap.call("insert", "three", 3);
203
+
204
+ // Keys returns a std::vector
205
+ Data_Object<std::vector<std::string>> keys = multimap.call("keys");
206
+ std::vector<std::string> expected_keys{ {"one", "three", "two"} };
207
+ ASSERT_EQUAL(3u, keys->size());
208
+ ASSERT_EQUAL(expected_keys[0], keys->operator[](0));
209
+ ASSERT_EQUAL(expected_keys[1], keys->operator[](1));
210
+ ASSERT_EQUAL(expected_keys[2], keys->operator[](2));
211
+
212
+ // Keys returns a std::vector
213
+ Data_Object<std::vector<std::int32_t>> values = multimap.call("values");
214
+ std::vector<std::int32_t> expected_values{ {1, 3, 2} };
215
+ ASSERT_EQUAL(3u, values->size());
216
+ ASSERT_EQUAL(expected_values[0], values->operator[](0));
217
+ ASSERT_EQUAL(expected_values[1], values->operator[](1));
218
+ ASSERT_EQUAL(expected_values[2], values->operator[](2));
219
+ }
220
+
221
+ TESTCASE(Copy)
222
+ {
223
+ Module m = define_module("Testing");
224
+
225
+ Class c = define_multimap<std::string, double>("DoubleMultimap");
226
+ Object object = c.call("new");
227
+
228
+ object.call("insert", "one", 11.1);
229
+ object.call("insert", "two", 22.2);
230
+ std::multimap<std::string, double>& multimap = detail::From_Ruby<std::multimap<std::string, double>&>().convert(object);
231
+
232
+ Object result = object.call("copy");
233
+ std::multimap<std::string, double>& multimapCopy = detail::From_Ruby<std::multimap<std::string, double>&>().convert(result);
234
+
235
+ ASSERT_EQUAL(multimap, multimapCopy);
236
+ }
237
+
238
+ TESTCASE(Iterate)
239
+ {
240
+ Module m = define_module("Testing");
241
+ Class c = define_multimap<std::string, int>("IntMultimap");
242
+
243
+ std::string code = R"(multimap = Std::IntMultimap.new
244
+ multimap.insert("five", 5)
245
+ multimap.insert("six", 6)
246
+ multimap.insert("seven", 7)
247
+
248
+ result = Hash.new
249
+ multimap.map do |pair|
250
+ result[pair.first] = 2 * pair.second
251
+ end
252
+ result)";
253
+
254
+ Hash result = m.module_eval(code);
255
+ ASSERT_EQUAL(3u, result.size());
256
+
257
+ std::string result_string = result.to_s().str();
258
+ #if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4
259
+ ASSERT_EQUAL("{\"five\" => 10, \"seven\" => 14, \"six\" => 12}", result_string);
260
+ #else
261
+ ASSERT_EQUAL("{\"five\"=>10, \"seven\"=>14, \"six\"=>12}", result_string);
262
+ #endif
263
+ }
264
+
265
+ TESTCASE(ToEnum)
266
+ {
267
+ Module m = define_module("Testing");
268
+ Class c = define_multimap<std::string, int>("IntMultimap");
269
+
270
+ std::string code = R"(multimap = Std::IntMultimap.new
271
+ multimap.insert("five", 5)
272
+ multimap.insert("six", 6)
273
+ multimap.insert("seven", 7)
274
+
275
+ result = Hash.new
276
+ multimap.each do |pair|
277
+ result[pair.first] = 2 * pair.second
278
+ end
279
+ result)";
280
+
281
+ Hash result = m.module_eval(code);
282
+ ASSERT_EQUAL(3u, result.size());
283
+
284
+ std::string result_string = result.to_s().str();
285
+
286
+ #if RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4
287
+ ASSERT_EQUAL("{\"five\" => 10, \"seven\" => 14, \"six\" => 12}", result_string);
288
+ #else
289
+ ASSERT_EQUAL("{\"five\"=>10, \"seven\"=>14, \"six\"=>12}", result_string);
290
+ #endif
291
+ }
292
+
293
+ TESTCASE(ToEnumSize)
294
+ {
295
+ Module m = define_module("TestingModule");
296
+ Class c = define_multimap<std::string, int>("IntMultimap");
297
+
298
+ std::string code = R"(multimap = Std::IntMultimap.new
299
+ multimap.insert("five", 5)
300
+ multimap.insert("six", 6)
301
+ multimap.insert("seven", 7)
302
+ multimap.insert("eight", 7)
303
+ multimap.insert("eight", 8)
304
+ multimap)";
305
+
306
+ Object multimap = m.module_eval(code);
307
+ Object enumerable = multimap.call("each");
308
+ Object result = enumerable.call("size");
309
+
310
+ ASSERT_EQUAL(5, detail::From_Ruby<int>().convert(result));
311
+ }
312
+
313
+ namespace
314
+ {
315
+ class NotComparable
316
+ {
317
+ public:
318
+ NotComparable(uint32_t value) : value_(value)
319
+ {
320
+ };
321
+
322
+ NotComparable() = default;
323
+
324
+ uint32_t value_;
325
+ };
326
+ }
327
+
328
+ TESTCASE(NotComparable)
329
+ {
330
+ define_class<NotComparable>("NotComparable").
331
+ define_constructor(Constructor<NotComparable, uint32_t>());
332
+
333
+ Class c = define_multimap<std::string, NotComparable>("NotComparableMultimap");
334
+
335
+ Object multimap = c.call("new");
336
+ multimap.call("insert", "one", NotComparable(1));
337
+ multimap.call("insert", "two", NotComparable(2));
338
+ multimap.call("insert", "three", NotComparable(3));
339
+
340
+ Object result = multimap.call("include?", "two");
341
+ ASSERT_EQUAL(Qtrue, result.value());
342
+
343
+ result = multimap.call("value?", NotComparable(3));
344
+ ASSERT_EQUAL(Qfalse, result.value());
345
+ }
346
+
347
+ TESTCASE(NotPrintable)
348
+ {
349
+ define_class<NotComparable>("NotComparable").
350
+ define_constructor(Constructor<NotComparable, uint32_t>());
351
+
352
+ Class c = define_multimap<std::string, NotComparable>("NotComparableMultimap");
353
+
354
+ Object multimap = c.call("new");
355
+ multimap.call("insert", "one", NotComparable(1));
356
+ multimap.call("insert", "two", NotComparable(2));
357
+ multimap.call("insert", "three", NotComparable(3));
358
+
359
+ Object result = multimap.call("to_s");
360
+ ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
361
+ }
362
+
363
+ namespace
364
+ {
365
+ class Comparable
366
+ {
367
+ public:
368
+ Comparable() = default;
369
+ Comparable(uint32_t value) : value_(value)
370
+ {
371
+ };
372
+
373
+ bool operator==(const Comparable& other) const
374
+ {
375
+ return this->value_ == other.value_;
376
+ }
377
+
378
+ uint32_t value_;
379
+ };
380
+
381
+ inline std::ostream& operator<<(std::ostream& stream, Comparable const& comparable)
382
+ {
383
+ stream << "Comparable(" << std::to_string(comparable.value_) << ")";
384
+ return stream;
385
+ }
386
+ }
387
+
388
+ TESTCASE(Comparable)
389
+ {
390
+ define_class<Comparable>("IsComparable").
391
+ define_constructor(Constructor<Comparable, uint32_t>());
392
+
393
+ Class c = define_multimap<std::string, Comparable>("ComparableMultimap");
394
+
395
+ Object multimap = c.call("new");
396
+
397
+ multimap.call("insert", "one", Comparable(1));
398
+ multimap.call("insert", "two", Comparable(2));
399
+ multimap.call("insert", "three", Comparable(3));
400
+
401
+ Object result = multimap.call("value?", Comparable(2));
402
+ ASSERT_EQUAL(Qtrue, result.value());
403
+ }
404
+
405
+ TESTCASE(Printable)
406
+ {
407
+ define_class<Comparable>("IsComparable").
408
+ define_constructor(Constructor<Comparable, uint32_t>());
409
+
410
+ Class c = define_multimap<std::string, Comparable>("ComparableMultimap");
411
+
412
+ Object multimap = c.call("new");
413
+ multimap.call("insert", "one", Comparable(1));
414
+ multimap.call("insert", "two", Comparable(2));
415
+ multimap.call("insert", "three", Comparable(3));
416
+
417
+ Object result = multimap.call("to_s");
418
+ ASSERT_EQUAL("<Multimap≺string‚ AnonymousNamespace꞉꞉Comparable≻:{one => Comparable(1), three => Comparable(3), two => Comparable(2)}>",
419
+ detail::From_Ruby<std::string>().convert(result));
420
+ }
421
+
422
+ namespace
423
+ {
424
+ std::multimap<std::string, std::complex<double>> returnComplexMultimap()
425
+ {
426
+ std::complex<double> complex1(1, 1);
427
+ std::complex<double> complex2(2, 2);
428
+ std::complex<double> complex3(3, 3);
429
+
430
+ std::multimap<std::string, std::complex<double>> result;
431
+ using Value_T = std::multimap<std::string, std::complex<double>>::value_type;
432
+ result.insert(Value_T{ "one", complex1 });
433
+ result.insert(Value_T{ "two", complex2 });
434
+ result.insert(Value_T{ "three", complex3 });
435
+ return result;
436
+ }
437
+
438
+ std::multimap<std::string, std::complex<double>> passComplexMultimap(std::multimap<std::string, std::complex<double>>& complexes)
439
+ {
440
+ return complexes;
441
+ }
442
+ }
443
+
444
+ TESTCASE(AutoRegisterReturn)
445
+ {
446
+ define_global_function("return_complex_multimap", &returnComplexMultimap);
447
+
448
+ Module m = define_module("Testing");
449
+ Object multimap = m.module_eval("return_complex_multimap");
450
+ ASSERT_EQUAL("Std::Multimap≺string‚ complex≺double≻≻",
451
+ multimap.class_name().str());
452
+
453
+ std::string code = R"(multimap = return_complex_multimap
454
+ complex = multimap['three']
455
+ complex == [Complex(3, 3)])";
456
+
457
+ Object result = m.module_eval(code);
458
+ ASSERT_EQUAL(Qtrue, result.value());
459
+
460
+ // Now register the multimap again
461
+ define_multimap<std::string, std::complex<double>>("ComplexMultimap");
462
+ code = R"(multimap = Std::ComplexMultimap.new)";
463
+ result = m.module_eval(code);
464
+ ASSERT(result.is_instance_of(multimap.class_of()));
465
+
466
+ // And again in the module
467
+ define_multimap<std::string, std::complex<double>>("ComplexMultimap2");
468
+ code = R"(multimap = Std::ComplexMultimap2.new)";
469
+ result = m.module_eval(code);
470
+ ASSERT(result.is_instance_of(multimap.class_of()));
471
+ }
472
+
473
+ TESTCASE(AutoRegisterParameter)
474
+ {
475
+ define_global_function("pass_complex_multimap", &passComplexMultimap);
476
+
477
+ std::string code = R"(multimap = Std::Multimap≺string‚ complex≺double≻≻.new
478
+ multimap.insert("four", Complex(4.0, 4.0))
479
+ multimap.insert("five", Complex(5.0, 5.0))
480
+ pass_complex_multimap(multimap))";
481
+
482
+ Module m = define_module("Testing");
483
+ Object multimap = m.module_eval(code);
484
+
485
+ Object result = multimap.call("size");
486
+ ASSERT_EQUAL("Std::Multimap≺string‚ complex≺double≻≻",
487
+ multimap.class_name().str());
488
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
489
+
490
+ std::multimap<std::string, std::complex<double>> expected{ {"four", std::complex<double>(4, 4)},
491
+ {"five", std::complex<double>(5, 5)} };
492
+
493
+ std::multimap<std::string, std::complex<double>> complexes = detail::From_Ruby<std::multimap<std::string, std::complex<double>>>().convert(multimap);
494
+
495
+ ASSERT_EQUAL(expected, complexes);
496
+ }
497
+
498
+ namespace
499
+ {
500
+ std::multimap<std::string, std::string> defaultMultimap(std::multimap<std::string, std::string> strings = {{"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"}})
501
+ {
502
+ return strings;
503
+ }
504
+ }
505
+
506
+ TESTCASE(DefaultValue)
507
+ {
508
+ define_multimap<std::string, std::string>("StringMultimap");
509
+ define_global_function("default_multimap", &defaultMultimap, Arg("strings") = std::multimap<std::string, std::string>{ {"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"} });
510
+
511
+ Module m = define_module("Testing");
512
+ Object result = m.module_eval("default_multimap");
513
+ std::multimap<std::string, std::string> actual = detail::From_Ruby<std::multimap<std::string, std::string>>().convert(result);
514
+
515
+ std::multimap<std::string, std::string> expected{ {"one", "value 1"}, {"two", "value 2"}, {"three", "value 3"} };
516
+
517
+ ASSERT_EQUAL(expected, actual);
518
+ }
519
+
520
+ namespace
521
+ {
522
+ std::multimap<std::string, int> ints;
523
+ std::multimap<std::string, float> floats;
524
+ std::multimap<std::string, std::string> strings;
525
+
526
+ void hashToMultimap(std::multimap<std::string, int> aInts, std::multimap<std::string, float> aFloats, std::multimap<std::string, std::string> aStrings)
527
+ {
528
+ ints = aInts;
529
+ floats = aFloats;
530
+ strings = aStrings;
531
+ }
532
+
533
+ void hashToMultimapRefs(std::multimap<std::string, int>& aInts, std::multimap<std::string, float>& aFloats, std::multimap<std::string, std::string>& aStrings)
534
+ {
535
+ ints = aInts;
536
+ floats = aFloats;
537
+ strings = aStrings;
538
+ }
539
+
540
+ void hashToMultimapPointers(std::multimap<std::string, int>* aInts, std::multimap<std::string, float>* aFloats, std::multimap<std::string, std::string>* aStrings)
541
+ {
542
+ ints = *aInts;
543
+ floats = *aFloats;
544
+ strings = *aStrings;
545
+ }
546
+ }
547
+
548
+ TESTCASE(HashToMultimap)
549
+ {
550
+ define_global_function("hash_to_multimap", &hashToMultimap);
551
+
552
+ Module m = define_module("Testing");
553
+
554
+ std::string code = R"(hash_to_multimap({"seven" => 7,
555
+ "nine" => 9,
556
+ "million" => 1_000_000},
557
+ {"forty nine" => 49.0,
558
+ "seventy eight" => 78.0,
559
+ "nine hundred ninety nine" => 999.0},
560
+ {"one" => "one",
561
+ "two" => "two",
562
+ "three" => "three"}))";
563
+
564
+ m.module_eval(code);
565
+
566
+ std::multimap<std::string, int> expectedInts{{"seven", 7},
567
+ {"nine", 9},
568
+ {"million", 1000000 } };
569
+ ASSERT_EQUAL(expectedInts, ints);
570
+
571
+ std::multimap<std::string, float> expectedFloats{ {"forty nine", 49.0f},
572
+ {"seventy eight", 78.0f},
573
+ {"nine hundred ninety nine", 999.0f} };
574
+ ASSERT_EQUAL(expectedFloats, floats);
575
+
576
+ std::multimap<std::string, std::string> expectedStrings{ {"one", "one"},
577
+ {"two", "two"},
578
+ {"three", "three"} };
579
+ ASSERT_EQUAL(expectedStrings, strings);
580
+ }
581
+
582
+ TESTCASE(HashToMultimapRefs)
583
+ {
584
+ define_global_function("hash_to_multimap_refs", &hashToMultimapRefs);
585
+
586
+ Module m = define_module("Testing");
587
+
588
+ std::string code = R"(hash_to_multimap_refs({"eight" => 8,
589
+ "ten" => 10,
590
+ "million one" => 1_000_001},
591
+ {"fifty" => 50.0,
592
+ "seventy nine" => 79.0,
593
+ "one thousand" => 1_000.0},
594
+ {"eleven" => "eleven",
595
+ "twelve" => "twelve",
596
+ "thirteen" => "thirteen"}))";
597
+ m.module_eval(code);
598
+
599
+ std::multimap<std::string, int> expectedInts{ {"eight", 8},
600
+ {"ten", 10},
601
+ {"million one", 1000001 } };
602
+ ASSERT_EQUAL(expectedInts, ints);
603
+
604
+ std::multimap<std::string, float> expectedFloats{ {"fifty", 50.0f},
605
+ {"seventy nine", 79.0f},
606
+ {"one thousand", 1000.0f} };
607
+ ASSERT_EQUAL(expectedFloats, floats);
608
+
609
+ std::multimap<std::string, std::string> expectedStrings{ {"eleven", "eleven"},
610
+ {"twelve", "twelve"},
611
+ {"thirteen", "thirteen"} };
612
+ ASSERT_EQUAL(expectedStrings, strings);
613
+ }
614
+
615
+ TESTCASE(HashToMultimapPointers)
616
+ {
617
+ define_global_function("hash_to_multimap_pointers", &hashToMultimapPointers);
618
+
619
+ Module m = define_module("Testing");
620
+
621
+ std::string code = R"(hash_to_multimap_pointers({"nine" => 9,
622
+ "eleven" => 11,
623
+ "million two" => 1_000_002},
624
+ {"fifty one" => 51.0,
625
+ "eighty" => 80.0,
626
+ "one thousand one" => 1_001.0},
627
+ {"fourteen" => "fourteen",
628
+ "fifteen" => "fifteen",
629
+ "sixteen" => "sixteen"}))";
630
+
631
+ m.module_eval(code);
632
+
633
+ std::multimap<std::string, int> expectedInts{ {"nine", 9},
634
+ {"eleven", 11},
635
+ {"million two", 1000002 } };
636
+ ASSERT_EQUAL(expectedInts, ints);
637
+
638
+ std::multimap<std::string, float> expectedFloats{ {"fifty one", 51.0f},
639
+ {"eighty", 80.0f},
640
+ {"one thousand one", 1001.0f} };
641
+ ASSERT_EQUAL(expectedFloats, floats);
642
+
643
+ std::multimap<std::string, std::string> expectedStrings{ {"fourteen", "fourteen"},
644
+ {"fifteen", "fifteen"},
645
+ {"sixteen", "sixteen"} };
646
+ ASSERT_EQUAL(expectedStrings, strings);
647
+ }
648
+
649
+ TESTCASE(HashToMultimapWrongTypes)
650
+ {
651
+ define_global_function("hash_to_multimap", &hashToMultimap);
652
+
653
+ Module m = define_module("Testing");
654
+
655
+ std::string code = R"(hash_to_multimap({"seven" => 7,
656
+ "nine" => 9,
657
+ "million" => 1_000_000},
658
+ {"forty nine" => 49.0,
659
+ "seventy eight" => 78.0,
660
+ "nine hundred ninety nine" => 999.0},
661
+ {"one" => 50.0,
662
+ "two" => 79.0,
663
+ "three" => 1000.0}))";
664
+
665
+ ASSERT_EXCEPTION_CHECK(
666
+ Exception,
667
+ m.module_eval(code),
668
+ ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
669
+ );
670
+ }
671
+
672
+ TESTCASE(HashToMultimapMixedTypes)
673
+ {
674
+ define_global_function("hash_to_multimap", &hashToMultimap);
675
+
676
+ Module m = define_module("Testing");
677
+
678
+ std::string code = R"(hash_to_multimap({"seven" => 7,
679
+ "nine" => "nine",
680
+ "million" => true},
681
+ {"forty nine" => 49.0,
682
+ "seventy eight" => 78.0,
683
+ "nine hundred ninety nine" => 999.0},
684
+ {"one" => "one",
685
+ "two" => "two",
686
+ "three" => "three"}))";
687
+
688
+ ASSERT_EXCEPTION_CHECK(
689
+ Exception,
690
+ m.module_eval(code),
691
+ ASSERT_EQUAL("no implicit conversion of String into Integer", ex.what())
692
+ );
693
+ }