[Kde-bindings] QtRuby: Qt::Variant#value fails for ushort and QChar variants

Richard Dale richard.dale at telefonica.net
Wed Apr 11 12:40:48 UTC 2012


On Wednesday, April 11, 2012 03:11:33 AM Yaohan Chen wrote:
> Hello,
> 
> I'm getting a segfault when calling Qt::Variant#value for QVariant<ushort>,
> and NoMethodError for QVariant<QChar>. I've included test cases that show
> the failures as well as workaround using String#unpack below. They require
> RSpec, RubyInline and of course QtRuby to run. Could anyone confirm if you
> have the same problem?
> 
> Thanks,
> 
> Yaohan Chen
> 
> 
> #!/usr/bin/env rspec
> 
> require 'Qt'
> require 'inline'
> 
> # These tests demonstrate that when you get a Qt::Variant by unserializing a
> serialized # QVariant via QDataStream, the value method fails if the
> variant's type is QChar or ushort. describe 'Qt::Variant#value' do
>   it 'returns the value of an int variant' do
>     variant = unserialize_variant SerializedVariant.of_int(15)
>     # This one works for me
>     variant.value.should == 15
>   end
> 
>   it 'returns the value of a QChar variant' do
>     variant = unserialize_variant SerializedVariant.of_QChar(10)
>     # This fails for me saying the QVariant does not have method toChar
> defined variant.value.should == 10
>   end
> 
>   it 'returns the value of a ushort variant' do
>     variant = unserialize_variant SerializedVariant.of_ushort(5)
> 
>     # pending 'causes segfault'
> 
>     # This causes Ruby to segfault for me. If it happens for you too,
> uncomment the pending # line above so RSpec can report the results of other
> examples. variant.value.should == 5
>   end
> end
> 
> # These extract Ruby values directly from serialized variants without Qt, to
> show that the # correct data is passed from C++ to Ruby. They use
> String#unpack and skip the first # 5 bytes ('@5') which are QVariant's type
> information and "null flag". See #
> https://qt-project.org/doc/qt-4.8/datastreamformat.html
> describe 'Workaround using String#unpack' do
>   it 'returns the value of an int variant' do
>     string = SerializedVariant.of_int(15);
>     # l> for big-endian 32bit signed integer
>     string.unpack('@5l>').first.should == 15
>   end
> 
>   it 'returns the value of a QChar variant' do
>     string = SerializedVariant.of_QChar(10);
>     # s> for big-endian 16bit signed integer (QChar stores a UTF-16
> character) string.unpack('@5s>').first.should == 10
>   end
> 
>   it 'returns the value of a ushort variant' do
>     string = SerializedVariant.of_ushort(5);
>     # S> for big-endian 16bit unsigned integer
>     string.unpack('@5S>').first.should == 5
>   end
> end
> 
> # Given string containing serialization of a variant, return the variant
> def unserialize_variant(string)
>   byte_array = Qt::ByteArray.new string
>   data_stream = Qt::DataStream.new byte_array
>   variant = Qt::Variant.new
>   data_stream >> variant
>   variant
> end
> 
> # This module contains functions that return serialization of several
> variant types module SerializedVariant
>   inline :C do |builder|
>     builder.add_compile_flags %w[-x c++]
>     builder.include '<QtCore/QByteArray>'
>     builder.include '<QtCore/QDataStream>'
>     builder.include '<QtCore/QVariant>'
>     builder.add_link_flags %w[-lQtCore]
> 
>     builder.prefix <<-CODE
>       // Return serialization of the given QVariant
>       VALUE serialize(QVariant variant) {
>         QByteArray byte_array;
>         QDataStream data_stream(&byte_array, QIODevice::WriteOnly);
>         data_stream << variant;
>         return rb_str_new(byte_array.data(), byte_array.size());
>       }
>     CODE
> 
>     # :expand_types => true makes RubyInline insert VALUE self and figure
> arity automatically builder.c_raw_singleton <<-CODE, :expand_types => true
>       // Return serialization of a QVariant containing the given int
>       VALUE of_int(VALUE v) {
>         QVariant variant = QVariant::fromValue<int>(FIX2INT(v));
>         return serialize(variant);
>       }
>     CODE
> 
>     builder.c_raw_singleton <<-CODE, :expand_types => true
>       // Return serialization of a QVariant containing the given QChar
>       VALUE of_QChar(VALUE v) {
>         QVariant variant = QVariant::fromValue<QChar>(FIX2INT(v));
>         return serialize(variant);
>       }
>     CODE
> 
>     builder.c_raw_singleton <<-CODE, :expand_types => true
>       // Return serialization of a QVariant containing the given ushort
>       VALUE of_ushort(VALUE v) {
>         QVariant variant = QVariant::fromValue<ushort>(FIX2INT(v));
>         return serialize(variant);
>       }
>     CODE
>   end
> end

Thanks for the bug report and the very interesting test program. I installed 
RubyInline to get it working and I'm really impressed how you can combine C 
code and ruby in the same source. QtRuby has never really had any test code 
and I think for the next version 3.0 it would be nice to do some tests using 
RSpec/RubyInline like you've done.

I've fixed the bug in Qt::Variant#value in the master branch. I needed to 
change the QChar comparison to:

  it 'returns the value of a QChar variant' do
    variant = unserialize_variant SerializedVariant.of_QChar(10)
    # This fails for me saying the QVariant does not have method toChar defined
    variant.value.should == Qt::Char.new(10)
  end

The three workround tests don't work for me though and they still fail, and I 
don't know if that is a problem with QtRuby or the test code.

-- Richard
-- Richard





More information about the Kde-bindings mailing list