ruby-dbus 0.18.0.beta5 → 0.18.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8b0c43d3f27f0877e52c0adfb8014374829f97bcd38be6b9fabda1d5da8413c
4
- data.tar.gz: 000eadf163b0fab2ef4ab39de81a79714b34392cd81b3be68e12587ddfa93372
3
+ metadata.gz: 54a45385340217271e3fb445cddf6afcddb9892c4bf75b503e7859390f4d2ed7
4
+ data.tar.gz: 3c4f71745992c5afece87e34909e67f451717c9398ac6efb6235cc64ad1d1b0c
5
5
  SHA512:
6
- metadata.gz: c2206dcd935fed4e3711b88b2c0c265e5a335700f9137d2c3972f419791d9c25198d0acf9ba7aaecdbc6a25e540005c64321e5165c6c644838fb3557355861ac
7
- data.tar.gz: 212cb8bdcd75e3f35622843f262cdb80eaa07c1919a7d17ffdf601e05c627556343b7855a014f60a220c8a757c201431d66799a6025a98d084aef6cc12f7d8bb
6
+ metadata.gz: 864aaaaa867ea04247515d875d836560a558b7a3d780712a41dcd52214d95e47e857d640d66a3573eaf4df778a0320f89ad2c59918c005a2fc80adb8a63074cb
7
+ data.tar.gz: cabd9d699d8b7aad7c5f77a83aa07389b59c11b34b1219822909a031774b078d0bf001a1bce9bb5912be42caa4adba7608906ebc76dde57ff9f06d13afd7850f
data/NEWS.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## Ruby D-Bus 0.18.0.beta6 - 2022-05-25
6
+
7
+ API:
8
+ * Data::Base#value returns plain Ruby types;
9
+ Data::Container#exact_value contains Data::Base ([#114][]).
10
+ * Data::Base#initialize and .from_typed allow plain or exact values, validate
11
+ argument types.
12
+ * Implement #== (converting) and #eql? (strict) for Data::Base and DBus::Type.
13
+
14
+ [#114]: https://github.com/mvidner/ruby-dbus/pull/114
15
+
5
16
  ## Ruby D-Bus 0.18.0.beta5 - 2022-04-27
6
17
 
7
18
  API:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.18.0.beta5
1
+ 0.18.0.beta6
data/lib/dbus/data.rb CHANGED
@@ -35,7 +35,7 @@ module DBus
35
35
  # construct an appropriate {Data::Base} instance.
36
36
  #
37
37
  # @param type [SingleCompleteType,Type]
38
- # @param value [::Object]
38
+ # @param value [::Object,Data::Base] a plain value; exact values also allowed
39
39
  # @return [Data::Base]
40
40
  # @raise TypeError
41
41
  def make_typed(type, value)
@@ -58,9 +58,13 @@ module DBus
58
58
  # @!method self.fixed?
59
59
  # @return [Boolean]
60
60
 
61
- # @return appropriately-typed, valid value
61
+ # @return [::Object] a valid value, plain-Ruby typed.
62
+ # @see Data::Container#exact_value
62
63
  attr_reader :value
63
64
 
65
+ # @!method self.type_code
66
+ # @return [String] a single-character string, for example "a" for arrays
67
+
64
68
  # @!method type
65
69
  # @abstract
66
70
  # Note that for Variants type=="v",
@@ -91,11 +95,18 @@ module DBus
91
95
 
92
96
  # Hash key equality
93
97
  # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
94
- alias eql? ==
98
+ # Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false
99
+ def eql?(other)
100
+ return false unless other.class == self.class
101
+
102
+ other.value.eql?(@value)
103
+ # TODO: this should work, now check derived classes, exact_value
104
+ end
95
105
 
96
106
  # @param type [Type]
97
107
  def self.assert_type_matches_class(type)
98
- raise ArgumentError unless type.sigtype == type_code
108
+ raise ArgumentError, "Expecting #{type_code.inspect} for class #{self}, got #{type.sigtype.inspect}" \
109
+ unless type.sigtype == type_code
99
110
  end
100
111
  end
101
112
 
@@ -480,7 +491,7 @@ module DBus
480
491
  Byte
481
492
  end
482
493
 
483
- # @return [Array<Type>]
494
+ # @return [::Array<Type>]
484
495
  def self.validate_raw!(value)
485
496
  DBus.types(value)
486
497
  rescue Type::SignatureException => e
@@ -510,6 +521,29 @@ module DBus
510
521
  # For containers, the type varies among instances
511
522
  # @see Base#type
512
523
  attr_reader :type
524
+
525
+ # @return something that is, or contains, {Data::Base}.
526
+ # Er, this docs kinda sucks.
527
+ def exact_value
528
+ @value
529
+ end
530
+
531
+ def value
532
+ @value.map(&:value)
533
+ end
534
+
535
+ # Hash key equality
536
+ # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
537
+ # Stricter than #== (RSpec: eq), 1==1.0 but 1.eql(1.0)->false
538
+ def eql?(other)
539
+ return false unless other.class == self.class
540
+
541
+ other.exact_value.eql?(exact_value)
542
+ end
543
+
544
+ # def ==(other)
545
+ # eql?(other) || super
546
+ # end
513
547
  end
514
548
 
515
549
  # An Array, or a Dictionary (Hash).
@@ -538,16 +572,17 @@ module DBus
538
572
  # @param type [Type]
539
573
  # @return [Data::Array]
540
574
  def self.from_typed(value, type:)
541
- assert_type_matches_class(type)
542
- # TODO: validation
543
- member_type = type.child
575
+ new(value, type: type) # initialize(::Array<Data::Base>)
576
+ end
544
577
 
545
- # TODO: Dict??
546
- items = value.map do |i|
547
- Data.make_typed(member_type, i)
578
+ def value
579
+ v = super
580
+ if type.child.sigtype == Type::DICT_ENTRY
581
+ # BTW this makes a copy so mutating it is pointless
582
+ v.to_h
583
+ else
584
+ v
548
585
  end
549
-
550
- new(items, type: type) # initialize(::Array<Data::Base>)
551
586
  end
552
587
 
553
588
  # FIXME: should Data::Array be mutable?
@@ -556,13 +591,27 @@ module DBus
556
591
  # TODO: specify type or guess type?
557
592
  # Data is the exact type, so its constructor should be exact
558
593
  # and guesswork should be clearly labeled
594
+
595
+ # @param value [Data::Array,Enumerable]
559
596
  # @param type [SingleCompleteType,Type]
560
597
  def initialize(value, type:)
561
- type = DBus.type(type) unless type.is_a?(Type)
598
+ type = Type::Factory.make_type(type)
562
599
  self.class.assert_type_matches_class(type)
563
600
  @type = type
564
- # TODO: copy from another Data::Array
565
- super(value)
601
+
602
+ typed_value = case value
603
+ when Data::Array
604
+ raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \
605
+ unless value.type == type
606
+
607
+ value.exact_value
608
+ else
609
+ # TODO: Dict??
610
+ value.map do |i|
611
+ Data.make_typed(type.child, i)
612
+ end
613
+ end
614
+ super(typed_value)
566
615
  end
567
616
  end
568
617
 
@@ -590,25 +639,72 @@ module DBus
590
639
  # @param type [Type]
591
640
  # @return [Struct]
592
641
  def self.from_typed(value, type:)
593
- # TODO: validation
594
- member_types = type.members
595
- raise unless value.size == member_types.size
596
-
597
- items = member_types.zip(value).map do |item_type, item|
598
- Data.make_typed(item_type, item)
599
- end
600
-
601
- new(items, type: type) # initialize(::Array<Data::Base>)
642
+ new(value, type: type)
602
643
  end
603
644
 
645
+ # @param value [Data::Struct,Enumerable]
646
+ # @param type [SingleCompleteType,Type]
604
647
  def initialize(value, type:)
648
+ type = Type::Factory.make_type(type)
605
649
  self.class.assert_type_matches_class(type)
606
650
  @type = type
607
- super(value)
651
+
652
+ typed_value = case value
653
+ when self.class
654
+ raise ArgumentError, "Specified type is #{type} but value type is #{value.type}" \
655
+ unless value.type == type
656
+
657
+ value.exact_value
658
+ else
659
+ member_types = type.members
660
+ unless value.size == member_types.size
661
+ raise ArgumentError, "Specified type has #{member_types.size} members " \
662
+ "but value has #{value.size} members"
663
+ end
664
+
665
+ member_types.zip(value).map do |item_type, item|
666
+ Data.make_typed(item_type, item)
667
+ end
668
+ end
669
+ super(typed_value)
670
+ end
671
+
672
+ def ==(other)
673
+ case other
674
+ when ::Struct
675
+ @value.size == other.size &&
676
+ @value.zip(other.to_a).all? { |i, other_i| i == other_i }
677
+ else
678
+ super
679
+ end
680
+ end
681
+ end
682
+
683
+ # Dictionary/Hash entry.
684
+ # TODO: shouldn't instantiate?
685
+ class DictEntry < Struct
686
+ def self.type_code
687
+ "e"
688
+ end
689
+
690
+ # @param value [::Array]
691
+ def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
692
+ value.freeze
693
+ # DictEntry ignores the :exact mode
694
+ value
695
+ end
696
+
697
+ # @param value [::Object] (#size, #each)
698
+ # @param type [Type]
699
+ # @return [DictEntry]
700
+ def self.from_typed(value, type:)
701
+ new(value, type: type)
608
702
  end
609
703
  end
610
704
 
611
- # A generic type
705
+ # A generic type.
706
+ #
707
+ # Implementation note: @value is a {Data::Base}.
612
708
  class Variant < Container
613
709
  def self.type_code
614
710
  "v"
@@ -618,6 +714,10 @@ module DBus
618
714
  1
619
715
  end
620
716
 
717
+ def value
718
+ @value.value
719
+ end
720
+
621
721
  # @param member_type [Type]
622
722
  def self.from_items(value, mode:, member_type:)
623
723
  return value if mode == :plain
@@ -631,7 +731,7 @@ module DBus
631
731
  def self.from_typed(value, type:)
632
732
  assert_type_matches_class(type)
633
733
 
634
- # decide on type of value
734
+ # nil: decide on type of value
635
735
  new(value, member_type: nil)
636
736
  end
637
737
 
@@ -659,61 +759,24 @@ module DBus
659
759
  # @param member_type [Type,nil]
660
760
  def initialize(value, member_type:)
661
761
  # TODO: validate that the given *member_type* matches *value*
662
- if value.is_a?(self.class)
762
+ case value
763
+ when Data::Variant
663
764
  # Copy the contained value instead of boxing it more
664
765
  # TODO: except perhaps for round-tripping in exact mode?
665
766
  @member_type = value.member_type
666
- value = value.value
767
+ value = value.exact_value
768
+ when Data::Base
769
+ @member_type = member_type || value.type
770
+ raise ArgumentError, "Variant type #{@member_type} does not match value type #{value.type}" \
771
+ unless @member_type == value.type
667
772
  else
668
773
  @member_type = member_type || self.class.guess_type(value)
774
+ value = Data.make_typed(@member_type, value)
669
775
  end
670
776
  super(value)
671
777
  end
672
778
  end
673
779
 
674
- # Dictionary/Hash entry.
675
- # TODO: shouldn't instantiate?
676
- class DictEntry < Container
677
- def self.type_code
678
- "e"
679
- end
680
-
681
- def self.alignment
682
- 8
683
- end
684
-
685
- # @param value [::Array]
686
- def self.from_items(value, mode:, type:) # rubocop:disable Lint/UnusedMethodArgument
687
- value.freeze
688
- # DictEntry ignores the :exact mode
689
- value
690
- end
691
-
692
- # @param value [::Object] (#size, #each)
693
- # @param type [Type]
694
- # @return [DictEntry]
695
- def self.from_typed(value, type:)
696
- assert_type_matches_class(type)
697
- member_types = type.members
698
- # assert member_types.size == 2
699
- # TODO: duplicated from Struct. Inherit/delegate?
700
- # TODO: validation
701
- raise unless value.size == member_types.size
702
-
703
- items = member_types.zip(value).map do |item_type, item|
704
- Data.make_typed(item_type, item)
705
- end
706
-
707
- new(items, type: type) # initialize(::Array<Data::Base>)
708
- end
709
-
710
- def initialize(value, type:)
711
- self.class.assert_type_matches_class(type)
712
- @type = type
713
- super(value)
714
- end
715
- end
716
-
717
780
  consts = constants.map { |c_sym| const_get(c_sym) }
718
781
  classes = consts.find_all { |c| c.respond_to?(:type_code) }
719
782
  by_type_code = classes.map { |cl| [cl.type_code, cl] }.to_h
data/lib/dbus/marshall.rb CHANGED
@@ -250,10 +250,10 @@ module DBus
250
250
  when Type::VARIANT
251
251
  append_variant(val)
252
252
  when Type::ARRAY
253
- val = val.value if val.is_a?(Data::Array)
253
+ val = val.exact_value if val.is_a?(Data::Array)
254
254
  append_array(type.child, val)
255
255
  when Type::STRUCT, Type::DICT_ENTRY
256
- val = val.value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
256
+ val = val.exact_value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
257
257
  unless val.is_a?(Array) || val.is_a?(Struct)
258
258
  type_name = Type::TYPE_MAPPING[type.sigtype].first
259
259
  raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}"
@@ -284,7 +284,10 @@ module DBus
284
284
  vartype = nil
285
285
  if val.is_a?(DBus::Data::Variant)
286
286
  vartype = val.member_type
287
- vardata = val.value
287
+ vardata = val.exact_value
288
+ elsif val.is_a?(DBus::Data::Container)
289
+ vartype = val.type
290
+ vardata = val.exact_value
288
291
  elsif val.is_a?(DBus::Data::Base)
289
292
  vartype = val.type
290
293
  vardata = val.value
data/lib/dbus/type.rb CHANGED
@@ -107,6 +107,29 @@ module DBus
107
107
  freeze
108
108
  end
109
109
 
110
+ # A Type is equal to
111
+ # - another Type with the same string representation
112
+ # - a String ({SingleCompleteType}) describing the type
113
+ def ==(other)
114
+ case other
115
+ when ::String
116
+ to_s == other
117
+ else
118
+ eql?(other)
119
+ end
120
+ end
121
+
122
+ # A Type is eql? to
123
+ # - another Type with the same string representation
124
+ #
125
+ # Hash key equality
126
+ # See https://ruby-doc.org/core-3.0.0/Object.html#method-i-eql-3F
127
+ def eql?(other)
128
+ return false unless other.is_a?(Type)
129
+
130
+ @sigtype == other.sigtype && @members == other.members
131
+ end
132
+
110
133
  # Return the required alignment for the type.
111
134
  def alignment
112
135
  TYPE_MAPPING[@sigtype].last
@@ -157,7 +180,7 @@ module DBus
157
180
 
158
181
  def inspect
159
182
  s = TYPE_MAPPING[@sigtype].first
160
- if [STRUCT, ARRAY].member?(@sigtype)
183
+ if [STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
161
184
  s += ": #{@members.inspect}"
162
185
  end
163
186
  s
data/spec/data_spec.rb CHANGED
@@ -6,14 +6,140 @@ require "dbus"
6
6
 
7
7
  # The from_raw methods are tested in packet_unmarshaller_spec.rb
8
8
 
9
+ RSpec.shared_examples "#== and #eql? work for basic types" do |*args|
10
+ plain_a = args.fetch(0, 22)
11
+ plain_b = args.fetch(1, 222)
12
+
13
+ context "with #{plain_a.inspect} and #{plain_b.inspect}" do
14
+ describe "#eql?" do
15
+ it "returns true for same class and value" do
16
+ a = described_class.new(plain_a)
17
+ b = described_class.new(plain_a)
18
+ expect(a).to eql(b)
19
+ end
20
+
21
+ it "returns false for same class, different value" do
22
+ a = described_class.new(plain_a)
23
+ b = described_class.new(plain_b)
24
+ expect(a).to_not eql(b)
25
+ end
26
+
27
+ it "returns false for same value but plain class" do
28
+ a = described_class.new(plain_a)
29
+ b = plain_a
30
+ expect(a).to_not eql(b)
31
+ end
32
+ end
33
+
34
+ describe "#==" do
35
+ it "returns true for same class and value" do
36
+ a = described_class.new(plain_a)
37
+ b = described_class.new(plain_a)
38
+ expect(a).to eq(b)
39
+ end
40
+
41
+ it "returns false for same class, different value" do
42
+ a = described_class.new(plain_a)
43
+ b = described_class.new(plain_b)
44
+ expect(a).to_not eq(b)
45
+ end
46
+
47
+ it "returns true for same value but plain class" do
48
+ a = described_class.new(plain_a)
49
+ b = plain_a
50
+ expect(a).to eq(b)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ RSpec.shared_examples "#== and #eql? work for container types (1 value)" do |plain_a, a_kwargs|
57
+ a1 = described_class.new(plain_a, **a_kwargs)
58
+ a2 = described_class.new(plain_a, **a_kwargs)
59
+
60
+ context "with #{plain_a.inspect}, #{a_kwargs.inspect}" do
61
+ describe "#eql?" do
62
+ it "returns true for same class and value" do
63
+ expect(a1).to eql(a2)
64
+ end
65
+
66
+ it "returns false for same value but plain class" do
67
+ expect(a1).to_not eql(plain_a)
68
+ end
69
+ end
70
+
71
+ describe "#==" do
72
+ it "returns true for same class and value" do
73
+ expect(a1).to eq(a2)
74
+ end
75
+
76
+ it "returns true for same value but plain class" do
77
+ expect(a1).to eq(plain_a)
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ RSpec.shared_examples "#== and #eql? work for container types (inequal)" do |plain_a, a_kwargs, plain_b, b_kwargs|
84
+ # RSpec note: if the shared_examples is used via include_examples more than
85
+ # once in a single context, `let` would take value from just one of them.
86
+ # So use plain assignment.
87
+ a = described_class.new(plain_a, **a_kwargs)
88
+ b = described_class.new(plain_b, **b_kwargs)
89
+
90
+ include_examples "#== and #eql? work for container types (1 value)", plain_a, a_kwargs
91
+
92
+ context "with #{plain_a.inspect}, #{a_kwargs.inspect} and #{plain_b.inspect}, #{b_kwargs.inspect}" do
93
+ describe "#eql?" do
94
+ it "returns false for same class, different value" do
95
+ expect(a).to_not eql(b)
96
+ end
97
+ end
98
+
99
+ describe "#==" do
100
+ it "returns false for same class, different value" do
101
+ expect(a).to_not eq(b)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ RSpec.shared_examples "#== and #eql? work for container types (equal)" do |plain_a, a_kwargs, plain_b, b_kwargs|
108
+ a = described_class.new(plain_a, **a_kwargs)
109
+ b = described_class.new(plain_b, **b_kwargs)
110
+
111
+ include_examples "#== and #eql? work for container types (1 value)", plain_a, a_kwargs
112
+
113
+ context "with #{plain_a.inspect}, #{a_kwargs.inspect} and #{plain_b.inspect}, #{b_kwargs.inspect}" do
114
+ describe "#eql?" do
115
+ it "returns true for same class, differently expressed value" do
116
+ expect(a).to eql(b)
117
+ end
118
+ end
119
+
120
+ describe "#==" do
121
+ it "returns true for same class, differently expressed value" do
122
+ expect(a).to eq(b)
123
+ end
124
+ end
125
+
126
+ describe "#==" do
127
+ it "returns true for plain, differently expressed value" do
128
+ expect(a).to eq(plain_b)
129
+ expect(b).to eq(plain_a)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
9
135
  RSpec.shared_examples "constructor accepts numeric range" do |min, max|
10
136
  describe "#initialize" do
11
137
  it "accepts the min value #{min}" do
12
- expect(described_class.new(min).value).to eq(min)
138
+ expect(described_class.new(min).value).to eql(min)
13
139
  end
14
140
 
15
141
  it "accepts the max value #{max}" do
16
- expect(described_class.new(max).value).to eq(max)
142
+ expect(described_class.new(max).value).to eql(max)
17
143
  end
18
144
 
19
145
  it "raises on too small a value #{min - 1}" do
@@ -34,27 +160,30 @@ RSpec.shared_examples "constructor accepts plain or typed values" do |plain_list
34
160
  describe "#initialize" do
35
161
  Array(plain_list).each do |plain|
36
162
  it "accepts the plain value #{plain.inspect}" do
37
- expect(described_class.new(plain).value).to eq(plain)
163
+ expect(described_class.new(plain).value).to eql(plain)
164
+ expect(described_class.new(plain)).to eq(plain)
38
165
  end
39
166
 
40
167
  it "accepts the typed value #{plain.inspect}" do
41
168
  typed = described_class.new(plain)
42
- expect(described_class.new(typed).value).to eq(plain)
169
+ expect(described_class.new(typed).value).to eql(plain)
170
+ expect(described_class.new(typed)).to eq(plain)
43
171
  end
44
172
  end
45
173
  end
46
174
  end
47
175
 
176
+ # FIXME: decide eq and eql here
48
177
  RSpec.shared_examples "constructor (kwargs) accepts values" do |list|
49
178
  describe "#initialize" do
50
179
  list.each do |value, kwargs_hash|
51
180
  it "accepts the plain value #{value.inspect}, #{kwargs_hash.inspect}" do
52
- expect(described_class.new(value, **kwargs_hash).value).to eq(value)
181
+ expect(described_class.new(value, **kwargs_hash)).to eq(value)
53
182
  end
54
183
 
55
184
  it "accepts the typed value #{value.inspect}, #{kwargs_hash.inspect}" do
56
185
  typed = described_class.new(value, **kwargs_hash)
57
- expect(described_class.new(typed, **kwargs_hash).value).to eq(value)
186
+ expect(described_class.new(typed, **kwargs_hash)).to eq(value)
58
187
  end
59
188
  end
60
189
  end
@@ -93,36 +222,43 @@ describe DBus::Data do
93
222
  # Kick InvalidPacketException out of here?
94
223
 
95
224
  describe DBus::Data::Byte do
225
+ include_examples "#== and #eql? work for basic types"
96
226
  include_examples "constructor accepts numeric range", 0, 2**8 - 1
97
227
  include_examples "constructor accepts plain or typed values", 42
98
228
  end
99
229
 
100
230
  describe DBus::Data::Int16 do
231
+ include_examples "#== and #eql? work for basic types"
101
232
  include_examples "constructor accepts numeric range", -2**15, 2**15 - 1
102
233
  include_examples "constructor accepts plain or typed values", 42
103
234
  end
104
235
 
105
236
  describe DBus::Data::UInt16 do
237
+ include_examples "#== and #eql? work for basic types"
106
238
  include_examples "constructor accepts numeric range", 0, 2**16 - 1
107
239
  include_examples "constructor accepts plain or typed values", 42
108
240
  end
109
241
 
110
242
  describe DBus::Data::Int32 do
243
+ include_examples "#== and #eql? work for basic types"
111
244
  include_examples "constructor accepts numeric range", -2**31, 2**31 - 1
112
245
  include_examples "constructor accepts plain or typed values", 42
113
246
  end
114
247
 
115
248
  describe DBus::Data::UInt32 do
249
+ include_examples "#== and #eql? work for basic types"
116
250
  include_examples "constructor accepts numeric range", 0, 2**32 - 1
117
251
  include_examples "constructor accepts plain or typed values", 42
118
252
  end
119
253
 
120
254
  describe DBus::Data::Int64 do
255
+ include_examples "#== and #eql? work for basic types"
121
256
  include_examples "constructor accepts numeric range", -2**63, 2**63 - 1
122
257
  include_examples "constructor accepts plain or typed values", 42
123
258
  end
124
259
 
125
260
  describe DBus::Data::UInt64 do
261
+ include_examples "#== and #eql? work for basic types"
126
262
  include_examples "constructor accepts numeric range", 0, 2**64 - 1
127
263
  include_examples "constructor accepts plain or typed values", 42
128
264
  end
@@ -142,10 +278,12 @@ describe DBus::Data do
142
278
  end
143
279
  end
144
280
 
281
+ include_examples "#== and #eql? work for basic types", false, true
145
282
  include_examples "constructor accepts plain or typed values", false
146
283
  end
147
284
 
148
285
  describe DBus::Data::Double do
286
+ include_examples "#== and #eql? work for basic types"
149
287
  include_examples "constructor accepts plain or typed values", Math::PI
150
288
 
151
289
  describe "#initialize" do
@@ -183,6 +321,7 @@ describe DBus::Data do
183
321
  ["\xF4\x90\xC0\xC0", DBus::InvalidPacketException, "not in UTF-8"]
184
322
  ]
185
323
 
324
+ include_examples "#== and #eql? work for basic types", "foo", "bar"
186
325
  include_examples "constructor accepts plain or typed values", good
187
326
  include_examples "constructor rejects values from this list", bad
188
327
 
@@ -206,6 +345,7 @@ describe DBus::Data do
206
345
  # TODO: others
207
346
  ]
208
347
 
348
+ include_examples "#== and #eql? work for basic types", "/foo", "/bar"
209
349
  include_examples "constructor accepts plain or typed values", good
210
350
  include_examples "constructor rejects values from this list", bad
211
351
 
@@ -231,6 +371,7 @@ describe DBus::Data do
231
371
  # TODO: others
232
372
  ]
233
373
 
374
+ include_examples "#== and #eql? work for basic types", "aah", "aaaaah"
234
375
  include_examples "constructor accepts plain or typed values", good
235
376
  include_examples "constructor rejects values from this list", bad
236
377
 
@@ -262,6 +403,14 @@ describe DBus::Data do
262
403
  # TODO: others
263
404
  ]
264
405
 
406
+ include_examples "#== and #eql? work for container types (inequal)",
407
+ [1, 2, 3], { type: "aq" },
408
+ [3, 2, 1], { type: "aq" }
409
+
410
+ include_examples "#== and #eql? work for container types (inequal)",
411
+ [[1, 2, 3]], { type: "aaq" },
412
+ [[3, 2, 1]], { type: "aaq" }
413
+
265
414
  include_examples "constructor (kwargs) accepts values", good
266
415
  include_examples "constructor (kwargs) rejects values", bad
267
416
 
@@ -315,6 +464,14 @@ describe DBus::Data do
315
464
  # TODO: others
316
465
  ]
317
466
 
467
+ include_examples "#== and #eql? work for container types (inequal)",
468
+ [1, 2, 3], { type: qqq },
469
+ [3, 2, 1], { type: qqq }
470
+
471
+ include_examples "#== and #eql? work for container types (equal)",
472
+ three_words.new(*integers), { type: qqq },
473
+ [1, 2, 3], { type: qqq }
474
+
318
475
  include_examples "constructor (kwargs) accepts values", good
319
476
  # include_examples "constructor (kwargs) rejects values", bad
320
477
 
@@ -325,6 +482,108 @@ describe DBus::Data do
325
482
  .to be_a(described_class)
326
483
  end
327
484
  end
485
+
486
+ describe "#initialize" do
487
+ it "converts type to Type" do
488
+ value = [1, 2, 3]
489
+ type = "(uuu)"
490
+ result = described_class.new(value, type: type)
491
+ expect(result.type).to be_a DBus::Type
492
+ end
493
+
494
+ it "checks that type matches class" do
495
+ value = [1, 2, 3]
496
+ type = T::Array[T::INT32]
497
+ expect { described_class.new(value, type: type) }
498
+ .to raise_error(ArgumentError, /Expecting "r"/)
499
+ end
500
+
501
+ it "checks type of a Data::Struct value" do
502
+ value1 = [1, 2, 3]
503
+ type1 = "(uuu)"
504
+ result1 = described_class.new(value1, type: type1)
505
+
506
+ value2 = result1
507
+ type2 = "(xxx)"
508
+ expect { described_class.new(value2, type: type2) }
509
+ .to raise_error(ArgumentError, /value type is .uuu./)
510
+ end
511
+
512
+ it "checks that size of type and value match" do
513
+ value = [1, 2, 3, 4]
514
+ type = "(uuu)"
515
+ expect { described_class.new(value, type: type) }
516
+ .to raise_error(ArgumentError, /type has 3 members.*value has 4 members/)
517
+ end
518
+
519
+ it "converts value to ::Array of Data::Base" do
520
+ value = three_words.new(*integers)
521
+ type = T::Struct[T::INT32, T::INT32, T::INT32]
522
+ result = described_class.new(value, type: type)
523
+
524
+ expect(result.exact_value).to be_an(::Array)
525
+ expect(result.exact_value[0]).to be_a(DBus::Data::Base)
526
+ end
527
+ end
528
+ end
529
+
530
+ describe DBus::Data::DictEntry do
531
+ describe ".from_typed" do
532
+ it "creates new instance from given object and type" do
533
+ type = T::Hash[String, T::INT16].child
534
+ expect(described_class.from_typed(["test", 12], type: type))
535
+ .to be_a(described_class)
536
+ end
537
+ end
538
+
539
+ describe "#initialize" do
540
+ it "checks that type matches class" do
541
+ value = [1, 2]
542
+ type = T::Array[T::INT32]
543
+
544
+ expect { described_class.new(value, type: type) }
545
+ .to raise_error(ArgumentError, /Expecting "e"/)
546
+ end
547
+
548
+ it "checks type of a Data::DictEntry value" do
549
+ value1 = [1, 2]
550
+ type1 = T::Hash[T::UINT32, T::UINT32].child
551
+ result1 = described_class.new(value1, type: type1)
552
+
553
+ value2 = result1
554
+ type2 = T::Hash[T::UINT64, T::UINT64].child
555
+ expect { described_class.new(value2, type: type2) }
556
+ .to raise_error(ArgumentError, /value type is .uu./)
557
+ end
558
+
559
+ it "checks that size of type and value match" do
560
+ value = [1, 2, 3]
561
+ type = T::Hash[T::UINT32, T::UINT32].child
562
+ expect { described_class.new(value, type: type) }
563
+ .to raise_error(ArgumentError, /type has 2 members.*value has 3 members/)
564
+ end
565
+
566
+ it "converts value to ::Array of Data::Base" do
567
+ two_words = ::Struct.new(:k, :v)
568
+ value = two_words.new(1, 2)
569
+ type = T::Hash[T::UINT32, T::UINT32].child
570
+ result = described_class.new(value, type: type)
571
+
572
+ expect(result.exact_value).to be_an(::Array)
573
+ expect(result.exact_value[0]).to be_a(DBus::Data::Base)
574
+ end
575
+
576
+ it "takes a plain value" do
577
+ input = ["test", 23]
578
+
579
+ type = T::Hash[String, T::INT16].child
580
+ value = described_class.new(input, type: type)
581
+
582
+ expect(value).to be_a(described_class)
583
+ expect(value.type.to_s).to eq "{sn}"
584
+ expect(value.value).to eql input
585
+ end
586
+ end
328
587
  end
329
588
 
330
589
  describe DBus::Data::Variant do
@@ -337,9 +596,42 @@ describe DBus::Data do
337
596
  expect(value.member_type.to_s).to eq "s"
338
597
  end
339
598
  end
340
- end
341
599
 
342
- describe DBus::Data::DictEntry do
600
+ describe "#initialize" do
601
+ it "takes a plain value" do
602
+ input = 42
603
+
604
+ type = DBus.type(T::INT16)
605
+ value = described_class.new(input, member_type: type)
606
+ expect(value).to be_a(described_class)
607
+ expect(value.type.to_s).to eq "v"
608
+ expect(value.member_type.to_s).to eq "n"
609
+ expect(value.value).to eq 42
610
+ end
611
+
612
+ # FIXME: verify that @value has the correct class
613
+ it "takes an exact value" do
614
+ input = DBus::Data::Int16.new(42)
615
+
616
+ type = DBus.type(T::INT16)
617
+ value = described_class.new(input, member_type: type)
618
+ expect(value).to be_a(described_class)
619
+ expect(value.type.to_s).to eq "v"
620
+ expect(value.member_type.to_s).to eq "n"
621
+ expect(value.value).to eq 42
622
+ end
623
+
624
+ it "checks the type of the exact value" do
625
+ input = DBus::Data::UInt16.new(42)
626
+
627
+ type = DBus.type(T::INT16)
628
+ expect { described_class.new(input, member_type: type) }
629
+ .to raise_error(ArgumentError, /Variant type n does not match value type q/)
630
+ end
631
+ end
632
+
633
+ include_examples "#== and #eql? work for container types (1 value)",
634
+ "/foo", { member_type: DBus.type(T::STRING) }
343
635
  end
344
636
  end
345
637
  end
@@ -48,14 +48,7 @@ RSpec.shared_examples "parses good data" do |cases|
48
48
  result = results.first
49
49
 
50
50
  expect(result).to be_a(DBus::Data::Base)
51
- if expected.is_a?(Hash)
52
- expect(result.value.size).to eq(expected.size)
53
- result.value.each_key do |result_key|
54
- expect(result.value[result_key]).to eq(expected[result_key.value])
55
- end
56
- else
57
- expect(result.value).to eq(expected)
58
- end
51
+ expect(result.value).to eq(expected)
59
52
 
60
53
  expect(remaining_buffer(subject)).to be_empty
61
54
  end
@@ -106,14 +99,7 @@ describe DBus::PacketUnmarshaller do
106
99
  result = results.first
107
100
 
108
101
  expect(result).to be_a(DBus::Data::Base)
109
- if expected.is_a?(Hash)
110
- expect(result.value.size).to eq(expected.size)
111
- result.value.each_key do |result_key|
112
- expect(result.value[result_key]).to eq(expected[result_key.value])
113
- end
114
- else
115
- expect(result.value).to eq(expected)
116
- end
102
+ expect(result.value).to eq(expected)
117
103
 
118
104
  expect(remaining_buffer(subject)).to be_empty
119
105
  end
data/spec/type_spec.rb CHANGED
@@ -82,6 +82,46 @@ describe DBus do
82
82
  end
83
83
 
84
84
  describe DBus::Type do
85
+ let(:as1) { DBus.type("as") }
86
+ let(:as2) { DBus.type("as") }
87
+ let(:aas) { DBus.type("aas") }
88
+
89
+ describe "#==" do
90
+ it "is true for same types" do
91
+ expect(as1).to eq(as2)
92
+ end
93
+
94
+ it "is true for a type and its string representation" do
95
+ expect(as1).to eq("as")
96
+ end
97
+
98
+ it "is false for different types" do
99
+ expect(as1).to_not eq(aas)
100
+ end
101
+
102
+ it "is false for a type and a different string" do
103
+ expect(as1).to_not eq("aas")
104
+ end
105
+ end
106
+
107
+ describe "#eql?" do
108
+ it "is true for same types" do
109
+ expect(as1).to eql(as2)
110
+ end
111
+
112
+ it "is false for a type and its string representation" do
113
+ expect(as1).to_not eql("as")
114
+ end
115
+
116
+ it "is false for different types" do
117
+ expect(as1).to_not eql(aas)
118
+ end
119
+
120
+ it "is false for a type and a different string" do
121
+ expect(as1).to_not eql("aas")
122
+ end
123
+ end
124
+
85
125
  describe "#<<" do
86
126
  it "raises if the argument is not a Type" do
87
127
  t = DBus::Type.new(DBus::Type::ARRAY)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-dbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0.beta5
4
+ version: 0.18.0.beta6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby DBus Team
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-27 00:00:00.000000000 Z
11
+ date: 2022-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml
@@ -202,7 +202,7 @@ homepage: https://github.com/mvidner/ruby-dbus
202
202
  licenses:
203
203
  - LGPL-2.1
204
204
  metadata: {}
205
- post_install_message:
205
+ post_install_message:
206
206
  rdoc_options: []
207
207
  require_paths:
208
208
  - lib
@@ -217,9 +217,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
217
  - !ruby/object:Gem::Version
218
218
  version: 1.3.1
219
219
  requirements: []
220
- rubyforge_project:
221
- rubygems_version: 2.7.6.3
222
- signing_key:
220
+ rubygems_version: 3.3.0.dev
221
+ signing_key:
223
222
  specification_version: 4
224
223
  summary: Ruby module for interaction with D-Bus
225
224
  test_files: []