Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rubygem-ruby-dbus for openSUSE:Factory checked in at 2022-04-30 00:44:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-ruby-dbus (Old) and /work/SRC/openSUSE:Factory/.rubygem-ruby-dbus.new.1538 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-ruby-dbus" Sat Apr 30 00:44:35 2022 rev:27 rq:973057 version:0.18.0.beta5 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-ruby-dbus/rubygem-ruby-dbus.changes 2022-04-23 00:25:26.327755453 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-ruby-dbus.new.1538/rubygem-ruby-dbus.changes 2022-04-30 00:44:55.414919439 +0200 @@ -1,0 +2,18 @@ +Wed Apr 27 08:29:35 UTC 2022 - Martin Vidner <mvid...@suse.com> + +- 0.18.0.beta5 + API + * DBus::Type instances are frozen. + * Data::Container classes (Array, Struct, DictEntry, but not Variant) + constructors (#initialize, .from_items, .from_typed) changed to have + a *type* argument instead of *member_type* or *member_types*. + * Added type factories + * Type::Array[type] + * Type::Hash[key_type, value_type] + * Type::Struct[type1, type2...] + + Bug fixes: + * Properties containing Variants would return them doubly wrapped + (gh#mvidner/ruby-dbus#111). + +------------------------------------------------------------------- Old: ---- ruby-dbus-0.18.0.beta4.gem New: ---- ruby-dbus-0.18.0.beta5.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-ruby-dbus.spec ++++++ --- /var/tmp/diff_new_pack.1MXlrp/_old 2022-04-30 00:44:56.002919949 +0200 +++ /var/tmp/diff_new_pack.1MXlrp/_new 2022-04-30 00:44:56.010919956 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-ruby-dbus -Version: 0.18.0.beta4 +Version: 0.18.0.beta5 Release: 0 %define mod_name ruby-dbus %define mod_full_name %{mod_name}-%{version} ++++++ ruby-dbus-0.18.0.beta4.gem -> ruby-dbus-0.18.0.beta5.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/NEWS.md new/NEWS.md --- old/NEWS.md 2022-04-21 13:44:41.000000000 +0200 +++ new/NEWS.md 2022-04-27 10:47:47.000000000 +0200 @@ -2,6 +2,23 @@ ## Unreleased +## Ruby D-Bus 0.18.0.beta5 - 2022-04-27 + +API: + * DBus::Type instances are frozen. + * Data::Container classes (Array, Struct, DictEntry, but not Variant) + constructors (#initialize, .from_items, .from_typed) changed to have + a *type* argument instead of *member_type* or *member_types*. + * Added type factories + * Type::Array[type] + * Type::Hash[key_type, value_type] + * Type::Struct[type1, type2...] + +Bug fixes: + * Properties containing Variants would return them doubly wrapped ([#111][]). + +[#111]: https://github.com/mvidner/ruby-dbus/pull/111 + ## Ruby D-Bus 0.18.0.beta4 - 2022-04-21 Bug fixes: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/VERSION new/VERSION --- old/VERSION 2022-04-21 13:44:41.000000000 +0200 +++ new/VERSION 2022-04-27 10:47:47.000000000 +0200 @@ -1 +1 @@ -0.18.0.beta4 +0.18.0.beta5 Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dbus/data.rb new/lib/dbus/data.rb --- old/lib/dbus/data.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/lib/dbus/data.rb 2022-04-27 10:47:47.000000000 +0200 @@ -43,7 +43,7 @@ data_class = Data::BY_TYPE_CODE[type.sigtype] # not nil because DBus.type validates - data_class.from_typed(value, member_types: type.members) + data_class.from_typed(value, type: type) end module_function :make_typed @@ -67,6 +67,15 @@ # for the specific see {Variant#member_type} # @return [Type] the exact type of this value + # @!method self.from_typed(value, type:) + # @param value [::Object] + # @param type [Type] + # @return [Base] + # @api private + # Use {Data.make_typed} instead. + # Construct an instance of the specific subclass, with a type further + # specified in the *type* argument. + # Child classes must validate *value*. def initialize(value) @value = value @@ -83,6 +92,11 @@ # Hash key equality # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F alias eql? == + + # @param type [Type] + def self.assert_type_matches_class(type) + raise ArgumentError unless type.sigtype == type_code + end end # A value that is not a {Container}. @@ -103,10 +117,10 @@ end # @param value [::Object] - # @param member_types [::Array<Type>] (ignored, will be empty) + # @param type [Type] # @return [Basic] - def self.from_typed(value, member_types:) # rubocop:disable Lint/UnusedMethodArgument - # assert member_types.empty? + def self.from_typed(value, type:) + assert_type_matches_class(type) new(value) end end @@ -132,34 +146,6 @@ end end - # {DBus::Data::String}, {DBus::Data::ObjectPath}, or {DBus::Data::Signature}. - class StringLike < Basic - def self.fixed? - false - end - - def initialize(value) - if value.is_a?(self.class) - value = value.value - else - self.class.validate_raw!(value) - end - - super(value) - end - end - - # Contains one or more other values. - class Container < Base - def self.basic? - false - end - - def self.fixed? - false - end - end - # Format strings for String#unpack, both little- and big-endian. Format = ::Struct.new(:little, :big) @@ -398,6 +384,23 @@ end end + # {DBus::Data::String}, {DBus::Data::ObjectPath}, or {DBus::Data::Signature}. + class StringLike < Basic + def self.fixed? + false + end + + def initialize(value) + if value.is_a?(self.class) + value = value.value + else + self.class.validate_raw!(value) + end + + super(value) + end + end + # UTF-8 encoded string. class String < StringLike def self.type_code @@ -494,6 +497,21 @@ end end + # Contains one or more other values. + class Container < Base + def self.basic? + false + end + + def self.fixed? + false + end + + # For containers, the type varies among instances + # @see Base#type + attr_reader :type + end + # An Array, or a Dictionary (Hash). class Array < Container def self.type_code @@ -504,44 +522,32 @@ 4 end - # @return [Type] - attr_reader :member_type - - def type - return @type if @type - - # TODO: reconstructing the type is cumbersome; have #initialize take *type* instead? - # TODO: or rather add Type::Array[t] - @type = Type.new("a") - @type << member_type - @type - end - # TODO: check that Hash keys are basic types # @param mode [:plain,:exact] - # @param member_type [Type] + # @param type [Type] # @param hash [Boolean] are we unmarshalling an ARRAY of DICT_ENTRY # @return [Data::Array] - def self.from_items(value, mode:, member_type:, hash: false) + def self.from_items(value, mode:, type:, hash: false) value = Hash[value] if hash return value if mode == :plain - new(value, member_type: member_type) + new(value, type: type) end # @param value [::Object] - # @param member_types [::Array<Type>] + # @param type [Type] # @return [Data::Array] - def self.from_typed(value, member_types:) + def self.from_typed(value, type:) + assert_type_matches_class(type) # TODO: validation - member_type = member_types.first + member_type = type.child # TODO: Dict?? items = value.map do |i| Data.make_typed(member_type, i) end - new(items, member_type: member_type) # initialize(::Array<Data::Base>) + new(items, type: type) # initialize(::Array<Data::Base>) end # FIXME: should Data::Array be mutable? @@ -550,12 +556,12 @@ # TODO: specify type or guess type? # Data is the exact type, so its constructor should be exact # and guesswork should be clearly labeled - # @param member_type [SingleCompleteType,Type] - def initialize(value, member_type:) - member_type = DBus.type(member_type) unless member_type.is_a?(Type) + # @param type [SingleCompleteType,Type] + def initialize(value, type:) + type = DBus.type(type) unless type.is_a?(Type) + self.class.assert_type_matches_class(type) + @type = type # TODO: copy from another Data::Array - @member_type = member_type - @type = nil super(value) end end @@ -572,46 +578,32 @@ 8 end - # @return [::Array<Type>] - attr_reader :member_types - - def type - return @type if @type - - # TODO: reconstructing the type is cumbersome; have #initialize take *type* instead? - # TODO: or rather add Type::Struct[t1, t2, ...] - @type = Type.new(self.class.type_code, abstract: true) - @member_types.each do |member_type| - @type << member_type - end - @type - end - # @param value [::Array] - def self.from_items(value, mode:, member_types:) + def self.from_items(value, mode:, type:) value.freeze return value if mode == :plain - new(value, member_types: member_types) + new(value, type: type) end # @param value [::Object] (#size, #each) - # @param member_types [::Array<Type>] + # @param type [Type] # @return [Struct] - def self.from_typed(value, member_types:) + def self.from_typed(value, type:) # TODO: validation + member_types = type.members raise unless value.size == member_types.size items = member_types.zip(value).map do |item_type, item| Data.make_typed(item_type, item) end - new(items, member_types: member_types) # initialize(::Array<Data::Base>) + new(items, type: type) # initialize(::Array<Data::Base>) end - def initialize(value, member_types:) - @member_types = member_types - @type = nil + def initialize(value, type:) + self.class.assert_type_matches_class(type) + @type = type super(value) end end @@ -634,10 +626,10 @@ end # @param value [::Object] - # @param member_types [::Array<Type>] + # @param type [Type] # @return [Variant] - def self.from_typed(value, member_types:) # rubocop:disable Lint/UnusedMethodArgument - # assert member_types.empty? + def self.from_typed(value, type:) + assert_type_matches_class(type) # decide on type of value new(value, member_type: nil) @@ -690,31 +682,19 @@ 8 end - # @return [::Array<Type>] - attr_reader :member_types - - def type - return @type if @type - - # TODO: reconstructing the type is cumbersome; have #initialize take *type* instead? - @type = Type.new(self.class.type_code, abstract: true) - @member_types.each do |member_type| - @type << member_type - end - @type - end - # @param value [::Array] - def self.from_items(value, mode:, member_types:) # rubocop:disable Lint/UnusedMethodArgument + def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument value.freeze # DictEntry ignores the :exact mode value end # @param value [::Object] (#size, #each) - # @param member_types [::Array<Type>] + # @param type [Type] # @return [DictEntry] - def self.from_typed(value, member_types:) + def self.from_typed(value, type:) + assert_type_matches_class(type) + member_types = type.members # assert member_types.size == 2 # TODO: duplicated from Struct. Inherit/delegate? # TODO: validation @@ -724,12 +704,12 @@ Data.make_typed(item_type, item) end - new(items, member_types: member_types) # initialize(::Array<Data::Base>) + new(items, type: type) # initialize(::Array<Data::Base>) end - def initialize(value, member_types:) - @member_types = member_types - @type = nil + def initialize(value, type:) + self.class.assert_type_matches_class(type) + @type = type super(value) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dbus/marshall.rb new/lib/dbus/marshall.rb --- old/lib/dbus/marshall.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/lib/dbus/marshall.rb 2022-04-27 10:47:47.000000000 +0200 @@ -118,7 +118,7 @@ values = signature.members.map do |child_sig| do_parse(child_sig, mode: mode) end - packet = data_class.from_items(values, mode: mode, member_types: signature.members) + packet = data_class.from_items(values, mode: mode, type: signature) when Type::VARIANT data_sig = do_parse(Data::Signature.type, mode: :exact) # -> Data::Signature @@ -147,7 +147,7 @@ items << item end is_hash = signature.child.sigtype == Type::DICT_ENTRY - packet = data_class.from_items(items, mode: mode, member_type: signature.child, hash: is_hash) + packet = data_class.from_items(items, mode: mode, type: signature, hash: is_hash) end end packet @@ -282,8 +282,11 @@ def append_variant(val) vartype = nil - if val.is_a?(DBus::Data::Base) - vartype = val.type # FIXME: box or unbox another variant? + if val.is_a?(DBus::Data::Variant) + vartype = val.member_type + vardata = val.value + elsif val.is_a?(DBus::Data::Base) + vartype = val.type vardata = val.value elsif val.is_a?(Array) && val.size == 2 case val[0] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/dbus/type.rb new/lib/dbus/type.rb --- old/lib/dbus/type.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/lib/dbus/type.rb 2022-04-27 10:47:47.000000000 +0200 @@ -29,14 +29,12 @@ # For documentation purposes only. class Prototype < String; end - # = D-Bus type module - # - # This module containts the constants of the types specified in the D-Bus - # protocol. + # Represents the D-Bus types. # # Corresponds to {SingleCompleteType}. + # Instances are immutable/frozen once fully constructed. # - # See also {DBus::Data::Signature} + # See also {DBus::Data::Signature} which is "type on the wire". class Type # Mapping from type number to name and alignment. TYPE_MAPPING = { @@ -104,8 +102,9 @@ end end - @sigtype = sigtype - @members = [] + @sigtype = sigtype.freeze + @members = [] # not frozen yet, Parser#parse_one or Factory will do it + freeze end # Return the required alignment for the type. @@ -124,16 +123,15 @@ when DICT_ENTRY "{#{@members.collect(&:to_s).join}}" else - if !TYPE_MAPPING.keys.member?(@sigtype) - raise NotImplementedError - end - @sigtype.chr end end # Add a new member type _item_. + # @param item [Type] def <<(item) + raise ArgumentError unless item.is_a?(Type) + if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype) raise SignatureException end @@ -232,6 +230,7 @@ else res = Type.new(char) end + res.members.freeze res end @@ -243,7 +242,7 @@ while (c = nextchar) ret << parse_one(c) end - ret + ret.freeze end # Parse one {SingleCompleteType} @@ -255,9 +254,116 @@ t = parse_one(c) raise SignatureException, "Has more than a Single Complete Type: #{@signature}" unless nextchar.nil? + t.freeze + end + end + + class Factory + # @param type [Type,SingleCompleteType,Class] + # @see from_plain_class + # @return [Type] (frozen) + def self.make_type(type) + case type + when Type + type + when String + DBus.type(type) + when Class + from_plain_class(type) + else + msg = "Expecting DBus::Type, DBus::SingleCompleteType(aka ::String), or Class, got #{type.inspect}" + raise ArgumentError, msg + end + end + + # Make a {Type} corresponding to some plain classes: + # - String + # - Float + # - DBus::ObjectPath + # - DBus::Signature, DBus::SingleCompleteType + # @param klass [Class] + # @return [Type] (frozen) + def self.from_plain_class(klass) + @signature_type ||= DBus.type(SIGNATURE) + @class_to_type ||= { + DBus::ObjectPath => DBus.type(OBJECT_PATH), + DBus::Signature => @signature_type, + DBus::SingleCompleteType => @signature_type, + String => DBus.type(STRING), + Float => DBus.type(DOUBLE) + } + t = @class_to_type[klass] + raise ArgumentError, "Cannot convert plain class #{klass} to a D-Bus type" if t.nil? + + t + end + end + + # Syntactic helper for constructing an array Type. + # You may be looking for {Data::Array} instead. + # @example + # t = Type::Array[Type::INT16] + class ArrayFactory < Factory + # @param member_type [Type,SingleCompleteType] + # @return [Type] (frozen) + def self.[](member_type) + t = Type.new(ARRAY) + t << make_type(member_type) + t.members.freeze + t + end + end + + # @example + # t = Type::Array[Type::INT16] + Array = ArrayFactory + + # Syntactic helper for constructing a hash Type. + # You may be looking for {Data::Array} and {Data::DictEntry} instead. + # @example + # t = Type::Hash[Type::STRING, Type::VARIANT] + class HashFactory < Factory + # @param key_type [Type,SingleCompleteType] + # @param value_type [Type,SingleCompleteType] + # @return [Type] (frozen) + def self.[](key_type, value_type) + t = Type.new(ARRAY) + de = Type.new(DICT_ENTRY, abstract: true) + de << make_type(key_type) + de << make_type(value_type) + de.members.freeze + t << de + t.members.freeze t end end + + # @example + # t = Type::Hash[Type::INT16] + Hash = HashFactory + + # Syntactic helper for constructing a struct Type. + # You may be looking for {Data::Struct} instead. + # @example + # t = Type::Struct[Type::INT16, Type::STRING] + class StructFactory < Factory + # @param member_types [::Array<Type,SingleCompleteType>] + # @return [Type] (frozen) + def self.[](*member_types) + raise ArgumentError if member_types.empty? + + t = Type.new(STRUCT, abstract: true) + member_types.each do |mt| + t << make_type(mt) + end + t.members.freeze + t + end + end + + # @example + # t = Type::Struct[Type::INT16, Type::STRING] + Struct = StructFactory end # shortcuts @@ -266,7 +372,7 @@ # This is prefered to {Type#initialize} which allows # incomplete or invalid types. # @param string_type [SingleCompleteType] - # @return [DBus::Type] + # @return [DBus::Type] (frozen) # @raise SignatureException def type(string_type) Type::Parser.new(string_type).parse1 @@ -275,7 +381,7 @@ # Parse a String to zero or more {DBus::Type}s. # @param string_type [Signature] - # @return [Array<DBus::Type>] + # @return [Array<DBus::Type>] (frozen) # @raise SignatureException def types(string_type) Type::Parser.new(string_type).parse diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2022-04-21 13:44:41.000000000 +0200 +++ new/metadata 2022-04-27 10:47:47.000000000 +0200 @@ -1,14 +1,14 @@ --- !ruby/object:Gem::Specification name: ruby-dbus version: !ruby/object:Gem::Version - version: 0.18.0.beta4 + version: 0.18.0.beta5 platform: ruby authors: - Ruby DBus Team autorequire: bindir: bin cert_chain: [] -date: 2022-04-21 00:00:00.000000000 Z +date: 2022-04-27 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rexml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/data_spec.rb new/spec/data_spec.rb --- old/spec/data_spec.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/spec/data_spec.rb 2022-04-27 10:47:47.000000000 +0200 @@ -85,6 +85,8 @@ # TODO: Look at conversions? to_str, to_int? describe DBus::Data do + T = DBus::Type unless const_defined? "T" + # test initialization, from user code, or from packet (from_raw) # remember to unpack if initializing from Data::Base # #value should recurse inside so that the user doesnt have to @@ -245,18 +247,18 @@ describe "containers" do describe DBus::Data::Array do good = [ - # [[1, 2, 3], member_type: nil], - [[1, 2, 3], { member_type: "q" }], - [[1, 2, 3], { member_type: DBus::Type::UINT16 }], - [[1, 2, 3], { member_type: DBus.type("q") }], - [[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], { member_type: "q" }] + # [[1, 2, 3], type: nil], + [[1, 2, 3], { type: "aq" }], + [[1, 2, 3], { type: T::Array[T::UINT16] }], + [[1, 2, 3], { type: T::Array["q"] }], + [[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], { type: T::Array["q"] }] # TODO: others ] bad = [ # undesirable type guessing - ## [[1, 2, 3], { member_type: nil }, DBus::InvalidPacketException, "Unknown type code"], - ## [[1, 2, 3], { member_type: "!" }, DBus::InvalidPacketException, "Unknown type code"] + ## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"], + ## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"] # TODO: others ] @@ -265,8 +267,8 @@ describe ".from_typed" do it "creates new instance from given object and type" do - type = DBus::Type.new("s") - expect(described_class.from_typed(["test", "lest"], member_types: [type])).to be_a(described_class) + type = T::Array[String] + expect(described_class.from_typed(["test", "lest"], type: type)).to be_a(described_class) end end end @@ -274,7 +276,7 @@ describe DBus::Data::Struct do three_words = ::Struct.new(:a, :b, :c) - qqq = ["q", "q", "q"] + qqq = T::Struct[T::UINT16, T::UINT16, T::UINT16] integers = [1, 2, 3] uints = [DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)] @@ -291,28 +293,25 @@ # TODO: also check data ownership: reasonable to own the data? # can make it explicit? good = [ - # from plain array; various m_t styles - [integers, { member_types: ["q", "q", "q"] }], - [integers, { member_types: [DBus::Type::UINT16, DBus::Type::UINT16, DBus::Type::UINT16] }], - [integers, { member_types: DBus.types("qqq") }], + # from plain array; various *type* styles + [integers, { type: DBus.type("(qqq)") }], + [integers, { type: T::Struct["q", "q", "q"] }], + [integers, { type: T::Struct[T::UINT16, T::UINT16, T::UINT16] }], + [integers, { type: T::Struct[*DBus.types("qqq")] }], # plain array of data - [uints, { member_types: DBus.types("qqq") }], + [uints, { type: qqq }], # ::Struct - [three_words.new(*integers), { member_types: qqq }], - [three_words.new(*uints), { member_types: qqq }] + [three_words.new(*integers), { type: qqq }], + [three_words.new(*uints), { type: qqq }] # TODO: others ] + # check these only when canonicalizing @value, because that will + # type-check the value deeply _bad_but_valid = [ - # Wrong member_types arg: - # hmm this is another reason to pass the type - # as the entire struct type, not the members: - # empty struct will be caught naturally - [integers, { member_types: [] }, ArgumentError, "???"], - [integers, { member_types: ["!"] }, DBus::InvalidPacketException, "Unknown type code"], # STRUCT specific: member count mismatch - [[1, 2], { member_types: DBus.types("qqq") }, ArgumentError, "???"], - [[1, 2, 3, 4], { member_types: DBus.types("qqq") }, ArgumentError, "???"] + [[1, 2], { type: qqq }, ArgumentError, "???"], + [[1, 2, 3, 4], { type: qqq }, ArgumentError, "???"] # TODO: others ] @@ -321,8 +320,8 @@ describe ".from_typed" do it "creates new instance from given object and type" do - type = DBus::Type.new("s") - expect(described_class.from_typed(["test", "lest"].freeze, member_types: [type, type])) + type = T::Struct[T::STRING, T::STRING] + expect(described_class.from_typed(["test", "lest"].freeze, type: type)) .to be_a(described_class) end end @@ -331,16 +330,9 @@ describe DBus::Data::Variant do describe ".from_typed" do it "creates new instance from given object and type" do - type = DBus::Type.new("s") - expect(described_class.from_typed("test", member_types: [type])).to be_a(described_class) - end - - it "ignores the member_types argument" do - type = DBus::Type.new("s") - # Base.from_typed is a generic interface with a fixed signature; - # So it must offer the member_types parameter, which is misleading - # for a Variant - value = described_class.from_typed("test", member_types: [type]) + type = DBus.type(T::VARIANT) + value = described_class.from_typed("test", type: type) + expect(value).to be_a(described_class) expect(value.type.to_s).to eq "v" expect(value.member_type.to_s).to eq "s" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/property_spec.rb new/spec/property_spec.rb --- old/spec/property_spec.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/spec/property_spec.rb 2022-04-27 10:47:47.000000000 +0200 @@ -163,7 +163,7 @@ end end - context "an dict-typed property" do + context "a dict-typed property" do it "gets read as a hash" do val = @iface["MyDict"] expect(val).to eq({ @@ -172,6 +172,23 @@ "three" => [3, 3, 3] }) end + + it "Get returns the correctly typed value (check with dbus-send)" do + cmd = "dbus-send --print-reply " \ + "--dest=org.ruby.service " \ + "/org/ruby/MyInstance " \ + "org.freedesktop.DBus.Properties.Get " \ + "string:org.ruby.SampleInterface " \ + "string:MyDict" + reply = `#{cmd}` + # a bug about variant nesting lead to a "variant variant int32 1" value + match_rx = /variant \s+ array \s \[ \s+ + dict \s entry\( \s+ + string \s "one" \s+ + variant \s+ int32 \s 1 \s+ + \)/x + expect(reply).to match(match_rx) + end end context "a variant-typed property" do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/type_spec.rb new/spec/type_spec.rb --- old/spec/type_spec.rb 2022-04-21 13:44:41.000000000 +0200 +++ new/spec/type_spec.rb 2022-04-27 10:47:47.000000000 +0200 @@ -45,6 +45,7 @@ ["a{vs}", "DICT_ENTRY key must be basic (non-container)"], ["{sv}", "DICT_ENTRY not an immediate child of an ARRAY"], ["a({sv})", "DICT_ENTRY not an immediate child of an ARRAY"], + ["a{s", "DICT_ENTRY not closed"], ["a{sv", "DICT_ENTRY not closed"], ["}", "DICT_ENTRY unexpectedly closed"], @@ -78,5 +79,109 @@ end end end + end + + describe DBus::Type do + describe "#<<" do + it "raises if the argument is not a Type" do + t = DBus::Type.new(DBus::Type::ARRAY) + expect { t << "s" }.to raise_error(ArgumentError) + end + + # TODO: the following raise checks do not occur in practice, as there are + # parallel checks in the parses. The code could be simplified? + it "raises if adding too much to an array" do + t = DBus::Type.new(DBus::Type::ARRAY) + b = DBus::Type.new(DBus::Type::BOOLEAN) + t << b + expect { t << b }.to raise_error(DBus::Type::SignatureException) + end + + it "raises if adding too much to a dict_entry" do + t = DBus::Type.new(DBus::Type::DICT_ENTRY, abstract: true) + b = DBus::Type.new(DBus::Type::BOOLEAN) + t << b + t << b + expect { t << b }.to raise_error(DBus::Type::SignatureException) + end + + it "raises if adding to a non-container" do + t = DBus::Type.new(DBus::Type::STRING) + b = DBus::Type.new(DBus::Type::BOOLEAN) + expect { t << b }.to raise_error(DBus::Type::SignatureException) + + t = DBus::Type.new(DBus::Type::VARIANT) + expect { t << b }.to raise_error(DBus::Type::SignatureException) + end + end + + describe DBus::Type::Array do + describe ".[]" do + it "takes Type argument" do + t = DBus::Type::Array[DBus::Type.new("s")] + expect(t.to_s).to eq "as" + end + + it "takes 's':String argument" do + t = DBus::Type::Array["s"] + expect(t.to_s).to eq "as" + end + + it "takes String:Class argument" do + t = DBus::Type::Array[String] + expect(t.to_s).to eq "as" + end + + it "rejects Integer:Class argument" do + expect { DBus::Type::Array[Integer] }.to raise_error(ArgumentError) + end + + it "rejects /./:Regexp argument" do + expect { DBus::Type::Array[/./] }.to raise_error(ArgumentError) + end + end + end + + describe DBus::Type::Hash do + describe ".[]" do + it "takes Type arguments" do + t = DBus::Type::Hash[DBus::Type.new("s"), DBus::Type.new("v")] + expect(t.to_s).to eq "a{sv}" + end + + it "takes 's':String arguments" do + t = DBus::Type::Hash["s", "v"] + expect(t.to_s).to eq "a{sv}" + end + + it "takes String:Class argument" do + t = DBus::Type::Hash[String, DBus::Type::VARIANT] + expect(t.to_s).to eq "a{sv}" + end + end + end + + describe DBus::Type::Struct do + describe ".[]" do + it "takes Type arguments" do + t = DBus::Type::Struct[DBus::Type.new("s"), DBus::Type.new("v")] + expect(t.to_s).to eq "(sv)" + end + + it "takes 's':String arguments" do + t = DBus::Type::Struct["s", "v"] + expect(t.to_s).to eq "(sv)" + end + + it "takes String:Class argument" do + t = DBus::Type::Struct[String, DBus::Type::VARIANT] + expect(t.to_s).to eq "(sv)" + end + + it "raises on no arguments" do + expect { DBus::Type::Struct[] }.to raise_error(ArgumentError) + end + end + end end end