From dec7ad9da111f230d33250e91f173906491fed67 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 25 May 2025 16:28:46 +0200 Subject: [PATCH] [consider merging] properly conveying string encoding for Ruby, so that UTF-8 encoding is maintained when returning such strings from C++ --- src/gsi/gsi_test/gsiTest.cc | 16 +++-- src/gsi/gsi_test/gsiTest.h | 11 ++++ src/pya/pya/pyaConvert.cc | 2 +- src/rba/rba/rbaConvert.cc | 16 ++++- src/rba/rba/rbaConvert.h | 6 +- src/rba/rba/rbaMarshal.cc | 2 +- src/tl/tl/tlInternational.cc | 7 ++- testdata/python/basic.py | 85 ++++++++++++++++--------- testdata/ruby/basic_testcore.rb | 108 +++++++++++++++++++------------- 9 files changed, 166 insertions(+), 87 deletions(-) diff --git a/src/gsi/gsi_test/gsiTest.cc b/src/gsi/gsi_test/gsiTest.cc index 29363acca..27ac72de1 100644 --- a/src/gsi/gsi_test/gsiTest.cc +++ b/src/gsi/gsi_test/gsiTest.cc @@ -218,7 +218,7 @@ A::ia_cref_to_qs (const std::vector &ia) { QString s; for (std::vector::const_iterator i = ia.begin (); i != ia.end (); ++i) { - s.push_back (char (*i)); + s.push_back (QChar (*i)); } return s; } @@ -229,7 +229,7 @@ A::ia_cref_to_qs_ref (const std::vector &ia) static QString s; s.clear (); for (std::vector::const_iterator i = ia.begin (); i != ia.end (); ++i) { - s.push_back (char (*i)); + s.push_back (QChar (*i)); } return s; } @@ -243,7 +243,7 @@ A::ql1s_cref_to_ia (const QLatin1String &ql1s) const char *cp = ql1s.data (); size_t n = ql1s.size (); for (size_t i = 0; i < n; ++i) { - ia.push_back (*cp++); + ia.push_back ((unsigned char) *cp++); } return ia; } @@ -1270,7 +1270,15 @@ static gsi::Class decl_a ("", "A", gsi::method ("to_s", &A::to_s) + gsi::iterator ("a6", &A::a6b, &A::a6e) + gsi::iterator ("a7", &A::a7b, &A::a7e) + - gsi::iterator ("a8", &A::a8b, &A::a8e) + gsi::iterator ("a8", &A::a8b, &A::a8e) + +#if defined(HAVE_QT) + gsi::method ("ft_qba", &A::ft_qba) + + gsi::method ("ft_qs", &A::ft_qs) + +#endif + gsi::method ("ft_str", &A::ft_str) + + gsi::method ("ft_cv", &A::ft_cv) + + gsi::method ("ft_cptr", &A::ft_cptr) + + gsi::method ("ft_var", &A::ft_var) ); static gsi::Class decl_a_nc (decl_a, "", "A_NC"); diff --git a/src/gsi/gsi_test/gsiTest.h b/src/gsi/gsi_test/gsiTest.h index c2b4bf58b..100d8dd2d 100644 --- a/src/gsi/gsi_test/gsiTest.h +++ b/src/gsi/gsi_test/gsiTest.h @@ -419,6 +419,17 @@ struct A static int sp_i_get (); static void sp_i_set (int v); + // feed-through values for full cycle tests + // (mainly for string encoding and binary strings) + static std::string ft_str (const std::string &v) { return v; } + static std::vector ft_cv (const std::vector &v) { return v; } + static const char *ft_cptr (const char *v) { return v; } + static tl::Variant ft_var (const tl::Variant &v) { return v; } +#if defined(HAVE_QT) + static QString ft_qs (const QString &v) { return v; } + static QByteArray ft_qba (const QByteArray &v) { return v; } +#endif + // members std::vector m_d; int n; diff --git a/src/pya/pya/pyaConvert.cc b/src/pya/pya/pyaConvert.cc index c7b7c6f64..44afc5917 100644 --- a/src/pya/pya/pyaConvert.cc +++ b/src/pya/pya/pyaConvert.cc @@ -501,7 +501,7 @@ PyObject *c2python_func::operator() (const tl::Variant &c) } else if (c.is_bool ()) { return c2python (c.to_bool ()); } else if (c.is_a_string ()) { - return c2python (c.to_string ()); + return c2python (c.to_stdstring ()); } else if (c.is_a_bytearray ()) { return c2python (c.to_bytearray ()); } else if (c.is_long ()) { diff --git a/src/rba/rba/rbaConvert.cc b/src/rba/rba/rbaConvert.cc index 61817a5a7..cd8aa5d0d 100644 --- a/src/rba/rba/rbaConvert.cc +++ b/src/rba/rba/rbaConvert.cc @@ -29,6 +29,8 @@ #include "gsiDecl.h" +#include + namespace rba { @@ -120,9 +122,17 @@ tl::Variant ruby2c (VALUE rval) } } else if (TYPE (rval) == T_STRING) { - return tl::Variant (ruby2c (rval)); + + // UTF-8 encoded strings are taken to be string, others are byte strings + // At least this ensures consistency for a full Ruby-C++ turnaround cycle. + if (rb_enc_from_index (rb_enc_get_index (rval)) == rb_utf8_encoding ()) { + return tl::Variant (ruby2c (rval)); + } else { + return tl::Variant (ruby2c > (rval)); + } + } else { - return tl::Variant (ruby2c (rba_safe_obj_as_string (rval))); + return tl::Variant (ruby2c (rba_safe_obj_as_string (rval))); } } @@ -261,7 +271,7 @@ VALUE c2ruby (const tl::Variant &c) } else if (c.is_bool ()) { return c2ruby (c.to_bool ()); } else if (c.is_a_string ()) { - return c2ruby (c.to_string ()); + return c2ruby (c.to_stdstring ()); } else if (c.is_a_bytearray ()) { return c2ruby > (c.to_bytearray ()); } else if (c.is_long () || c.is_char ()) { diff --git a/src/rba/rba/rbaConvert.h b/src/rba/rba/rbaConvert.h index 01533f843..6865dc7d2 100644 --- a/src/rba/rba/rbaConvert.h +++ b/src/rba/rba/rbaConvert.h @@ -461,7 +461,7 @@ inline VALUE c2ruby (const float &c) template <> inline VALUE c2ruby (const std::string &c) { - return rb_str_new (c.c_str (), long (c.size ())); + return rb_utf8_str_new (c.c_str (), long (c.size ())); } template <> @@ -488,7 +488,7 @@ inline VALUE c2ruby (const QString &qs) return Qnil; } else { std::string c (tl::to_string (qs)); - return rb_str_new (c.c_str (), long (c.size ())); + return rb_utf8_str_new (c.c_str (), long (c.size ())); } } #endif @@ -509,7 +509,7 @@ inline VALUE c2ruby (const char * const & s) static const char null_string[] = "(null)"; return rb_str_new (null_string, sizeof (null_string) - 1); } else { - return rb_str_new (s, long (strlen (s))); + return rb_utf8_str_new (s, long (strlen (s))); } } diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index b55f82111..29cf797c5 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -679,7 +679,7 @@ struct reader if (!a.get ()) { *ret = Qnil; } else { - *ret = rb_str_new (a->c_str (), long (a->size ())); + *ret = rb_utf8_str_new (a->c_str (), long (a->size ())); } } }; diff --git a/src/tl/tl/tlInternational.cc b/src/tl/tl/tlInternational.cc index 343a5ffa4..f9d4e60b8 100644 --- a/src/tl/tl/tlInternational.cc +++ b/src/tl/tl/tlInternational.cc @@ -45,12 +45,13 @@ QTextCodec *ms_system_codec = 0; QString to_qstring (const std::string &s) { - return QString::fromUtf8 (s.c_str ()); + return QString::fromUtf8 (s.c_str (), s.size ()); } std::string to_string (const QString &s) { - return std::string (s.toUtf8 ().constData ()); + auto utf8 = s.toUtf8 (); + return std::string (utf8.constData (), utf8.size ()); } #if !defined(_WIN32) @@ -70,7 +71,7 @@ std::string string_to_system (const std::string &s) initialize_codecs (); } - QString qs = QString::fromUtf8 (s.c_str ()); + QString qs = QString::fromUtf8 (s.c_str (), s.size ()); return std::string (ms_system_codec->fromUnicode (qs).constData ()); } #endif diff --git a/testdata/python/basic.py b/testdata/python/basic.py index a0b39a025..9f604f9d0 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -2994,8 +2994,12 @@ class BasicTest(unittest.TestCase): qba = pya.A.ia_cref_to_qba([ 16, 42, 0, 8 ]) if sys.version_info < (3, 0): self.assertEqual(repr(qba), "bytearray(b'\\x10*\\x00\\x08')") + self.assertEqual(repr(pya.A.ft_qba(qba)), "bytearray(b'\\x10*\\x00\\x08')") + self.assertEqual(repr(pya.A.ft_var(qba)), "bytearray(b'\\x10*\\x00\\x08')") else: self.assertEqual(repr(qba), "b'\\x10*\\x00\\x08'") + self.assertEqual(repr(pya.A.ft_qba(qba)), "b'\\x10*\\x00\\x08'") + self.assertEqual(repr(pya.A.ft_var(qba)), "b'\\x10*\\x00\\x08'") self.assertEqual(pya.A.qba_to_ia(qba), [ 16, 42, 0, 8 ]) self.assertEqual(pya.A.qba_cref_to_ia(qba), [ 16, 42, 0, 8 ]) @@ -3079,26 +3083,29 @@ class BasicTest(unittest.TestCase): if "ia_cref_to_qs" in pya.A.__dict__: - qs = pya.A.ia_cref_to_qs([ 16, 42, 0, 8 ]) - self.assertEqual(repr(qs), "'\\x10*\\x00\\x08'") + qs = pya.A.ia_cref_to_qs([ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(qs), "'\\x10*\\x00\\x08\u03a9'") + # full cycle must preserve encoding, also for var + self.assertEqual(repr(pya.A.ft_qs(qs)), "'\\x10*\\x00\\x08\u03a9'") + self.assertEqual(repr(pya.A.ft_var(qs)), "'\\x10*\\x00\\x08\u03a9'") - self.assertEqual(pya.A.qs_to_ia(qs), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.qs_cref_to_ia(qs), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.qs_cptr_to_ia(qs), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.qs_ref_to_ia(qs), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.qs_ptr_to_ia(qs), [ 16, 42, 0, 8 ]) + self.assertEqual(pya.A.qs_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(pya.A.qs_cref_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(pya.A.qs_cptr_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(pya.A.qs_ref_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(pya.A.qs_ptr_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) - qs = pya.A.ia_cref_to_qs_cref([ 17, 42, 0, 8 ]) - self.assertEqual(repr(qs), "'\\x11*\\x00\\x08'") + qs = pya.A.ia_cref_to_qs_cref([ 17, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(qs), "'\\x11*\\x00\\x08\u03a9'") - qs = pya.A.ia_cref_to_qs_ref([ 18, 42, 0, 8 ]) - self.assertEqual(repr(qs), "'\\x12*\\x00\\x08'") + qs = pya.A.ia_cref_to_qs_ref([ 18, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(qs), "'\\x12*\\x00\\x08\u03a9'") - qs = pya.A.ia_cref_to_qs_cptr([ 19, 42, 0, 8 ]) - self.assertEqual(repr(qs), "'\\x13*\\x00\\x08'") + qs = pya.A.ia_cref_to_qs_cptr([ 19, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(qs), "'\\x13*\\x00\\x08\u03a9'") - qs = pya.A.ia_cref_to_qs_ptr([ 20, 42, 0, 8 ]) - self.assertEqual(repr(qs), "'\\x14*\\x00\\x08'") + qs = pya.A.ia_cref_to_qs_ptr([ 20, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(qs), "'\\x14*\\x00\\x08\u03a9'") self.assertEqual(pya.A.qs_to_ia('\x00\x01\x02'), [ 0, 1, 2 ]) @@ -3137,29 +3144,42 @@ class BasicTest(unittest.TestCase): if "ia_cref_to_ql1s" in pya.A.__dict__: - ql1s = pya.A.ia_cref_to_ql1s([ 16, 42, 0, 8 ]) - self.assertEqual(repr(ql1s), "'\\x10*\\x00\\x08'") + ql1s = pya.A.ia_cref_to_ql1s([ 16, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(ql1s), "'\\x10*\\x00\\x08\u00a9'") - self.assertEqual(pya.A.ql1s_to_ia(ql1s), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.ql1s_cref_to_ia(ql1s), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.ql1s_cptr_to_ia(ql1s), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.ql1s_ref_to_ia(ql1s), [ 16, 42, 0, 8 ]) - self.assertEqual(pya.A.ql1s_ptr_to_ia(ql1s), [ 16, 42, 0, 8 ]) + self.assertEqual(pya.A.ql1s_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + self.assertEqual(pya.A.ql1s_cref_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + self.assertEqual(pya.A.ql1s_cptr_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + self.assertEqual(pya.A.ql1s_ref_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + self.assertEqual(pya.A.ql1s_ptr_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) - ql1s = pya.A.ia_cref_to_ql1s_cref([ 17, 42, 0, 8 ]) - self.assertEqual(repr(ql1s), "'\\x11*\\x00\\x08'") + ql1s = pya.A.ia_cref_to_ql1s_cref([ 17, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(ql1s), "'\\x11*\\x00\\x08\u00a9'") - ql1s = pya.A.ia_cref_to_ql1s_ref([ 18, 42, 0, 8 ]) - self.assertEqual(repr(ql1s), "'\\x12*\\x00\\x08'") + ql1s = pya.A.ia_cref_to_ql1s_ref([ 18, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(ql1s), "'\\x12*\\x00\\x08\u00a9'") - ql1s = pya.A.ia_cref_to_ql1s_cptr([ 19, 42, 0, 8 ]) - self.assertEqual(repr(ql1s), "'\\x13*\\x00\\x08'") + ql1s = pya.A.ia_cref_to_ql1s_cptr([ 19, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(ql1s), "'\\x13*\\x00\\x08\u00a9'") - ql1s = pya.A.ia_cref_to_ql1s_ptr([ 20, 42, 0, 8 ]) - self.assertEqual(repr(ql1s), "'\\x14*\\x00\\x08'") + ql1s = pya.A.ia_cref_to_ql1s_ptr([ 20, 42, 0, 8, 0x03a9 ]) + self.assertEqual(repr(ql1s), "'\\x14*\\x00\\x08\u00a9'") self.assertEqual(pya.A.ql1s_to_ia('\x00\x01\x02'), [ 0, 1, 2 ]) + def test_utf8Strings(self): + + # UTF8 strings (non-Qt) + s = "\u0010*\u0000\b\u03a9" + self.assertEqual(repr(s), "'\\x10*\\x00\\x08\u03a9'") + + # full cycle must preserve encoding, also for var + self.assertEqual(repr(pya.A.ft_str(s)), "'\\x10*\\x00\\x08\u03a9'") + self.assertEqual(repr(pya.A.ft_var(s)), "'\\x10*\\x00\\x08\u03a9'") + + # NUL character terminates in const char * mode: + self.assertEqual(repr(pya.A.ft_cptr(s)), "'\\x10*'") + def test_binaryStrings(self): # binary strings (non-Qt) @@ -3167,8 +3187,13 @@ class BasicTest(unittest.TestCase): ba = pya.A.ia_cref_to_ba([ 17, 42, 0, 8 ]) if sys.version_info < (3, 0): self.assertEqual(repr(ba), "bytearray(b'\\x11*\\x00\\x08')") + self.assertEqual(repr(pya.A.ft_cv(ba)), "bytearray(b'\\x11*\\x00\\x08')") + self.assertEqual(repr(pya.A.ft_var(ba)), "bytearray(b'\\x11*\\x00\\x08')") else: self.assertEqual(repr(ba), "b'\\x11*\\x00\\x08'") + self.assertEqual(repr(pya.A.ft_cv(ba)), "b'\\x11*\\x00\\x08'") + self.assertEqual(repr(pya.A.ft_var(ba)), "b'\\x11*\\x00\\x08'") + self.assertEqual(pya.A.ba_to_ia(ba), [ 17, 42, 0, 8 ]) self.assertEqual(pya.A.ba_cref_to_ia(ba), [ 17, 42, 0, 8 ]) self.assertEqual(pya.A.ba_cptr_to_ia(ba), [ 17, 42, 0, 8 ]) diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 72a8d1e02..ac734c3bc 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -2958,6 +2958,9 @@ class Basic_TestClass < TestBase qba = RBA::A::ia_cref_to_qba([ 16, 42, 0, 8 ]) assert_equal(qba.inspect, "\"\\x10*\\x00\\b\"") + # full cycle must preserve encoding, also for var + assert_equal(RBA::A::ft_qba(qba).inspect, "\"\\x10*\\x00\\b\"") + assert_equal(RBA::A::ft_var(qba).inspect, "\"\\x10*\\x00\\b\"") assert_equal(RBA::A::qba_to_ia(qba), [ 16, 42, 0, 8 ]) assert_equal(RBA::A::qba_cref_to_ia(qba), [ 16, 42, 0, 8 ]) @@ -3016,23 +3019,26 @@ class Basic_TestClass < TestBase if RBA::A.respond_to?(:ia_cref_to_qs) - qs = RBA::A::ia_cref_to_qs([ 16, 42, 0, 8 ]) - assert_equal(qs.inspect, "\"\\x10*\\x00\\b\"") + qs = RBA::A::ia_cref_to_qs([ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(qs.inspect, "\"\\u0010*\\u0000\\b\u03a9\"") + # full cycle must preserve encoding, also for var + assert_equal(RBA::A::ft_qs(qs).inspect, "\"\\u0010*\\u0000\\b\u03a9\"") + assert_equal(RBA::A::ft_var(qs).inspect, "\"\\u0010*\\u0000\\b\u03a9\"") - assert_equal(RBA::A::qs_to_ia(qs), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::qs_cref_to_ia(qs), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::qs_cptr_to_ia(qs), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::qs_ref_to_ia(qs), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::qs_ptr_to_ia(qs), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::qs_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(RBA::A::qs_cref_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(RBA::A::qs_cptr_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(RBA::A::qs_ref_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(RBA::A::qs_ptr_to_ia(qs), [ 16, 42, 0, 8, 0x03a9 ]) - qs = RBA::A::ia_cref_to_qs_cref([ 17, 42, 0, 8 ]) - assert_equal(qs.inspect, "\"\\x11*\\x00\\b\"") - qs = RBA::A::ia_cref_to_qs_ref([ 18, 42, 0, 8 ]) - assert_equal(qs.inspect, "\"\\x12*\\x00\\b\"") - qs = RBA::A::ia_cref_to_qs_cptr([ 19, 42, 0, 8 ]) - assert_equal(qs.inspect, "\"\\x13*\\x00\\b\"") - qs = RBA::A::ia_cref_to_qs_ptr([ 20, 42, 0, 8 ]) - assert_equal(qs.inspect, "\"\\x14*\\x00\\b\"") + qs = RBA::A::ia_cref_to_qs_cref([ 17, 42, 0, 8, 0x03a9 ]) + assert_equal(qs.inspect, "\"\\u0011*\\u0000\\b\u03a9\"") + qs = RBA::A::ia_cref_to_qs_ref([ 18, 42, 0, 8, 0x03a9 ]) + assert_equal(qs.inspect, "\"\\u0012*\\u0000\\b\u03a9\"") + qs = RBA::A::ia_cref_to_qs_cptr([ 19, 42, 0, 8, 0x03a9 ]) + assert_equal(qs.inspect, "\"\\u0013*\\u0000\\b\u03a9\"") + qs = RBA::A::ia_cref_to_qs_ptr([ 20, 42, 0, 8, 0x03a9 ]) + assert_equal(qs.inspect, "\"\\u0014*\\u0000\\b\u03a9\"") assert_equal(RBA::A::qs_to_ia("\x00\x01\x02"), [ 0, 1, 2 ]) @@ -3046,23 +3052,23 @@ class Basic_TestClass < TestBase if RBA::A.respond_to?(:ia_cref_to_ql1s) - ql1s = RBA::A::ia_cref_to_ql1s([ 16, 42, 0, 8 ]) - assert_equal(ql1s.inspect, "\"\\x10*\\x00\\b\"") + ql1s = RBA::A::ia_cref_to_ql1s([ 16, 42, 0, 8, 0x03a9 ]) + assert_equal(ql1s.inspect, "\"\\u0010*\\u0000\\b\u00a9\"") - assert_equal(RBA::A::ql1s_to_ia(ql1s), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::ql1s_cref_to_ia(ql1s), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::ql1s_cptr_to_ia(ql1s), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::ql1s_ref_to_ia(ql1s), [ 16, 42, 0, 8 ]) - assert_equal(RBA::A::ql1s_ptr_to_ia(ql1s), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::ql1s_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + assert_equal(RBA::A::ql1s_cref_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + assert_equal(RBA::A::ql1s_cptr_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + assert_equal(RBA::A::ql1s_ref_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) + assert_equal(RBA::A::ql1s_ptr_to_ia(ql1s), [ 16, 42, 0, 8, 0xa9 ]) - ql1s = RBA::A::ia_cref_to_ql1s_cref([ 17, 42, 0, 8 ]) - assert_equal(ql1s.inspect, "\"\\x11*\\x00\\b\"") - ql1s = RBA::A::ia_cref_to_ql1s_ref([ 18, 42, 0, 8 ]) - assert_equal(ql1s.inspect, "\"\\x12*\\x00\\b\"") - ql1s = RBA::A::ia_cref_to_ql1s_cptr([ 19, 42, 0, 8 ]) - assert_equal(ql1s.inspect, "\"\\x13*\\x00\\b\"") - ql1s = RBA::A::ia_cref_to_ql1s_ptr([ 20, 42, 0, 8 ]) - assert_equal(ql1s.inspect, "\"\\x14*\\x00\\b\"") + ql1s = RBA::A::ia_cref_to_ql1s_cref([ 17, 42, 0, 8, 0xa9 ]) + assert_equal(ql1s.inspect, "\"\\u0011*\\u0000\\b\u00a9\"") + ql1s = RBA::A::ia_cref_to_ql1s_ref([ 18, 42, 0, 8, 0xa9 ]) + assert_equal(ql1s.inspect, "\"\\u0012*\\u0000\\b\u00a9\"") + ql1s = RBA::A::ia_cref_to_ql1s_cptr([ 19, 42, 0, 8, 0xa9 ]) + assert_equal(ql1s.inspect, "\"\\u0013*\\u0000\\b\u00a9\"") + ql1s = RBA::A::ia_cref_to_ql1s_ptr([ 20, 42, 0, 8, 0xa9 ]) + assert_equal(ql1s.inspect, "\"\\u0014*\\u0000\\b\u00a9\"") assert_equal(RBA::A::ql1s_to_ia("\x00\x01\x02"), [ 0, 1, 2 ]) @@ -3077,7 +3083,7 @@ class Basic_TestClass < TestBase if RBA::A.respond_to?(:ia_cref_to_qsv) qsv = RBA::A::ia_cref_to_qsv([ 16, 42, 0, 8 ]) - assert_equal(qsv.inspect, "\"\\x10*\\x00\\b\"") + assert_equal(qsv.inspect, "\"\\u0010*\\u0000\\b\"") assert_equal(RBA::A::qsv_to_ia(qsv), [ 16, 42, 0, 8 ]) assert_equal(RBA::A::qsv_cref_to_ia(qsv), [ 16, 42, 0, 8 ]) @@ -3086,13 +3092,13 @@ class Basic_TestClass < TestBase assert_equal(RBA::A::qsv_ptr_to_ia(qsv), [ 16, 42, 0, 8 ]) qsv = RBA::A::ia_cref_to_qsv_cref([ 17, 42, 0, 8 ]) - assert_equal(qsv.inspect, "\"\\x11*\\x00\\b\"") + assert_equal(qsv.inspect, "\"\\u0011*\\u0000\\b\"") qsv = RBA::A::ia_cref_to_qsv_ref([ 18, 42, 0, 8 ]) - assert_equal(qsv.inspect, "\"\\x12*\\x00\\b\"") + assert_equal(qsv.inspect, "\"\\u0012*\\u0000\\b\"") qsv = RBA::A::ia_cref_to_qsv_cptr([ 19, 42, 0, 8 ]) - assert_equal(qsv.inspect, "\"\\x13*\\x00\\b\"") + assert_equal(qsv.inspect, "\"\\u0013*\\u0000\\b\"") qsv = RBA::A::ia_cref_to_qsv_ptr([ 20, 42, 0, 8 ]) - assert_equal(qsv.inspect, "\"\\x14*\\x00\\b\"") + assert_equal(qsv.inspect, "\"\\u0014*\\u0000\\b\"") assert_equal(RBA::A::qsv_to_ia("\x00\x01\x02"), [ 0, 1, 2 ]) @@ -3100,18 +3106,36 @@ class Basic_TestClass < TestBase end + def test_utf8Strings + + # UTF8 strings (non-Qt) + s = "\u0010*\u0000\b\u03a9" + assert_equal(s.inspect, "\"\\u0010*\\u0000\\b\u03a9\"") + + # full cycle must preserve encoding, also for var + assert_equal(RBA::A::ft_str(s).inspect, "\"\\u0010*\\u0000\\b\u03a9\"") + assert_equal(RBA::A::ft_var(s).inspect, "\"\\u0010*\\u0000\\b\u03a9\"") + + # NUL character terminates in const char * mode: + assert_equal(RBA::A::ft_cptr(s).inspect, "\"\\u0010*\"") + + end + def test_binaryStrings # binary strings (non-Qt) - ba = RBA::A::ia_cref_to_ba([ 16, 42, 1, 8 ]) - assert_equal(ba.inspect, "\"\\x10*\\x01\\b\"") + ba = RBA::A::ia_cref_to_ba([ 16, 42, 0, 8 ]) + assert_equal(ba.inspect, "\"\\x10*\\x00\\b\"") + # full cycle must preserve encoding, also for var + assert_equal(RBA::A::ft_cv(ba).inspect, "\"\\x10*\\x00\\b\"") + assert_equal(RBA::A::ft_var(ba).inspect, "\"\\x10*\\x00\\b\"") - assert_equal(RBA::A::ba_to_ia(ba), [ 16, 42, 1, 8 ]) - assert_equal(RBA::A::ba_cref_to_ia(ba), [ 16, 42, 1, 8 ]) - assert_equal(RBA::A::ba_cptr_to_ia(ba), [ 16, 42, 1, 8 ]) - assert_equal(RBA::A::ba_ref_to_ia(ba), [ 16, 42, 1, 8 ]) - assert_equal(RBA::A::ba_ptr_to_ia(ba), [ 16, 42, 1, 8 ]) + assert_equal(RBA::A::ba_to_ia(ba), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::ba_cref_to_ia(ba), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::ba_cptr_to_ia(ba), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::ba_ref_to_ia(ba), [ 16, 42, 0, 8 ]) + assert_equal(RBA::A::ba_ptr_to_ia(ba), [ 16, 42, 0, 8 ]) ba = RBA::A::ia_cref_to_ba_cref([ 17, 42, 0, 8 ]) assert_equal(ba.inspect, "\"\\x11*\\x00\\b\"")