test/test_Stl_Vector.cpp in rice-4.3.0 vs test/test_Stl_Vector.cpp in rice-4.3.1
- old
+ new
@@ -1,871 +1,871 @@
-#include <complex>
-
-#include "unittest.hpp"
-#include "embed_ruby.hpp"
-#include <rice/rice.hpp>
-#include <rice/stl.hpp>
-
-using namespace Rice;
-
-TESTSUITE(Vector);
-
-SETUP(Vector)
-{
- embed_ruby();
-}
-
-namespace
-{
-
- class MyClass
- {
- public:
- std::vector<std::string> stringVector()
- {
- std::vector<std::string> result{ "One", "Two", "Three" };
- return result;
- }
- };
-}
-
-Class makeVectorClass()
-{
- Class c = define_class<MyClass>("MyClass").
- define_constructor(Constructor<MyClass>()).
- define_method("stringVector", &MyClass::stringVector);
-
- return c;
-}
-
-TESTCASE(StringVector)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::string>>("StringVector");
-
- Object vec = m.module_eval("$vector = StringVector.new");
- Object result = vec.call("size");
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-
- m.module_eval("$vector << 'one' << 'two' << 'two' << 'three'");
- result = vec.call("size");
- ASSERT_EQUAL(4, detail::From_Ruby<int32_t>().convert(result));
-
- m.module_eval("$vector.append('four')");
- result = vec.call("size");
- ASSERT_EQUAL(5, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("first");
- ASSERT_EQUAL("one", detail::From_Ruby<std::string>().convert(result));
-
- result = vec.call("last");
- ASSERT_EQUAL("four", detail::From_Ruby<std::string>().convert(result));
-}
-
-TESTCASE(WrongType)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::string>>("StringVector");
-
- Object vec = m.module_eval("$vector = StringVector.new");
- ASSERT_EXCEPTION_CHECK(
- Exception,
- m.module_eval("$vector << 1"),
- ASSERT_EQUAL("wrong argument type Integer (expected String)", ex.what()));
-}
-
-TESTCASE(Empty)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::int32_t>>("IntVector");
- Object vec = c.call("new");
-
- Object result = vec.call("size");
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("empty?");
- ASSERT_EQUAL(Qtrue, result.value());
-
- result = vec.call("first");
- ASSERT_EQUAL(Qnil, result.value());
-
- result = vec.call("last");
- ASSERT_EQUAL(Qnil, result.value());
-}
-
-TESTCASE(Indexing)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::int32_t>>("IntVector");
- Object vec = c.call("new");
- vec.call("push", 0);
- vec.call("push", 1);
- vec.call("push", 2);
-
- Object result = vec.call("size");
- ASSERT_EQUAL(3, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", 0);
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", 1);
- ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", 2);
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", 3);
- ASSERT_EQUAL(Qnil, result.value());
-
- result = vec.call("[]", -1);
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", -2);
- ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", -3);
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", -4);
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]", -7);
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-}
-
-TESTCASE(Sizing)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::int32_t>>("IntVector");
- Object vec = c.call("new");
- vec.call("resize", 10);
-
- Object result = vec.call("size");
- ASSERT_EQUAL(10, detail::From_Ruby<int32_t>().convert(result));
-
- vec.call("clear");
-
- result = vec.call("size");
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-}
-
-TESTCASE(ToString)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::int32_t>>("IntVector");
- Object vec = c.call("new");
- vec.call("resize", 3);
-
- Object result = vec.call("to_s");
- ASSERT_EQUAL("[0, 0, 0]", detail::From_Ruby<std::string>().convert(result));
-
- vec.call("clear");
-
- result = vec.call("to_s");
- ASSERT_EQUAL("[]", detail::From_Ruby<std::string>().convert(result));
-}
-
-TESTCASE(Update)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::string>>("StringVector");
- Object vec = c.call("new");
- vec.call("push", "original 1");
- vec.call("push", "original 2");
-
- Object result = vec.call("size");
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("[]=", 1, "new 2");
- ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
-
- result = vec.call("[]", 1);
- ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
-
- ASSERT_EXCEPTION_CHECK(
- Exception,
- result = vec.call("[]=", 99999, "new 2"),
- ASSERT_EQUAL("Invalid index: 99999", ex.what()));
-}
-
-TESTCASE(Modify)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<int64_t>>("Int64Vector");
- Object vec = c.call("new");
-
- Object result = vec.call("push", 11);
- ASSERT(result.is_equal(vec));
-
- result = vec.call("push", 22);
- ASSERT(result.is_equal(vec));
-
- result = vec.call("size");
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("insert", 1, 33);
- ASSERT(result.is_equal(vec));
-
- result = vec.call("to_s");
- ASSERT_EQUAL("[11, 33, 22]", detail::From_Ruby<std::string>().convert(result));
-
- result = vec.call("delete", 11);
- ASSERT_EQUAL(11, detail::From_Ruby<int64_t>().convert(result));
-
- result = vec.call("size");
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("delete_at", 0);
- ASSERT_EQUAL(33, detail::From_Ruby<int64_t>().convert(result));
-
- result = vec.call("size");
- ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("pop");
- ASSERT_EQUAL(22, detail::From_Ruby<int64_t>().convert(result));
-
- result = vec.call("size");
- ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
-
- result = vec.call("pop");
- ASSERT_EQUAL(Qnil, result.value());
-}
-
-TESTCASE(Copy)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<double>>("DoubleVector");
- Object object = c.call("new");
-
- object.call("push", 11.1);
- object.call("push", 22.2);
- std::vector<double>& vec = detail::From_Ruby<std::vector<double>&>().convert(object);
-
- Object result = object.call("copy");
- std::vector<double>& vecCopy = detail::From_Ruby<std::vector<double>&>().convert(result);
-
- ASSERT_EQUAL(vec.size(), vecCopy.size());
- ASSERT_EQUAL(vec[0], vecCopy[0]);
- ASSERT_EQUAL(vec[1], vecCopy[1]);
-
- vecCopy.push_back(33.3);
- ASSERT_NOT_EQUAL(vec.size(), vecCopy.size());
-}
-
-namespace
-{
- class NotComparable
- {
- public:
- NotComparable(uint32_t value) : value_(value)
- {
- };
-
- uint32_t value_;
- };
-}
-
-TESTCASE(NotComparable)
-{
- define_class<NotComparable>("NotComparable").
- define_constructor(Constructor<NotComparable, uint32_t>());
-
- Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
-
- Object vec = c.call("new");
- vec.call("push", NotComparable(1));
- vec.call("push", NotComparable(2));
- vec.call("push", NotComparable(3));
-
- Object result = vec.call("delete", NotComparable(1));
- ASSERT_EQUAL(Qnil, result.value());
-
- result = vec.call("length");
- ASSERT_EQUAL(3u, detail::From_Ruby<size_t>().convert(result));
-
- result = vec.call("include?", NotComparable(2));
- ASSERT_EQUAL(Qfalse, result.value());
-
- result = vec.call("index", NotComparable(3));
- ASSERT_EQUAL(Qnil, result.value());
-}
-
-TESTCASE(NotDefaultConstructable)
-{
- define_class<NotComparable>("NotComparable").
- define_constructor(Constructor<NotComparable, uint32_t>());
-
- Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
- Object vec = c.call("new");
-
- Object result = vec.call("resize", 10);
- ASSERT_EQUAL(Qnil, result.value());
-
- result = vec.call("length");
- ASSERT_EQUAL(0, detail::From_Ruby<size_t>().convert(result));
-}
-
-TESTCASE(NotPrintable)
-{
- define_class<NotComparable>("NotComparable").
- define_constructor(Constructor<NotComparable, uint32_t>());
-
- Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
-
- Object vec = c.call("new");
- vec.call("push", NotComparable(1));
- vec.call("push", NotComparable(2));
- vec.call("push", NotComparable(3));
-
- Object result = vec.call("to_s");
- ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
-}
-
-namespace
-{
- class Comparable
- {
- public:
- Comparable(uint32_t value) : value_(value)
- {
- };
-
- bool operator==(const Comparable& other)
- {
- return this->value_ == other.value_;
- }
-
- uint32_t value_;
- };
-
- inline std::ostream& operator<<(std::ostream& stream, Comparable const& comparable)
- {
- stream << "Comparable(" << std::to_string(comparable.value_) << ")";
- return stream;
- }
-}
-
-TESTCASE(Comparable)
-{
- define_class<Comparable>("IsComparable").
- define_constructor(Constructor<Comparable, uint32_t>());
-
- Class c = define_vector<std::vector<Comparable>>("ComparableVector");
-
- Object vec = c.call("new");
-
- Comparable comparable1(1);
- vec.call("push", comparable1);
-
- Comparable comparable2(2);
- vec.call("push", comparable2);
-
- Comparable comparable3(3);
- vec.call("push", comparable3);
-
- Object result = vec.call("delete", Comparable(1));
- Comparable comparable = detail::From_Ruby<Comparable>().convert(result);
- ASSERT_EQUAL(1, comparable.value_);
-
- result = vec.call("length");
- ASSERT_EQUAL(2, detail::From_Ruby<size_t>().convert(result));
-
- result = vec.call("include?", Comparable(2));
- ASSERT_EQUAL(Qtrue, result.value());
-
- result = vec.call("index", Comparable(3));
- ASSERT_EQUAL(1, detail::From_Ruby<size_t>().convert(result.value()));
-}
-
-TESTCASE(DefaultConstructable)
-{
- define_class<Comparable>("IsComparable").
- define_constructor(Constructor<Comparable, uint32_t>());
-
- Class c = define_vector<std::vector<Comparable>>("ComparableVector");
- Object vec = c.call("new");
-
- Object result = vec.call("resize", 10);
- ASSERT_EQUAL(Qnil, result.value());
-
- result = vec.call("length");
- ASSERT_EQUAL(0, detail::From_Ruby<size_t>().convert(result));
-}
-
-TESTCASE(Printable)
-{
- define_class<Comparable>("IsComparable").
- define_constructor(Constructor<Comparable, uint32_t>());
-
- Class c = define_vector<std::vector<Comparable>>("ComparableVector");
-
- Object vec = c.call("new");
- vec.call("push", Comparable(1));
- vec.call("push", Comparable(2));
- vec.call("push", Comparable(3));
-
- Object result = vec.call("to_s");
- ASSERT_EQUAL("[Comparable(1), Comparable(2), Comparable(3)]", detail::From_Ruby<std::string>().convert(result));
-}
-
-namespace
-{
- std::vector<std::complex<double>> returnComplexVector()
- {
- std::complex<double> complex1(1, 1);
- std::complex<double> complex2(2, 2);
- std::complex<double> complex3(3, 3);
-
- std::vector<std::complex<double>> result;
- result.push_back(complex1);
- result.push_back(complex2);
- result.push_back(complex3);
- return result;
- }
-
- std::vector<std::complex<double>> passComplexVector(std::vector<std::complex<double>>& complexes)
- {
- return complexes;
- }
-}
-
-TESTCASE(AutoRegisterReturn)
-{
- define_global_function("return_complex_vector", &returnComplexVector);
-
- Module m = define_module("Testing");
- Object vec = m.module_eval("return_complex_vector");
- ASSERT_EQUAL("Rice::Std::Vector__complex__double___allocator__complex__double______", vec.class_name().str());
-
- std::string code = R"(vector = return_complex_vector
- complex = vector.last
- complex == Complex(3, 3))";
-
- Object result = m.module_eval(code);
- ASSERT_EQUAL(Qtrue, result.value());
-
- // Now register this same vector
- define_vector<std::vector<std::complex<double>>>("ComplexVector");
- code = R"(vector = ComplexVector.new)";
- result = m.module_eval(code);
- ASSERT(result.is_instance_of(vec.class_of()));
-
- // Now register it again in the module
- define_vector_under<std::vector<std::complex<double>>>(m, "ComplexVector2");
- code = R"(vector = Testing::ComplexVector2.new)";
- result = m.module_eval(code);
- ASSERT(result.is_instance_of(vec.class_of()));
-}
-
-TESTCASE(AutoRegisterParameter)
-{
- define_global_function("pass_complex_vector", &passComplexVector);
-
- std::string code = R"(vector = Rice::Std::Vector__complex__double___allocator__complex__double______.new
- vector << Complex(4.0, 4.0)
- vector << Complex(5.0, 5.0)
- pass_complex_vector(vector))";
-
- Module m = define_module("Testing");
- Object vec = m.module_eval(code);
-
- Object result = vec.call("size");
- ASSERT_EQUAL("Rice::Std::Vector__complex__double___allocator__complex__double______", vec.class_name().str());
- ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
-
- std::vector<std::complex<double>> complexes = detail::From_Ruby<std::vector<std::complex<double>>>().convert(vec);
- ASSERT_EQUAL(complexes[0], std::complex<double>(4, 4));
- ASSERT_EQUAL(complexes[1], std::complex<double>(5, 5));
-}
-
-namespace
-{
- std::vector<std::string> defaultVector(std::vector<std::string> strings = {"one", "two", "three"})
- {
- return strings;
- }
-}
-
-TESTCASE(DefaultValue)
-{
- define_vector<std::vector<std::string>>("StringVector");
- define_global_function("default_vector", &defaultVector, Arg("strings") = std::vector<std::string> { "one", "two", "three" });
-
- Module m = define_module("Testing");
- Object result = m.module_eval("default_vector");
- std::vector<std::string> actual = detail::From_Ruby<std::vector<std::string>>().convert(result);
-
- std::vector<std::string> expected{ "one", "two", "three" };
-
- ASSERT_EQUAL(expected.size(), actual.size());
- ASSERT_EQUAL(expected[0], actual[0]);
- ASSERT_EQUAL(expected[1], actual[1]);
- ASSERT_EQUAL(expected[2], actual[2]);
-}
-
-TESTCASE(ToArray)
-{
- Module m = define_module("Testing");
-
- Class c = define_vector<std::vector<std::string>>("StringVector").
- define_constructor(Constructor<std::vector<std::string>>());
-
- std::string code = R"(vector = StringVector.new
- vector << "abc"
- vector << "def"
- vector << "ghi"
- vector.to_a)";
-
- Array array = m.module_eval(code);
- ASSERT_EQUAL(3u, array.size());
-
- ASSERT_EQUAL("abc", detail::From_Ruby<std::string>().convert(array[0].value()));
- ASSERT_EQUAL("def", detail::From_Ruby<std::string>().convert(array[1].value()));
- ASSERT_EQUAL("ghi", detail::From_Ruby<std::string>().convert(array[2].value()));
-}
-
-namespace
-{
- std::vector<int> ints;
- std::vector<float> floats;
- std::vector<std::string> strings;
-
- void arrayToVector(std::vector<int> aInts, std::vector<float> aFloats, std::vector<std::string> aStrings)
- {
- ints = aInts;
- floats = aFloats;
- strings = aStrings;
- }
-
- void arrayToVectorRefs(std::vector<int>& aInts, std::vector<float>& aFloats, std::vector<std::string>& aStrings)
- {
- ints = aInts;
- floats = aFloats;
- strings = aStrings;
- }
-
- void arrayToVectorPointers(std::vector<int>* aInts, std::vector<float>* aFloats, std::vector<std::string>* aStrings)
- {
- ints = *aInts;
- floats = *aFloats;
- strings = *aStrings;
- }
-}
-
-TESTCASE(ArrayToVector)
-{
- define_global_function("array_to_vector", &arrayToVector);
-
- Module m = define_module("Testing");
-
- std::string code = "array_to_vector([7, 9, 1_000_000], [49.0, 78.0, 999.0], %w[one two three])";
- m.module_eval(code);
-
- ASSERT_EQUAL(3, ints.size());
- ASSERT_EQUAL(7, ints[0]);
- ASSERT_EQUAL(9, ints[1]);
- ASSERT_EQUAL(1'000'000, ints[2]);
-
- ASSERT_EQUAL(3, floats.size());
- ASSERT_EQUAL(49.0, floats[0]);
- ASSERT_EQUAL(78.0, floats[1]);
- ASSERT_EQUAL(999.0, floats[2]);
-
- ASSERT_EQUAL(3, strings.size());
- ASSERT_EQUAL("one", strings[0]);
- ASSERT_EQUAL("two", strings[1]);
- ASSERT_EQUAL("three", strings[2]);
-}
-
-TESTCASE(ArrayToVectorRefs)
-{
- define_global_function("array_to_vector_refs", &arrayToVectorRefs);
-
- Module m = define_module("Testing");
-
- std::string code = "array_to_vector_refs([8, 10, 1_000_001], [50.0, 79.0, 1_000.0], %w[eleven twelve thirteen])";
- m.module_eval(code);
-
- ASSERT_EQUAL(3, ints.size());
- ASSERT_EQUAL(8, ints[0]);
- ASSERT_EQUAL(10, ints[1]);
- ASSERT_EQUAL(1'000'001, ints[2]);
-
- ASSERT_EQUAL(3, floats.size());
- ASSERT_EQUAL(50.0, floats[0]);
- ASSERT_EQUAL(79.0, floats[1]);
- ASSERT_EQUAL(1'000.0, floats[2]);
-
- ASSERT_EQUAL(3, strings.size());
- ASSERT_EQUAL("eleven", strings[0]);
- ASSERT_EQUAL("twelve", strings[1]);
- ASSERT_EQUAL("thirteen", strings[2]);
-}
-
-TESTCASE(ArrayToVectorPointers)
-{
- define_global_function("array_to_vector_pointers", &arrayToVectorPointers);
-
- Module m = define_module("Testing");
-
- std::string code = "array_to_vector_pointers([9, 11, 1_000_002], [51.0, 80.0, 1_001.0], %w[fourteen fifteen sixteen])";
- m.module_eval(code);
-
- ASSERT_EQUAL(3, ints.size());
- ASSERT_EQUAL(9, ints[0]);
- ASSERT_EQUAL(11, ints[1]);
- ASSERT_EQUAL(1'000'002, ints[2]);
-
- ASSERT_EQUAL(3, floats.size());
- ASSERT_EQUAL(51.0, floats[0]);
- ASSERT_EQUAL(80.0, floats[1]);
- ASSERT_EQUAL(1'001.0, floats[2]);
-
- ASSERT_EQUAL(3, strings.size());
- ASSERT_EQUAL("fourteen", strings[0]);
- ASSERT_EQUAL("fifteen", strings[1]);
- ASSERT_EQUAL("sixteen", strings[2]);
-}
-
-TESTCASE(ArrayToVectorWrongTypes)
-{
- define_global_function("array_to_vector", &arrayToVector);
-
- Module m = define_module("Testing");
-
- std::string code = "array_to_vector([7, 9, 1_000_000], [49.0, 78.0, 999.0], [50.0, 79.0, 1000.0])";
-
- ASSERT_EXCEPTION_CHECK(
- Exception,
- m.module_eval(code),
- ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
- );
-}
-
-TESTCASE(ArrayToVectorMixedTypes)
-{
- define_global_function("array_to_vector", &arrayToVector);
-
- Module m = define_module("Testing");
-
- std::string code = "array_to_vector([7, 'nine', true], [49.0, 78.0, 999.0], %w[one two three])";
-
- ASSERT_EXCEPTION_CHECK(
- Exception,
- m.module_eval(code),
- ASSERT_EQUAL("no implicit conversion of String into Integer", ex.what())
- );
-}
-
-namespace
-{
- class Factory
- {
- public:
- std::vector<std::string>* returnPointer()
- {
- return &this->instance_;
- }
-
- std::vector<std::string>& returnReference()
- {
- return this->instance_;
- }
-
- std::vector<std::string> returnValue()
- {
- return this->instance_;
- }
-
- public:
- static inline std::vector<std::string> instance_{ "one", "two", "three" };
- };
-
- std::ostream& operator<<(std::ostream& stream, const std::vector<std::string>& vector)
- {
- stream << "Vector";
- return stream;
- }
-}
-
-void createFactoryClass()
-{
- define_class<Factory>("Factory").
- define_constructor(Constructor<Factory>()).
- define_method("pointer", &Factory::returnPointer).
- define_method("reference", &Factory::returnReference).
- define_method("value", &Factory::returnValue);
-}
-
-TESTCASE(Returns)
-{
- createFactoryClass();
- Module m = define_module("TestingModule");
- Object factory = m.module_eval("Factory.new");
-
- std::vector<std::string> expected{ "one", "two", "three" };
-
- Data_Object<std::vector<std::string>> vec1 = factory.call("pointer");
- ASSERT_EQUAL(expected, *vec1);
-
- Data_Object<std::vector<std::string>> vec2 = factory.call("reference");
- ASSERT_EQUAL(expected, *vec2);
-
- Data_Object<std::vector<std::string>> vec3 = factory.call("value");
- ASSERT_EQUAL(expected, *vec3);
-}
-
-TESTCASE(Iterate)
-{
- Module m = define_module("Testing");
- Class c = define_vector<std::vector<double>>("DoubleVector");
-
- std::string code = R"(vector = DoubleVector.new
- vector << 5.0 << 6.0 << 7.0
- updated = vector.map do |value|
- value * 2.0
- end)";
-
- Array result = m.module_eval(code);
- ASSERT_EQUAL(3, result.size());
- ASSERT_EQUAL(10.0, detail::From_Ruby<double>().convert(result[0].value()));
- ASSERT_EQUAL(12.0, detail::From_Ruby<double>().convert(result[1].value()));
- ASSERT_EQUAL(14.0, detail::From_Ruby<double>().convert(result[2].value()));
-}
-
-TESTCASE(ToEnumPointer)
-{
- createFactoryClass();
- Module m = define_module("TestingModule");
-
- std::string code = R"(factory = Factory.new
- vector = factory.pointer
- updated = vector.each.map do |value|
- value + "_updated"
- end)";
-
- Array result = m.module_eval(code);
-
- ASSERT_EQUAL(3, result.size());
- ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
- ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
- ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
-}
-
-TESTCASE(ToEnumReference)
-{
- createFactoryClass();
- Module m = define_module("TestingModule");
-
- std::string code = R"(factory = Factory.new
- vector = factory.reference
- updated = vector.each.map do |value|
- value + "_updated"
- end)";
-
- Array result = m.module_eval(code);
-
- ASSERT_EQUAL(3, result.size());
- ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
- ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
- ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
-}
-
-TESTCASE(ToEnumValue)
-{
- createFactoryClass();
- Module m = define_module("TestingModule");
-
- std::string code = R"(factory = Factory.new
- vector = factory.value
- updated = vector.each.map do |value|
- value + "_updated"
- end)";
-
- Array result = m.module_eval(code);
-
- ASSERT_EQUAL(3, result.size());
- ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
- ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
- ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
-}
-
-TESTCASE(ToEnumSize)
-{
- createFactoryClass();
- Module m = define_module("TestingModule");
- Object factory = m.module_eval("Factory.new");
- Object vector = factory.call("pointer");
- Object enumerable = vector.call("each");
- Object result = enumerable.call("size");
-
- ASSERT_EQUAL(3, detail::From_Ruby<int>().convert(result));
-}
-
-namespace
-{
- std::vector<std::string*> vectorOfStringPointers()
- {
- std::vector<std::string*> result;
- std::string* pString = new std::string("Hello");
- result.push_back(pString);
- return result;
- }
-}
-
-TESTCASE(StringPointerVector)
-{
- define_global_function("vector_of_string_pointers", &vectorOfStringPointers);
-
- Module m(rb_mKernel);
- Data_Object<std::vector<std::string*>> vec = m.call("vector_of_string_pointers");
- ASSERT_EQUAL(1, vec->size());
-
- std::string expected("Hello");
- std::string* actual = (*vec)[0];
- ASSERT_EQUAL(expected, *actual);
-}
-
-namespace
-{
- class MyClass2
- {
- public:
- MyClass2(std::string name): name(name)
- {
- }
- std::string name;
- };
-
- std::vector<MyClass2*> vectorOfMyClass2Pointers()
- {
- std::vector<MyClass2*> result;
- MyClass2* pMyClass = new MyClass2("Hello MyClass2");
- result.push_back(pMyClass);
- return result;
- }
-}
-
-TESTCASE(MyClass2PointerVector)
-{
- Class c = define_class<MyClass2>("MyClass2").
- define_constructor(Constructor<MyClass2, std::string>()).
- define_attr("name", &MyClass2::name, AttrAccess::Read);
-
- define_global_function("vector_of_myclass2_pointers", &vectorOfMyClass2Pointers);
-
- Module m(rb_mKernel);
- Data_Object<std::vector<MyClass2*>> result = m.call("vector_of_myclass2_pointers");
- ASSERT_EQUAL(1, result->size());
-
- MyClass2* pMyClass = (*result)[0];
- ASSERT_EQUAL("Hello MyClass2", pMyClass->name);
-}
+#include <complex>
+
+#include "unittest.hpp"
+#include "embed_ruby.hpp"
+#include <rice/rice.hpp>
+#include <rice/stl.hpp>
+
+using namespace Rice;
+
+TESTSUITE(Vector);
+
+SETUP(Vector)
+{
+ embed_ruby();
+}
+
+namespace
+{
+
+ class MyClass
+ {
+ public:
+ std::vector<std::string> stringVector()
+ {
+ std::vector<std::string> result{ "One", "Two", "Three" };
+ return result;
+ }
+ };
+}
+
+Class makeVectorClass()
+{
+ Class c = define_class<MyClass>("MyClass").
+ define_constructor(Constructor<MyClass>()).
+ define_method("stringVector", &MyClass::stringVector);
+
+ return c;
+}
+
+TESTCASE(StringVector)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::string>>("StringVector");
+
+ Object vec = m.module_eval("$vector = StringVector.new");
+ Object result = vec.call("size");
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+
+ m.module_eval("$vector << 'one' << 'two' << 'two' << 'three'");
+ result = vec.call("size");
+ ASSERT_EQUAL(4, detail::From_Ruby<int32_t>().convert(result));
+
+ m.module_eval("$vector.append('four')");
+ result = vec.call("size");
+ ASSERT_EQUAL(5, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("first");
+ ASSERT_EQUAL("one", detail::From_Ruby<std::string>().convert(result));
+
+ result = vec.call("last");
+ ASSERT_EQUAL("four", detail::From_Ruby<std::string>().convert(result));
+}
+
+TESTCASE(WrongType)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::string>>("StringVector");
+
+ Object vec = m.module_eval("$vector = StringVector.new");
+ ASSERT_EXCEPTION_CHECK(
+ Exception,
+ m.module_eval("$vector << 1"),
+ ASSERT_EQUAL("wrong argument type Integer (expected String)", ex.what()));
+}
+
+TESTCASE(Empty)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::int32_t>>("IntVector");
+ Object vec = c.call("new");
+
+ Object result = vec.call("size");
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("empty?");
+ ASSERT_EQUAL(Qtrue, result.value());
+
+ result = vec.call("first");
+ ASSERT_EQUAL(Qnil, result.value());
+
+ result = vec.call("last");
+ ASSERT_EQUAL(Qnil, result.value());
+}
+
+TESTCASE(Indexing)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::int32_t>>("IntVector");
+ Object vec = c.call("new");
+ vec.call("push", 0);
+ vec.call("push", 1);
+ vec.call("push", 2);
+
+ Object result = vec.call("size");
+ ASSERT_EQUAL(3, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", 0);
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", 1);
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", 2);
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", 3);
+ ASSERT_EQUAL(Qnil, result.value());
+
+ result = vec.call("[]", -1);
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", -2);
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", -3);
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", -4);
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]", -7);
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+}
+
+TESTCASE(Sizing)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::int32_t>>("IntVector");
+ Object vec = c.call("new");
+ vec.call("resize", 10);
+
+ Object result = vec.call("size");
+ ASSERT_EQUAL(10, detail::From_Ruby<int32_t>().convert(result));
+
+ vec.call("clear");
+
+ result = vec.call("size");
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+}
+
+TESTCASE(ToString)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::int32_t>>("IntVector");
+ Object vec = c.call("new");
+ vec.call("resize", 3);
+
+ Object result = vec.call("to_s");
+ ASSERT_EQUAL("[0, 0, 0]", detail::From_Ruby<std::string>().convert(result));
+
+ vec.call("clear");
+
+ result = vec.call("to_s");
+ ASSERT_EQUAL("[]", detail::From_Ruby<std::string>().convert(result));
+}
+
+TESTCASE(Update)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::string>>("StringVector");
+ Object vec = c.call("new");
+ vec.call("push", "original 1");
+ vec.call("push", "original 2");
+
+ Object result = vec.call("size");
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("[]=", 1, "new 2");
+ ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
+
+ result = vec.call("[]", 1);
+ ASSERT_EQUAL("new 2", detail::From_Ruby<std::string>().convert(result));
+
+ ASSERT_EXCEPTION_CHECK(
+ Exception,
+ result = vec.call("[]=", 99999, "new 2"),
+ ASSERT_EQUAL("Invalid index: 99999", ex.what()));
+}
+
+TESTCASE(Modify)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<int64_t>>("Int64Vector");
+ Object vec = c.call("new");
+
+ Object result = vec.call("push", 11);
+ ASSERT(result.is_equal(vec));
+
+ result = vec.call("push", 22);
+ ASSERT(result.is_equal(vec));
+
+ result = vec.call("size");
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("insert", 1, 33);
+ ASSERT(result.is_equal(vec));
+
+ result = vec.call("to_s");
+ ASSERT_EQUAL("[11, 33, 22]", detail::From_Ruby<std::string>().convert(result));
+
+ result = vec.call("delete", 11);
+ ASSERT_EQUAL(11, detail::From_Ruby<int64_t>().convert(result));
+
+ result = vec.call("size");
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("delete_at", 0);
+ ASSERT_EQUAL(33, detail::From_Ruby<int64_t>().convert(result));
+
+ result = vec.call("size");
+ ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("pop");
+ ASSERT_EQUAL(22, detail::From_Ruby<int64_t>().convert(result));
+
+ result = vec.call("size");
+ ASSERT_EQUAL(0, detail::From_Ruby<int32_t>().convert(result));
+
+ result = vec.call("pop");
+ ASSERT_EQUAL(Qnil, result.value());
+}
+
+TESTCASE(Copy)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<double>>("DoubleVector");
+ Object object = c.call("new");
+
+ object.call("push", 11.1);
+ object.call("push", 22.2);
+ std::vector<double>& vec = detail::From_Ruby<std::vector<double>&>().convert(object);
+
+ Object result = object.call("copy");
+ std::vector<double>& vecCopy = detail::From_Ruby<std::vector<double>&>().convert(result);
+
+ ASSERT_EQUAL(vec.size(), vecCopy.size());
+ ASSERT_EQUAL(vec[0], vecCopy[0]);
+ ASSERT_EQUAL(vec[1], vecCopy[1]);
+
+ vecCopy.push_back(33.3);
+ ASSERT_NOT_EQUAL(vec.size(), vecCopy.size());
+}
+
+namespace
+{
+ class NotComparable
+ {
+ public:
+ NotComparable(uint32_t value) : value_(value)
+ {
+ };
+
+ uint32_t value_;
+ };
+}
+
+TESTCASE(NotComparable)
+{
+ define_class<NotComparable>("NotComparable").
+ define_constructor(Constructor<NotComparable, uint32_t>());
+
+ Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
+
+ Object vec = c.call("new");
+ vec.call("push", NotComparable(1));
+ vec.call("push", NotComparable(2));
+ vec.call("push", NotComparable(3));
+
+ Object result = vec.call("delete", NotComparable(1));
+ ASSERT_EQUAL(Qnil, result.value());
+
+ result = vec.call("length");
+ ASSERT_EQUAL(3u, detail::From_Ruby<size_t>().convert(result));
+
+ result = vec.call("include?", NotComparable(2));
+ ASSERT_EQUAL(Qfalse, result.value());
+
+ result = vec.call("index", NotComparable(3));
+ ASSERT_EQUAL(Qnil, result.value());
+}
+
+TESTCASE(NotDefaultConstructable)
+{
+ define_class<NotComparable>("NotComparable").
+ define_constructor(Constructor<NotComparable, uint32_t>());
+
+ Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
+ Object vec = c.call("new");
+
+ Object result = vec.call("resize", 10);
+ ASSERT_EQUAL(Qnil, result.value());
+
+ result = vec.call("length");
+ ASSERT_EQUAL(0, detail::From_Ruby<size_t>().convert(result));
+}
+
+TESTCASE(NotPrintable)
+{
+ define_class<NotComparable>("NotComparable").
+ define_constructor(Constructor<NotComparable, uint32_t>());
+
+ Class c = define_vector<std::vector<NotComparable>>("NotComparableVector");
+
+ Object vec = c.call("new");
+ vec.call("push", NotComparable(1));
+ vec.call("push", NotComparable(2));
+ vec.call("push", NotComparable(3));
+
+ Object result = vec.call("to_s");
+ ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
+}
+
+namespace
+{
+ class Comparable
+ {
+ public:
+ Comparable(uint32_t value) : value_(value)
+ {
+ };
+
+ bool operator==(const Comparable& other)
+ {
+ return this->value_ == other.value_;
+ }
+
+ uint32_t value_;
+ };
+
+ inline std::ostream& operator<<(std::ostream& stream, Comparable const& comparable)
+ {
+ stream << "Comparable(" << std::to_string(comparable.value_) << ")";
+ return stream;
+ }
+}
+
+TESTCASE(Comparable)
+{
+ define_class<Comparable>("IsComparable").
+ define_constructor(Constructor<Comparable, uint32_t>());
+
+ Class c = define_vector<std::vector<Comparable>>("ComparableVector");
+
+ Object vec = c.call("new");
+
+ Comparable comparable1(1);
+ vec.call("push", comparable1);
+
+ Comparable comparable2(2);
+ vec.call("push", comparable2);
+
+ Comparable comparable3(3);
+ vec.call("push", comparable3);
+
+ Object result = vec.call("delete", Comparable(1));
+ Comparable comparable = detail::From_Ruby<Comparable>().convert(result);
+ ASSERT_EQUAL(1, comparable.value_);
+
+ result = vec.call("length");
+ ASSERT_EQUAL(2, detail::From_Ruby<size_t>().convert(result));
+
+ result = vec.call("include?", Comparable(2));
+ ASSERT_EQUAL(Qtrue, result.value());
+
+ result = vec.call("index", Comparable(3));
+ ASSERT_EQUAL(1, detail::From_Ruby<size_t>().convert(result.value()));
+}
+
+TESTCASE(DefaultConstructable)
+{
+ define_class<Comparable>("IsComparable").
+ define_constructor(Constructor<Comparable, uint32_t>());
+
+ Class c = define_vector<std::vector<Comparable>>("ComparableVector");
+ Object vec = c.call("new");
+
+ Object result = vec.call("resize", 10);
+ ASSERT_EQUAL(Qnil, result.value());
+
+ result = vec.call("length");
+ ASSERT_EQUAL(0, detail::From_Ruby<size_t>().convert(result));
+}
+
+TESTCASE(Printable)
+{
+ define_class<Comparable>("IsComparable").
+ define_constructor(Constructor<Comparable, uint32_t>());
+
+ Class c = define_vector<std::vector<Comparable>>("ComparableVector");
+
+ Object vec = c.call("new");
+ vec.call("push", Comparable(1));
+ vec.call("push", Comparable(2));
+ vec.call("push", Comparable(3));
+
+ Object result = vec.call("to_s");
+ ASSERT_EQUAL("[Comparable(1), Comparable(2), Comparable(3)]", detail::From_Ruby<std::string>().convert(result));
+}
+
+namespace
+{
+ std::vector<std::complex<double>> returnComplexVector()
+ {
+ std::complex<double> complex1(1, 1);
+ std::complex<double> complex2(2, 2);
+ std::complex<double> complex3(3, 3);
+
+ std::vector<std::complex<double>> result;
+ result.push_back(complex1);
+ result.push_back(complex2);
+ result.push_back(complex3);
+ return result;
+ }
+
+ std::vector<std::complex<double>> passComplexVector(std::vector<std::complex<double>>& complexes)
+ {
+ return complexes;
+ }
+}
+
+TESTCASE(AutoRegisterReturn)
+{
+ define_global_function("return_complex_vector", &returnComplexVector);
+
+ Module m = define_module("Testing");
+ Object vec = m.module_eval("return_complex_vector");
+ ASSERT_EQUAL("Rice::Std::Vector__complex__double___allocator__complex__double______", vec.class_name().str());
+
+ std::string code = R"(vector = return_complex_vector
+ complex = vector.last
+ complex == Complex(3, 3))";
+
+ Object result = m.module_eval(code);
+ ASSERT_EQUAL(Qtrue, result.value());
+
+ // Now register this same vector
+ define_vector<std::vector<std::complex<double>>>("ComplexVector");
+ code = R"(vector = ComplexVector.new)";
+ result = m.module_eval(code);
+ ASSERT(result.is_instance_of(vec.class_of()));
+
+ // Now register it again in the module
+ define_vector_under<std::vector<std::complex<double>>>(m, "ComplexVector2");
+ code = R"(vector = Testing::ComplexVector2.new)";
+ result = m.module_eval(code);
+ ASSERT(result.is_instance_of(vec.class_of()));
+}
+
+TESTCASE(AutoRegisterParameter)
+{
+ define_global_function("pass_complex_vector", &passComplexVector);
+
+ std::string code = R"(vector = Rice::Std::Vector__complex__double___allocator__complex__double______.new
+ vector << Complex(4.0, 4.0)
+ vector << Complex(5.0, 5.0)
+ pass_complex_vector(vector))";
+
+ Module m = define_module("Testing");
+ Object vec = m.module_eval(code);
+
+ Object result = vec.call("size");
+ ASSERT_EQUAL("Rice::Std::Vector__complex__double___allocator__complex__double______", vec.class_name().str());
+ ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
+
+ std::vector<std::complex<double>> complexes = detail::From_Ruby<std::vector<std::complex<double>>>().convert(vec);
+ ASSERT_EQUAL(complexes[0], std::complex<double>(4, 4));
+ ASSERT_EQUAL(complexes[1], std::complex<double>(5, 5));
+}
+
+namespace
+{
+ std::vector<std::string> defaultVector(std::vector<std::string> strings = {"one", "two", "three"})
+ {
+ return strings;
+ }
+}
+
+TESTCASE(DefaultValue)
+{
+ define_vector<std::vector<std::string>>("StringVector");
+ define_global_function("default_vector", &defaultVector, Arg("strings") = std::vector<std::string> { "one", "two", "three" });
+
+ Module m = define_module("Testing");
+ Object result = m.module_eval("default_vector");
+ std::vector<std::string> actual = detail::From_Ruby<std::vector<std::string>>().convert(result);
+
+ std::vector<std::string> expected{ "one", "two", "three" };
+
+ ASSERT_EQUAL(expected.size(), actual.size());
+ ASSERT_EQUAL(expected[0], actual[0]);
+ ASSERT_EQUAL(expected[1], actual[1]);
+ ASSERT_EQUAL(expected[2], actual[2]);
+}
+
+TESTCASE(ToArray)
+{
+ Module m = define_module("Testing");
+
+ Class c = define_vector<std::vector<std::string>>("StringVector").
+ define_constructor(Constructor<std::vector<std::string>>());
+
+ std::string code = R"(vector = StringVector.new
+ vector << "abc"
+ vector << "def"
+ vector << "ghi"
+ vector.to_a)";
+
+ Array array = m.module_eval(code);
+ ASSERT_EQUAL(3u, array.size());
+
+ ASSERT_EQUAL("abc", detail::From_Ruby<std::string>().convert(array[0].value()));
+ ASSERT_EQUAL("def", detail::From_Ruby<std::string>().convert(array[1].value()));
+ ASSERT_EQUAL("ghi", detail::From_Ruby<std::string>().convert(array[2].value()));
+}
+
+namespace
+{
+ std::vector<int> ints;
+ std::vector<float> floats;
+ std::vector<std::string> strings;
+
+ void arrayToVector(std::vector<int> aInts, std::vector<float> aFloats, std::vector<std::string> aStrings)
+ {
+ ints = aInts;
+ floats = aFloats;
+ strings = aStrings;
+ }
+
+ void arrayToVectorRefs(std::vector<int>& aInts, std::vector<float>& aFloats, std::vector<std::string>& aStrings)
+ {
+ ints = aInts;
+ floats = aFloats;
+ strings = aStrings;
+ }
+
+ void arrayToVectorPointers(std::vector<int>* aInts, std::vector<float>* aFloats, std::vector<std::string>* aStrings)
+ {
+ ints = *aInts;
+ floats = *aFloats;
+ strings = *aStrings;
+ }
+}
+
+TESTCASE(ArrayToVector)
+{
+ define_global_function("array_to_vector", &arrayToVector);
+
+ Module m = define_module("Testing");
+
+ std::string code = "array_to_vector([7, 9, 1_000_000], [49.0, 78.0, 999.0], %w[one two three])";
+ m.module_eval(code);
+
+ ASSERT_EQUAL(3, ints.size());
+ ASSERT_EQUAL(7, ints[0]);
+ ASSERT_EQUAL(9, ints[1]);
+ ASSERT_EQUAL(1'000'000, ints[2]);
+
+ ASSERT_EQUAL(3, floats.size());
+ ASSERT_EQUAL(49.0, floats[0]);
+ ASSERT_EQUAL(78.0, floats[1]);
+ ASSERT_EQUAL(999.0, floats[2]);
+
+ ASSERT_EQUAL(3, strings.size());
+ ASSERT_EQUAL("one", strings[0]);
+ ASSERT_EQUAL("two", strings[1]);
+ ASSERT_EQUAL("three", strings[2]);
+}
+
+TESTCASE(ArrayToVectorRefs)
+{
+ define_global_function("array_to_vector_refs", &arrayToVectorRefs);
+
+ Module m = define_module("Testing");
+
+ std::string code = "array_to_vector_refs([8, 10, 1_000_001], [50.0, 79.0, 1_000.0], %w[eleven twelve thirteen])";
+ m.module_eval(code);
+
+ ASSERT_EQUAL(3, ints.size());
+ ASSERT_EQUAL(8, ints[0]);
+ ASSERT_EQUAL(10, ints[1]);
+ ASSERT_EQUAL(1'000'001, ints[2]);
+
+ ASSERT_EQUAL(3, floats.size());
+ ASSERT_EQUAL(50.0, floats[0]);
+ ASSERT_EQUAL(79.0, floats[1]);
+ ASSERT_EQUAL(1'000.0, floats[2]);
+
+ ASSERT_EQUAL(3, strings.size());
+ ASSERT_EQUAL("eleven", strings[0]);
+ ASSERT_EQUAL("twelve", strings[1]);
+ ASSERT_EQUAL("thirteen", strings[2]);
+}
+
+TESTCASE(ArrayToVectorPointers)
+{
+ define_global_function("array_to_vector_pointers", &arrayToVectorPointers);
+
+ Module m = define_module("Testing");
+
+ std::string code = "array_to_vector_pointers([9, 11, 1_000_002], [51.0, 80.0, 1_001.0], %w[fourteen fifteen sixteen])";
+ m.module_eval(code);
+
+ ASSERT_EQUAL(3, ints.size());
+ ASSERT_EQUAL(9, ints[0]);
+ ASSERT_EQUAL(11, ints[1]);
+ ASSERT_EQUAL(1'000'002, ints[2]);
+
+ ASSERT_EQUAL(3, floats.size());
+ ASSERT_EQUAL(51.0, floats[0]);
+ ASSERT_EQUAL(80.0, floats[1]);
+ ASSERT_EQUAL(1'001.0, floats[2]);
+
+ ASSERT_EQUAL(3, strings.size());
+ ASSERT_EQUAL("fourteen", strings[0]);
+ ASSERT_EQUAL("fifteen", strings[1]);
+ ASSERT_EQUAL("sixteen", strings[2]);
+}
+
+TESTCASE(ArrayToVectorWrongTypes)
+{
+ define_global_function("array_to_vector", &arrayToVector);
+
+ Module m = define_module("Testing");
+
+ std::string code = "array_to_vector([7, 9, 1_000_000], [49.0, 78.0, 999.0], [50.0, 79.0, 1000.0])";
+
+ ASSERT_EXCEPTION_CHECK(
+ Exception,
+ m.module_eval(code),
+ ASSERT_EQUAL("wrong argument type Float (expected String)", ex.what())
+ );
+}
+
+TESTCASE(ArrayToVectorMixedTypes)
+{
+ define_global_function("array_to_vector", &arrayToVector);
+
+ Module m = define_module("Testing");
+
+ std::string code = "array_to_vector([7, 'nine', true], [49.0, 78.0, 999.0], %w[one two three])";
+
+ ASSERT_EXCEPTION_CHECK(
+ Exception,
+ m.module_eval(code),
+ ASSERT_EQUAL("no implicit conversion of String into Integer", ex.what())
+ );
+}
+
+namespace
+{
+ class Factory
+ {
+ public:
+ std::vector<std::string>* returnPointer()
+ {
+ return &this->instance_;
+ }
+
+ std::vector<std::string>& returnReference()
+ {
+ return this->instance_;
+ }
+
+ std::vector<std::string> returnValue()
+ {
+ return this->instance_;
+ }
+
+ public:
+ static inline std::vector<std::string> instance_{ "one", "two", "three" };
+ };
+
+ std::ostream& operator<<(std::ostream& stream, const std::vector<std::string>& vector)
+ {
+ stream << "Vector";
+ return stream;
+ }
+}
+
+void createFactoryClass()
+{
+ define_class<Factory>("Factory").
+ define_constructor(Constructor<Factory>()).
+ define_method("pointer", &Factory::returnPointer).
+ define_method("reference", &Factory::returnReference).
+ define_method("value", &Factory::returnValue);
+}
+
+TESTCASE(Returns)
+{
+ createFactoryClass();
+ Module m = define_module("TestingModule");
+ Object factory = m.module_eval("Factory.new");
+
+ std::vector<std::string> expected{ "one", "two", "three" };
+
+ Data_Object<std::vector<std::string>> vec1 = factory.call("pointer");
+ ASSERT_EQUAL(expected, *vec1);
+
+ Data_Object<std::vector<std::string>> vec2 = factory.call("reference");
+ ASSERT_EQUAL(expected, *vec2);
+
+ Data_Object<std::vector<std::string>> vec3 = factory.call("value");
+ ASSERT_EQUAL(expected, *vec3);
+}
+
+TESTCASE(Iterate)
+{
+ Module m = define_module("Testing");
+ Class c = define_vector<std::vector<double>>("DoubleVector");
+
+ std::string code = R"(vector = DoubleVector.new
+ vector << 5.0 << 6.0 << 7.0
+ updated = vector.map do |value|
+ value * 2.0
+ end)";
+
+ Array result = m.module_eval(code);
+ ASSERT_EQUAL(3, result.size());
+ ASSERT_EQUAL(10.0, detail::From_Ruby<double>().convert(result[0].value()));
+ ASSERT_EQUAL(12.0, detail::From_Ruby<double>().convert(result[1].value()));
+ ASSERT_EQUAL(14.0, detail::From_Ruby<double>().convert(result[2].value()));
+}
+
+TESTCASE(ToEnumPointer)
+{
+ createFactoryClass();
+ Module m = define_module("TestingModule");
+
+ std::string code = R"(factory = Factory.new
+ vector = factory.pointer
+ updated = vector.each.map do |value|
+ value + "_updated"
+ end)";
+
+ Array result = m.module_eval(code);
+
+ ASSERT_EQUAL(3, result.size());
+ ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
+ ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
+ ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
+}
+
+TESTCASE(ToEnumReference)
+{
+ createFactoryClass();
+ Module m = define_module("TestingModule");
+
+ std::string code = R"(factory = Factory.new
+ vector = factory.reference
+ updated = vector.each.map do |value|
+ value + "_updated"
+ end)";
+
+ Array result = m.module_eval(code);
+
+ ASSERT_EQUAL(3, result.size());
+ ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
+ ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
+ ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
+}
+
+TESTCASE(ToEnumValue)
+{
+ createFactoryClass();
+ Module m = define_module("TestingModule");
+
+ std::string code = R"(factory = Factory.new
+ vector = factory.value
+ updated = vector.each.map do |value|
+ value + "_updated"
+ end)";
+
+ Array result = m.module_eval(code);
+
+ ASSERT_EQUAL(3, result.size());
+ ASSERT_EQUAL("one_updated", detail::From_Ruby<std::string>().convert(result[0].value()));
+ ASSERT_EQUAL("two_updated", detail::From_Ruby<std::string>().convert(result[1].value()));
+ ASSERT_EQUAL("three_updated", detail::From_Ruby<std::string>().convert(result[2].value()));
+}
+
+TESTCASE(ToEnumSize)
+{
+ createFactoryClass();
+ Module m = define_module("TestingModule");
+ Object factory = m.module_eval("Factory.new");
+ Object vector = factory.call("pointer");
+ Object enumerable = vector.call("each");
+ Object result = enumerable.call("size");
+
+ ASSERT_EQUAL(3, detail::From_Ruby<int>().convert(result));
+}
+
+namespace
+{
+ std::vector<std::string*> vectorOfStringPointers()
+ {
+ std::vector<std::string*> result;
+ std::string* pString = new std::string("Hello");
+ result.push_back(pString);
+ return result;
+ }
+}
+
+TESTCASE(StringPointerVector)
+{
+ define_global_function("vector_of_string_pointers", &vectorOfStringPointers);
+
+ Module m(rb_mKernel);
+ Data_Object<std::vector<std::string*>> vec = m.call("vector_of_string_pointers");
+ ASSERT_EQUAL(1, vec->size());
+
+ std::string expected("Hello");
+ std::string* actual = (*vec)[0];
+ ASSERT_EQUAL(expected, *actual);
+}
+
+namespace
+{
+ class MyClass2
+ {
+ public:
+ MyClass2(std::string name): name(name)
+ {
+ }
+ std::string name;
+ };
+
+ std::vector<MyClass2*> vectorOfMyClass2Pointers()
+ {
+ std::vector<MyClass2*> result;
+ MyClass2* pMyClass = new MyClass2("Hello MyClass2");
+ result.push_back(pMyClass);
+ return result;
+ }
+}
+
+TESTCASE(MyClass2PointerVector)
+{
+ Class c = define_class<MyClass2>("MyClass2").
+ define_constructor(Constructor<MyClass2, std::string>()).
+ define_attr("name", &MyClass2::name, AttrAccess::Read);
+
+ define_global_function("vector_of_myclass2_pointers", &vectorOfMyClass2Pointers);
+
+ Module m(rb_mKernel);
+ Data_Object<std::vector<MyClass2*>> result = m.call("vector_of_myclass2_pointers");
+ ASSERT_EQUAL(1, result->size());
+
+ MyClass2* pMyClass = (*result)[0];
+ ASSERT_EQUAL("Hello MyClass2", pMyClass->name);
+}