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-05-26 18:43:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-ruby-dbus (Old) and /work/SRC/openSUSE:Factory/.rubygem-ruby-dbus.new.2254 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-ruby-dbus" Thu May 26 18:43:59 2022 rev:28 rq:979195 version:0.18.0.beta6 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-ruby-dbus/rubygem-ruby-dbus.changes 2022-04-30 00:44:55.414919439 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-ruby-dbus.new.2254/rubygem-ruby-dbus.changes 2022-05-26 18:44:06.085180859 +0200 @@ -1,0 +2,11 @@ +Wed May 25 13:20:39 UTC 2022 - Martin Vidner <mvid...@suse.com> + +- 0.18.0.beta6 + API: + * Data::Base#value returns plain Ruby types; + Data::Container#exact_value contains Data::Base (gh#mvidner/ruby-dbus#114). + * Data::Base#initialize and .from_typed allow plain or exact values, validate + argument types. + * Implement #== (converting) and #eql? (strict) for Data::Base and DBus::Type. + +------------------------------------------------------------------- Old: ---- ruby-dbus-0.18.0.beta5.gem New: ---- ruby-dbus-0.18.0.beta6.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-ruby-dbus.spec ++++++ --- /var/tmp/diff_new_pack.PK4Fku/_old 2022-05-26 18:44:06.585181442 +0200 +++ /var/tmp/diff_new_pack.PK4Fku/_new 2022-05-26 18:44:06.585181442 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-ruby-dbus -Version: 0.18.0.beta5 +Version: 0.18.0.beta6 Release: 0 %define mod_name ruby-dbus %define mod_full_name %{mod_name}-%{version} ++++++ ruby-dbus-0.18.0.beta5.gem -> ruby-dbus-0.18.0.beta6.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/NEWS.md new/NEWS.md --- old/NEWS.md 2022-04-27 10:47:47.000000000 +0200 +++ new/NEWS.md 2022-05-25 15:29:26.000000000 +0200 @@ -2,6 +2,17 @@ ## Unreleased +## Ruby D-Bus 0.18.0.beta6 - 2022-05-25 + +API: + * Data::Base#value returns plain Ruby types; + Data::Container#exact_value contains Data::Base ([#114][]). + * Data::Base#initialize and .from_typed allow plain or exact values, validate + argument types. + * Implement #== (converting) and #eql? (strict) for Data::Base and DBus::Type. + +[#114]: https://github.com/mvidner/ruby-dbus/pull/114 + ## Ruby D-Bus 0.18.0.beta5 - 2022-04-27 API: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/VERSION new/VERSION --- old/VERSION 2022-04-27 10:47:47.000000000 +0200 +++ new/VERSION 2022-05-25 15:29:26.000000000 +0200 @@ -1 +1 @@ -0.18.0.beta5 +0.18.0.beta6 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-27 10:47:47.000000000 +0200 +++ new/lib/dbus/data.rb 2022-05-25 15:29:26.000000000 +0200 @@ -35,7 +35,7 @@ # construct an appropriate {Data::Base} instance. # # @param type [SingleCompleteType,Type] - # @param value [::Object] + # @param value [::Object,Data::Base] a plain value; exact values also allowed # @return [Data::Base] # @raise TypeError def make_typed(type, value) @@ -58,9 +58,13 @@ # @!method self.fixed? # @return [Boolean] - # @return appropriately-typed, valid value + # @return [::Object] a valid value, plain-Ruby typed. + # @see Data::Container#exact_value attr_reader :value + # @!method self.type_code + # @return [String] a single-character string, for example "a" for arrays + # @!method type # @abstract # Note that for Variants type=="v", @@ -91,11 +95,18 @@ # Hash key equality # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F - alias eql? == + # Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false + def eql?(other) + return false unless other.class == self.class + + other.value.eql?(@value) + # TODO: this should work, now check derived classes, exact_value + end # @param type [Type] def self.assert_type_matches_class(type) - raise ArgumentError unless type.sigtype == type_code + raise ArgumentError, "Expecting #{type_code.inspect} for class #{self}, got #{type.sigtype.inspect}" \ + unless type.sigtype == type_code end end @@ -480,7 +491,7 @@ Byte end - # @return [Array<Type>] + # @return [::Array<Type>] def self.validate_raw!(value) DBus.types(value) rescue Type::SignatureException => e @@ -510,6 +521,29 @@ # For containers, the type varies among instances # @see Base#type attr_reader :type + + # @return something that is, or contains, {Data::Base}. + # Er, this docs kinda sucks. + def exact_value + @value + end + + def value + @value.map(&:value) + end + + # Hash key equality + # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F + # Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false + def eql?(other) + return false unless other.class == self.class + + other.exact_value.eql?(exact_value) + end + + # def ==(other) + # eql?(other) || super + # end end # An Array, or a Dictionary (Hash). @@ -538,16 +572,17 @@ # @param type [Type] # @return [Data::Array] def self.from_typed(value, type:) - assert_type_matches_class(type) - # TODO: validation - member_type = type.child + new(value, type: type) # initialize(::Array<Data::Base>) + end - # TODO: Dict?? - items = value.map do |i| - Data.make_typed(member_type, i) + def value + v = super + if type.child.sigtype == Type::DICT_ENTRY + # BTW this makes a copy so mutating it is pointless + v.to_h + else + v end - - new(items, type: type) # initialize(::Array<Data::Base>) end # FIXME: should Data::Array be mutable? @@ -556,13 +591,27 @@ # TODO: specify type or guess type? # Data is the exact type, so its constructor should be exact # and guesswork should be clearly labeled + + # @param value [Data::Array,Enumerable] # @param type [SingleCompleteType,Type] def initialize(value, type:) - type = DBus.type(type) unless type.is_a?(Type) + type = Type::Factory.make_type(type) self.class.assert_type_matches_class(type) @type = type - # TODO: copy from another Data::Array - super(value) + + typed_value = case value + when Data::Array + raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \ + unless value.type == type + + value.exact_value + else + # TODO: Dict?? + value.map do |i| + Data.make_typed(type.child, i) + end + end + super(typed_value) end end @@ -590,25 +639,72 @@ # @param type [Type] # @return [Struct] 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, type: type) # initialize(::Array<Data::Base>) + new(value, type: type) end + # @param value [Data::Struct,Enumerable] + # @param type [SingleCompleteType,Type] def initialize(value, type:) + type = Type::Factory.make_type(type) self.class.assert_type_matches_class(type) @type = type - super(value) + + typed_value = case value + when self.class + raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \ + unless value.type == type + + value.exact_value + else + member_types = type.members + unless value.size == member_types.size + raise ArgumentError, "Specified type has #{member_types.size} members " \ + "but value has #{value.size} members" + end + + member_types.zip(value).map do |item_type, item| + Data.make_typed(item_type, item) + end + end + super(typed_value) + end + + def ==(other) + case other + when ::Struct + @value.size == other.size && + @value.zip(other.to_a).all? { |i, other_i| i == other_i } + else + super + end + end + end + + # Dictionary/Hash entry. + # TODO: shouldn't instantiate? + class DictEntry < Struct + def self.type_code + "e" + end + + # @param value [::Array] + 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 type [Type] + # @return [DictEntry] + def self.from_typed(value, type:) + new(value, type: type) end end - # A generic type + # A generic type. + # + # Implementation note: @value is a {Data::Base}. class Variant < Container def self.type_code "v" @@ -618,6 +714,10 @@ 1 end + def value + @value.value + end + # @param member_type [Type] def self.from_items(value, mode:, member_type:) return value if mode == :plain @@ -631,7 +731,7 @@ def self.from_typed(value, type:) assert_type_matches_class(type) - # decide on type of value + # nil: decide on type of value new(value, member_type: nil) end @@ -659,60 +759,23 @@ # @param member_type [Type,nil] def initialize(value, member_type:) # TODO: validate that the given *member_type* matches *value* - if value.is_a?(self.class) + case value + when Data::Variant # Copy the contained value instead of boxing it more # TODO: except perhaps for round-tripping in exact mode? @member_type = value.member_type - value = value.value + value = value.exact_value + when Data::Base + @member_type = member_type || value.type + raise ArgumentError, "Variant type #{@member_type} does not match value type #{value.type}" \ + unless @member_type == value.type else @member_type = member_type || self.class.guess_type(value) + value = Data.make_typed(@member_type, value) end super(value) end end - - # Dictionary/Hash entry. - # TODO: shouldn't instantiate? - class DictEntry < Container - def self.type_code - "e" - end - - def self.alignment - 8 - end - - # @param value [::Array] - 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 type [Type] - # @return [DictEntry] - 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 - 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, type: type) # initialize(::Array<Data::Base>) - end - - def initialize(value, type:) - self.class.assert_type_matches_class(type) - @type = type - super(value) - end - end consts = constants.map { |c_sym| const_get(c_sym) } classes = consts.find_all { |c| c.respond_to?(:type_code) } 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-27 10:47:47.000000000 +0200 +++ new/lib/dbus/marshall.rb 2022-05-25 15:29:26.000000000 +0200 @@ -250,10 +250,10 @@ when Type::VARIANT append_variant(val) when Type::ARRAY - val = val.value if val.is_a?(Data::Array) + val = val.exact_value if val.is_a?(Data::Array) append_array(type.child, val) when Type::STRUCT, Type::DICT_ENTRY - val = val.value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry) + val = val.exact_value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry) unless val.is_a?(Array) || val.is_a?(Struct) type_name = Type::TYPE_MAPPING[type.sigtype].first raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}" @@ -284,7 +284,10 @@ vartype = nil if val.is_a?(DBus::Data::Variant) vartype = val.member_type - vardata = val.value + vardata = val.exact_value + elsif val.is_a?(DBus::Data::Container) + vartype = val.type + vardata = val.exact_value elsif val.is_a?(DBus::Data::Base) vartype = val.type vardata = val.value 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-27 10:47:47.000000000 +0200 +++ new/lib/dbus/type.rb 2022-05-25 15:29:26.000000000 +0200 @@ -107,6 +107,29 @@ freeze end + # A Type is equal to + # - another Type with the same string representation + # - a String ({SingleCompleteType}) describing the type + def ==(other) + case other + when ::String + to_s == other + else + eql?(other) + end + end + + # A Type is eql? to + # - another Type with the same string representation + # + # Hash key equality + # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F + def eql?(other) + return false unless other.is_a?(Type) + + @sigtype == other.sigtype && @members == other.members + end + # Return the required alignment for the type. def alignment TYPE_MAPPING[@sigtype].last @@ -157,7 +180,7 @@ def inspect s = TYPE_MAPPING[@sigtype].first - if [STRUCT, ARRAY].member?(@sigtype) + if [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype) s += ": #{@members.inspect}" end s diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2022-04-27 10:47:47.000000000 +0200 +++ new/metadata 2022-05-25 15:29:26.000000000 +0200 @@ -1,14 +1,14 @@ --- !ruby/object:Gem::Specification name: ruby-dbus version: !ruby/object:Gem::Version - version: 0.18.0.beta5 + version: 0.18.0.beta6 platform: ruby authors: - Ruby DBus Team -autorequire: +autorequire: bindir: bin cert_chain: [] -date: 2022-04-27 00:00:00.000000000 Z +date: 2022-05-25 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rexml @@ -202,7 +202,7 @@ licenses: - LGPL-2.1 metadata: {} -post_install_message: +post_install_message: rdoc_options: [] require_paths: - lib @@ -217,9 +217,8 @@ - !ruby/object:Gem::Version version: 1.3.1 requirements: [] -rubyforge_project: -rubygems_version: 2.7.6.3 -signing_key: +rubygems_version: 3.3.0.dev +signing_key: specification_version: 4 summary: Ruby module for interaction with D-Bus test_files: [] 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-27 10:47:47.000000000 +0200 +++ new/spec/data_spec.rb 2022-05-25 15:29:26.000000000 +0200 @@ -6,14 +6,140 @@ # The from_raw methods are tested in packet_unmarshaller_spec.rb +RSpec.shared_examples "#== and #eql? work for basic types" do |*args| + plain_a = args.fetch(0, 22) + plain_b = args.fetch(1, 222) + + context "with #{plain_a.inspect} and #{plain_b.inspect}" do + describe "#eql?" do + it "returns true for same class and value" do + a = described_class.new(plain_a) + b = described_class.new(plain_a) + expect(a).to eql(b) + end + + it "returns false for same class, different value" do + a = described_class.new(plain_a) + b = described_class.new(plain_b) + expect(a).to_not eql(b) + end + + it "returns false for same value but plain class" do + a = described_class.new(plain_a) + b = plain_a + expect(a).to_not eql(b) + end + end + + describe "#==" do + it "returns true for same class and value" do + a = described_class.new(plain_a) + b = described_class.new(plain_a) + expect(a).to eq(b) + end + + it "returns false for same class, different value" do + a = described_class.new(plain_a) + b = described_class.new(plain_b) + expect(a).to_not eq(b) + end + + it "returns true for same value but plain class" do + a = described_class.new(plain_a) + b = plain_a + expect(a).to eq(b) + end + end + end +end + +RSpec.shared_examples "#== and #eql? work for container types (1 value)" do |plain_a, a_kwargs| + a1 = described_class.new(plain_a, **a_kwargs) + a2 = described_class.new(plain_a, **a_kwargs) + + context "with #{plain_a.inspect}, #{a_kwargs.inspect}" do + describe "#eql?" do + it "returns true for same class and value" do + expect(a1).to eql(a2) + end + + it "returns false for same value but plain class" do + expect(a1).to_not eql(plain_a) + end + end + + describe "#==" do + it "returns true for same class and value" do + expect(a1).to eq(a2) + end + + it "returns true for same value but plain class" do + expect(a1).to eq(plain_a) + end + end + end +end + +RSpec.shared_examples "#== and #eql? work for container types (inequal)" do |plain_a, a_kwargs, plain_b, b_kwargs| + # RSpec note: if the shared_examples is used via include_examples more than + # once in a single context, `let` would take value from just one of them. + # So use plain assignment. + a = described_class.new(plain_a, **a_kwargs) + b = described_class.new(plain_b, **b_kwargs) + + include_examples "#== and #eql? work for container types (1 value)", plain_a, a_kwargs + + context "with #{plain_a.inspect}, #{a_kwargs.inspect} and #{plain_b.inspect}, #{b_kwargs.inspect}" do + describe "#eql?" do + it "returns false for same class, different value" do + expect(a).to_not eql(b) + end + end + + describe "#==" do + it "returns false for same class, different value" do + expect(a).to_not eq(b) + end + end + end +end + +RSpec.shared_examples "#== and #eql? work for container types (equal)" do |plain_a, a_kwargs, plain_b, b_kwargs| + a = described_class.new(plain_a, **a_kwargs) + b = described_class.new(plain_b, **b_kwargs) + + include_examples "#== and #eql? work for container types (1 value)", plain_a, a_kwargs + + context "with #{plain_a.inspect}, #{a_kwargs.inspect} and #{plain_b.inspect}, #{b_kwargs.inspect}" do + describe "#eql?" do + it "returns true for same class, differently expressed value" do + expect(a).to eql(b) + end + end + + describe "#==" do + it "returns true for same class, differently expressed value" do + expect(a).to eq(b) + end + end + + describe "#==" do + it "returns true for plain, differently expressed value" do + expect(a).to eq(plain_b) + expect(b).to eq(plain_a) + end + end + end +end + RSpec.shared_examples "constructor accepts numeric range" do |min, max| describe "#initialize" do it "accepts the min value #{min}" do - expect(described_class.new(min).value).to eq(min) + expect(described_class.new(min).value).to eql(min) end it "accepts the max value #{max}" do - expect(described_class.new(max).value).to eq(max) + expect(described_class.new(max).value).to eql(max) end it "raises on too small a value #{min - 1}" do @@ -34,27 +160,30 @@ describe "#initialize" do Array(plain_list).each do |plain| it "accepts the plain value #{plain.inspect}" do - expect(described_class.new(plain).value).to eq(plain) + expect(described_class.new(plain).value).to eql(plain) + expect(described_class.new(plain)).to eq(plain) end it "accepts the typed value #{plain.inspect}" do typed = described_class.new(plain) - expect(described_class.new(typed).value).to eq(plain) + expect(described_class.new(typed).value).to eql(plain) + expect(described_class.new(typed)).to eq(plain) end end end end +# FIXME: decide eq and eql here RSpec.shared_examples "constructor (kwargs) accepts values" do |list| describe "#initialize" do list.each do |value, kwargs_hash| it "accepts the plain value #{value.inspect}, #{kwargs_hash.inspect}" do - expect(described_class.new(value, **kwargs_hash).value).to eq(value) + expect(described_class.new(value, **kwargs_hash)).to eq(value) end it "accepts the typed value #{value.inspect}, #{kwargs_hash.inspect}" do typed = described_class.new(value, **kwargs_hash) - expect(described_class.new(typed, **kwargs_hash).value).to eq(value) + expect(described_class.new(typed, **kwargs_hash)).to eq(value) end end end @@ -93,36 +222,43 @@ # Kick InvalidPacketException out of here? describe DBus::Data::Byte do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", 0, 2**8 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int16 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", -2**15, 2**15 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt16 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", 0, 2**16 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int32 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", -2**31, 2**31 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt32 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", 0, 2**32 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::Int64 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", -2**63, 2**63 - 1 include_examples "constructor accepts plain or typed values", 42 end describe DBus::Data::UInt64 do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts numeric range", 0, 2**64 - 1 include_examples "constructor accepts plain or typed values", 42 end @@ -142,10 +278,12 @@ end end + include_examples "#== and #eql? work for basic types", false, true include_examples "constructor accepts plain or typed values", false end describe DBus::Data::Double do + include_examples "#== and #eql? work for basic types" include_examples "constructor accepts plain or typed values", Math::PI describe "#initialize" do @@ -183,6 +321,7 @@ ["\xF4\x90\xC0\xC0", DBus::InvalidPacketException, "not in UTF-8"] ] + include_examples "#== and #eql? work for basic types", "foo", "bar" include_examples "constructor accepts plain or typed values", good include_examples "constructor rejects values from this list", bad @@ -206,6 +345,7 @@ # TODO: others ] + include_examples "#== and #eql? work for basic types", "/foo", "/bar" include_examples "constructor accepts plain or typed values", good include_examples "constructor rejects values from this list", bad @@ -231,6 +371,7 @@ # TODO: others ] + include_examples "#== and #eql? work for basic types", "aah", "aaaaah" include_examples "constructor accepts plain or typed values", good include_examples "constructor rejects values from this list", bad @@ -262,6 +403,14 @@ # TODO: others ] + include_examples "#== and #eql? work for container types (inequal)", + [1, 2, 3], { type: "aq" }, + [3, 2, 1], { type: "aq" } + + include_examples "#== and #eql? work for container types (inequal)", + [[1, 2, 3]], { type: "aaq" }, + [[3, 2, 1]], { type: "aaq" } + include_examples "constructor (kwargs) accepts values", good include_examples "constructor (kwargs) rejects values", bad @@ -315,6 +464,14 @@ # TODO: others ] + include_examples "#== and #eql? work for container types (inequal)", + [1, 2, 3], { type: qqq }, + [3, 2, 1], { type: qqq } + + include_examples "#== and #eql? work for container types (equal)", + three_words.new(*integers), { type: qqq }, + [1, 2, 3], { type: qqq } + include_examples "constructor (kwargs) accepts values", good # include_examples "constructor (kwargs) rejects values", bad @@ -325,6 +482,108 @@ .to be_a(described_class) end end + + describe "#initialize" do + it "converts type to Type" do + value = [1, 2, 3] + type = "(uuu)" + result = described_class.new(value, type: type) + expect(result.type).to be_a DBus::Type + end + + it "checks that type matches class" do + value = [1, 2, 3] + type = T::Array[T::INT32] + expect { described_class.new(value, type: type) } + .to raise_error(ArgumentError, /Expecting "r"/) + end + + it "checks type of a Data::Struct value" do + value1 = [1, 2, 3] + type1 = "(uuu)" + result1 = described_class.new(value1, type: type1) + + value2 = result1 + type2 = "(xxx)" + expect { described_class.new(value2, type: type2) } + .to raise_error(ArgumentError, /value type is .uuu./) + end + + it "checks that size of type and value match" do + value = [1, 2, 3, 4] + type = "(uuu)" + expect { described_class.new(value, type: type) } + .to raise_error(ArgumentError, /type has 3 members.*value has 4 members/) + end + + it "converts value to ::Array of Data::Base" do + value = three_words.new(*integers) + type = T::Struct[T::INT32, T::INT32, T::INT32] + result = described_class.new(value, type: type) + + expect(result.exact_value).to be_an(::Array) + expect(result.exact_value[0]).to be_a(DBus::Data::Base) + end + end + end + + describe DBus::Data::DictEntry do + describe ".from_typed" do + it "creates new instance from given object and type" do + type = T::Hash[String, T::INT16].child + expect(described_class.from_typed(["test", 12], type: type)) + .to be_a(described_class) + end + end + + describe "#initialize" do + it "checks that type matches class" do + value = [1, 2] + type = T::Array[T::INT32] + + expect { described_class.new(value, type: type) } + .to raise_error(ArgumentError, /Expecting "e"/) + end + + it "checks type of a Data::DictEntry value" do + value1 = [1, 2] + type1 = T::Hash[T::UINT32, T::UINT32].child + result1 = described_class.new(value1, type: type1) + + value2 = result1 + type2 = T::Hash[T::UINT64, T::UINT64].child + expect { described_class.new(value2, type: type2) } + .to raise_error(ArgumentError, /value type is .uu./) + end + + it "checks that size of type and value match" do + value = [1, 2, 3] + type = T::Hash[T::UINT32, T::UINT32].child + expect { described_class.new(value, type: type) } + .to raise_error(ArgumentError, /type has 2 members.*value has 3 members/) + end + + it "converts value to ::Array of Data::Base" do + two_words = ::Struct.new(:k, :v) + value = two_words.new(1, 2) + type = T::Hash[T::UINT32, T::UINT32].child + result = described_class.new(value, type: type) + + expect(result.exact_value).to be_an(::Array) + expect(result.exact_value[0]).to be_a(DBus::Data::Base) + end + + it "takes a plain value" do + input = ["test", 23] + + type = T::Hash[String, T::INT16].child + value = described_class.new(input, type: type) + + expect(value).to be_a(described_class) + expect(value.type.to_s).to eq "{sn}" + expect(value.value).to eql input + end + end end describe DBus::Data::Variant do @@ -337,9 +596,42 @@ expect(value.member_type.to_s).to eq "s" end end - end - describe DBus::Data::DictEntry do + describe "#initialize" do + it "takes a plain value" do + input = 42 + + type = DBus.type(T::INT16) + value = described_class.new(input, member_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 "n" + expect(value.value).to eq 42 + end + + # FIXME: verify that @value has the correct class + it "takes an exact value" do + input = DBus::Data::Int16.new(42) + + type = DBus.type(T::INT16) + value = described_class.new(input, member_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 "n" + expect(value.value).to eq 42 + end + + it "checks the type of the exact value" do + input = DBus::Data::UInt16.new(42) + + type = DBus.type(T::INT16) + expect { described_class.new(input, member_type: type) } + .to raise_error(ArgumentError, /Variant type n does not match value type q/) + end + end + + include_examples "#== and #eql? work for container types (1 value)", + "/foo", { member_type: DBus.type(T::STRING) } end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spec/packet_unmarshaller_spec.rb new/spec/packet_unmarshaller_spec.rb --- old/spec/packet_unmarshaller_spec.rb 2022-04-27 10:47:47.000000000 +0200 +++ new/spec/packet_unmarshaller_spec.rb 2022-05-25 15:29:26.000000000 +0200 @@ -48,14 +48,7 @@ result = results.first expect(result).to be_a(DBus::Data::Base) - if expected.is_a?(Hash) - expect(result.value.size).to eq(expected.size) - result.value.each_key do |result_key| - expect(result.value[result_key]).to eq(expected[result_key.value]) - end - else - expect(result.value).to eq(expected) - end + expect(result.value).to eq(expected) expect(remaining_buffer(subject)).to be_empty end @@ -106,14 +99,7 @@ result = results.first expect(result).to be_a(DBus::Data::Base) - if expected.is_a?(Hash) - expect(result.value.size).to eq(expected.size) - result.value.each_key do |result_key| - expect(result.value[result_key]).to eq(expected[result_key.value]) - end - else - expect(result.value).to eq(expected) - end + expect(result.value).to eq(expected) expect(remaining_buffer(subject)).to be_empty end 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-27 10:47:47.000000000 +0200 +++ new/spec/type_spec.rb 2022-05-25 15:29:26.000000000 +0200 @@ -82,6 +82,46 @@ end describe DBus::Type do + let(:as1) { DBus.type("as") } + let(:as2) { DBus.type("as") } + let(:aas) { DBus.type("aas") } + + describe "#==" do + it "is true for same types" do + expect(as1).to eq(as2) + end + + it "is true for a type and its string representation" do + expect(as1).to eq("as") + end + + it "is false for different types" do + expect(as1).to_not eq(aas) + end + + it "is false for a type and a different string" do + expect(as1).to_not eq("aas") + end + end + + describe "#eql?" do + it "is true for same types" do + expect(as1).to eql(as2) + end + + it "is false for a type and its string representation" do + expect(as1).to_not eql("as") + end + + it "is false for different types" do + expect(as1).to_not eql(aas) + end + + it "is false for a type and a different string" do + expect(as1).to_not eql("aas") + end + end + describe "#<<" do it "raises if the argument is not a Type" do t = DBus::Type.new(DBus::Type::ARRAY)