ruby-dbus 0.18.0.beta3 → 0.18.0.beta6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -85,42 +214,51 @@ end
85
214
  # TODO: Look at conversions? to_str, to_int?
86
215
 
87
216
  describe DBus::Data do
217
+ T = DBus::Type unless const_defined? "T"
218
+
88
219
  # test initialization, from user code, or from packet (from_raw)
89
220
  # remember to unpack if initializing from Data::Base
90
221
  # #value should recurse inside so that the user doesnt have to
91
222
  # Kick InvalidPacketException out of here?
92
223
 
93
224
  describe DBus::Data::Byte do
225
+ include_examples "#== and #eql? work for basic types"
94
226
  include_examples "constructor accepts numeric range", 0, 2**8 - 1
95
227
  include_examples "constructor accepts plain or typed values", 42
96
228
  end
97
229
 
98
230
  describe DBus::Data::Int16 do
231
+ include_examples "#== and #eql? work for basic types"
99
232
  include_examples "constructor accepts numeric range", -2**15, 2**15 - 1
100
233
  include_examples "constructor accepts plain or typed values", 42
101
234
  end
102
235
 
103
236
  describe DBus::Data::UInt16 do
237
+ include_examples "#== and #eql? work for basic types"
104
238
  include_examples "constructor accepts numeric range", 0, 2**16 - 1
105
239
  include_examples "constructor accepts plain or typed values", 42
106
240
  end
107
241
 
108
242
  describe DBus::Data::Int32 do
243
+ include_examples "#== and #eql? work for basic types"
109
244
  include_examples "constructor accepts numeric range", -2**31, 2**31 - 1
110
245
  include_examples "constructor accepts plain or typed values", 42
111
246
  end
112
247
 
113
248
  describe DBus::Data::UInt32 do
249
+ include_examples "#== and #eql? work for basic types"
114
250
  include_examples "constructor accepts numeric range", 0, 2**32 - 1
115
251
  include_examples "constructor accepts plain or typed values", 42
116
252
  end
117
253
 
118
254
  describe DBus::Data::Int64 do
255
+ include_examples "#== and #eql? work for basic types"
119
256
  include_examples "constructor accepts numeric range", -2**63, 2**63 - 1
120
257
  include_examples "constructor accepts plain or typed values", 42
121
258
  end
122
259
 
123
260
  describe DBus::Data::UInt64 do
261
+ include_examples "#== and #eql? work for basic types"
124
262
  include_examples "constructor accepts numeric range", 0, 2**64 - 1
125
263
  include_examples "constructor accepts plain or typed values", 42
126
264
  end
@@ -140,10 +278,12 @@ describe DBus::Data do
140
278
  end
141
279
  end
142
280
 
281
+ include_examples "#== and #eql? work for basic types", false, true
143
282
  include_examples "constructor accepts plain or typed values", false
144
283
  end
145
284
 
146
285
  describe DBus::Data::Double do
286
+ include_examples "#== and #eql? work for basic types"
147
287
  include_examples "constructor accepts plain or typed values", Math::PI
148
288
 
149
289
  describe "#initialize" do
@@ -181,6 +321,7 @@ describe DBus::Data do
181
321
  ["\xF4\x90\xC0\xC0", DBus::InvalidPacketException, "not in UTF-8"]
182
322
  ]
183
323
 
324
+ include_examples "#== and #eql? work for basic types", "foo", "bar"
184
325
  include_examples "constructor accepts plain or typed values", good
185
326
  include_examples "constructor rejects values from this list", bad
186
327
 
@@ -204,6 +345,7 @@ describe DBus::Data do
204
345
  # TODO: others
205
346
  ]
206
347
 
348
+ include_examples "#== and #eql? work for basic types", "/foo", "/bar"
207
349
  include_examples "constructor accepts plain or typed values", good
208
350
  include_examples "constructor rejects values from this list", bad
209
351
 
@@ -229,6 +371,7 @@ describe DBus::Data do
229
371
  # TODO: others
230
372
  ]
231
373
 
374
+ include_examples "#== and #eql? work for basic types", "aah", "aaaaah"
232
375
  include_examples "constructor accepts plain or typed values", good
233
376
  include_examples "constructor rejects values from this list", bad
234
377
 
@@ -245,28 +388,36 @@ describe DBus::Data do
245
388
  describe "containers" do
246
389
  describe DBus::Data::Array do
247
390
  good = [
248
- # [[1, 2, 3], member_type: nil],
249
- [[1, 2, 3], { member_type: "q" }],
250
- [[1, 2, 3], { member_type: DBus::Type::UINT16 }],
251
- [[1, 2, 3], { member_type: DBus.type("q") }],
252
- [[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], { member_type: "q" }]
391
+ # [[1, 2, 3], type: nil],
392
+ [[1, 2, 3], { type: "aq" }],
393
+ [[1, 2, 3], { type: T::Array[T::UINT16] }],
394
+ [[1, 2, 3], { type: T::Array["q"] }],
395
+ [[DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)], { type: T::Array["q"] }]
253
396
  # TODO: others
254
397
  ]
255
398
 
256
399
  bad = [
257
400
  # undesirable type guessing
258
- ## [[1, 2, 3], { member_type: nil }, DBus::InvalidPacketException, "Unknown type code"],
259
- ## [[1, 2, 3], { member_type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
401
+ ## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"],
402
+ ## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
260
403
  # TODO: others
261
404
  ]
262
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
+
263
414
  include_examples "constructor (kwargs) accepts values", good
264
415
  include_examples "constructor (kwargs) rejects values", bad
265
416
 
266
417
  describe ".from_typed" do
267
418
  it "creates new instance from given object and type" do
268
- type = DBus::Type.new("s")
269
- expect(described_class.from_typed(["test", "lest"], member_types: [type])).to be_a(described_class)
419
+ type = T::Array[String]
420
+ expect(described_class.from_typed(["test", "lest"], type: type)).to be_a(described_class)
270
421
  end
271
422
  end
272
423
  end
@@ -274,7 +425,7 @@ describe DBus::Data do
274
425
  describe DBus::Data::Struct do
275
426
  three_words = ::Struct.new(:a, :b, :c)
276
427
 
277
- qqq = ["q", "q", "q"]
428
+ qqq = T::Struct[T::UINT16, T::UINT16, T::UINT16]
278
429
  integers = [1, 2, 3]
279
430
  uints = [DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)]
280
431
 
@@ -291,63 +442,196 @@ describe DBus::Data do
291
442
  # TODO: also check data ownership: reasonable to own the data?
292
443
  # can make it explicit?
293
444
  good = [
294
- # from plain array; various m_t styles
295
- [integers, { member_types: ["q", "q", "q"] }],
296
- [integers, { member_types: [DBus::Type::UINT16, DBus::Type::UINT16, DBus::Type::UINT16] }],
297
- [integers, { member_types: DBus.types("qqq") }],
445
+ # from plain array; various *type* styles
446
+ [integers, { type: DBus.type("(qqq)") }],
447
+ [integers, { type: T::Struct["q", "q", "q"] }],
448
+ [integers, { type: T::Struct[T::UINT16, T::UINT16, T::UINT16] }],
449
+ [integers, { type: T::Struct[*DBus.types("qqq")] }],
298
450
  # plain array of data
299
- [uints, { member_types: DBus.types("qqq") }],
451
+ [uints, { type: qqq }],
300
452
  # ::Struct
301
- [three_words.new(*integers), { member_types: qqq }],
302
- [three_words.new(*uints), { member_types: qqq }]
453
+ [three_words.new(*integers), { type: qqq }],
454
+ [three_words.new(*uints), { type: qqq }]
303
455
  # TODO: others
304
456
  ]
305
457
 
458
+ # check these only when canonicalizing @value, because that will
459
+ # type-check the value deeply
306
460
  _bad_but_valid = [
307
- # Wrong member_types arg:
308
- # hmm this is another reason to pass the type
309
- # as the entire struct type, not the members:
310
- # empty struct will be caught naturally
311
- [integers, { member_types: [] }, ArgumentError, "???"],
312
- [integers, { member_types: ["!"] }, DBus::InvalidPacketException, "Unknown type code"],
313
461
  # STRUCT specific: member count mismatch
314
- [[1, 2], { member_types: DBus.types("qqq") }, ArgumentError, "???"],
315
- [[1, 2, 3, 4], { member_types: DBus.types("qqq") }, ArgumentError, "???"]
462
+ [[1, 2], { type: qqq }, ArgumentError, "???"],
463
+ [[1, 2, 3, 4], { type: qqq }, ArgumentError, "???"]
316
464
  # TODO: others
317
465
  ]
318
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
+
319
475
  include_examples "constructor (kwargs) accepts values", good
320
476
  # include_examples "constructor (kwargs) rejects values", bad
321
477
 
322
478
  describe ".from_typed" do
323
479
  it "creates new instance from given object and type" do
324
- type = DBus::Type.new("s")
325
- expect(described_class.from_typed(["test", "lest"].freeze, member_types: [type, type]))
480
+ type = T::Struct[T::STRING, T::STRING]
481
+ expect(described_class.from_typed(["test", "lest"].freeze, type: type))
326
482
  .to be_a(described_class)
327
483
  end
328
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
329
528
  end
330
529
 
331
- describe DBus::Data::Variant do
530
+ describe DBus::Data::DictEntry do
332
531
  describe ".from_typed" do
333
532
  it "creates new instance from given object and type" do
334
- type = DBus::Type.new("s")
335
- expect(described_class.from_typed("test", member_types: [type])).to be_a(described_class)
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
336
585
  end
586
+ end
587
+ end
337
588
 
338
- it "ignores the member_types argument" do
339
- type = DBus::Type.new("s")
340
- # Base.from_typed is a generic interface with a fixed signature;
341
- # So it must offer the member_types parameter, which is misleading
342
- # for a Variant
343
- value = described_class.from_typed("test", member_types: [type])
589
+ describe DBus::Data::Variant do
590
+ describe ".from_typed" do
591
+ it "creates new instance from given object and type" do
592
+ type = DBus.type(T::VARIANT)
593
+ value = described_class.from_typed("test", type: type)
594
+ expect(value).to be_a(described_class)
344
595
  expect(value.type.to_s).to eq "v"
345
596
  expect(value.member_type.to_s).to eq "s"
346
597
  end
347
598
  end
348
- end
349
599
 
350
- 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) }
351
635
  end
352
636
  end
353
637
  end
@@ -29,6 +29,13 @@ describe DBus::PacketMarshaller do
29
29
  subject.append(signature, t.val)
30
30
  expect(subject.packet).to eq(expected)
31
31
  end
32
+
33
+ it "writes a '#{signature}' with typed value #{t.val.inspect} (#{endianness})" do
34
+ subject = described_class.new(endianness: endianness)
35
+ typed_val = DBus::Data.make_typed(signature, t.val)
36
+ subject.append(signature, typed_val)
37
+ expect(subject.packet).to eq(expected)
38
+ end
32
39
  end
33
40
  end
34
41
  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
@@ -4,6 +4,14 @@
4
4
  require_relative "spec_helper"
5
5
  require "dbus"
6
6
 
7
+ # FIXME: factor out DBus::TestFixtures::Value in spec_helper
8
+ require "ostruct"
9
+ require "yaml"
10
+
11
+ data_dir = File.expand_path("data", __dir__)
12
+ marshall_yaml_s = File.read("#{data_dir}/marshall.yaml")
13
+ marshall_yaml = YAML.safe_load(marshall_yaml_s)
14
+
7
15
  describe "PropertyTest" do
8
16
  before(:each) do
9
17
  @session_bus = DBus::ASessionBus.new
@@ -155,7 +163,7 @@ describe "PropertyTest" do
155
163
  end
156
164
  end
157
165
 
158
- context "an dict-typed property" do
166
+ context "a dict-typed property" do
159
167
  it "gets read as a hash" do
160
168
  val = @iface["MyDict"]
161
169
  expect(val).to eq({
@@ -164,12 +172,50 @@ describe "PropertyTest" do
164
172
  "three" => [3, 3, 3]
165
173
  })
166
174
  end
175
+
176
+ it "Get returns the correctly typed value (check with dbus-send)" do
177
+ cmd = "dbus-send --print-reply " \
178
+ "--dest=org.ruby.service " \
179
+ "/org/ruby/MyInstance " \
180
+ "org.freedesktop.DBus.Properties.Get " \
181
+ "string:org.ruby.SampleInterface " \
182
+ "string:MyDict"
183
+ reply = `#{cmd}`
184
+ # a bug about variant nesting lead to a "variant variant int32 1" value
185
+ match_rx = /variant \s+ array \s \[ \s+
186
+ dict \s entry\( \s+
187
+ string \s "one" \s+
188
+ variant \s+ int32 \s 1 \s+
189
+ \)/x
190
+ expect(reply).to match(match_rx)
191
+ end
167
192
  end
168
193
 
169
194
  context "a variant-typed property" do
170
195
  it "gets read at all" do
171
- val = @iface["MyVariant"]
196
+ obj = @svc.object("/org/ruby/MyDerivedInstance")
197
+ iface = obj["org.ruby.SampleInterface"]
198
+ val = iface["MyVariant"]
172
199
  expect(val).to eq([42, 43])
173
200
  end
174
201
  end
202
+
203
+ context "marshall.yaml round-trip via a VARIANT property" do
204
+ marshall_yaml.each do |test|
205
+ t = OpenStruct.new(test)
206
+ next if t.val.nil?
207
+
208
+ # Round trips do not work yet because the properties
209
+ # must present a plain Ruby value so the exact D-Bus type is lost.
210
+ # Round trips will work once users can declare accepting DBus::Data
211
+ # in properties and method arguments.
212
+ it "Sets #{t.sig.inspect}:#{t.val.inspect} and Gets something back" do
213
+ before = DBus::Data.make_typed(t.sig, t.val)
214
+ expect { @iface["MyVariant"] = before }.to_not raise_error
215
+ expect { _after = @iface["MyVariant"] }.to_not raise_error
216
+ # round-trip:
217
+ # expect(after).to eq(before.value)
218
+ end
219
+ end
220
+ end
175
221
  end
@@ -107,10 +107,10 @@ class Test < DBus::Object
107
107
  end
108
108
  dbus_reader :explosive, "s"
109
109
 
110
- dbus_attr_reader :my_struct, "(sss)"
111
- dbus_attr_reader :my_array, "aq"
112
- dbus_attr_reader :my_dict, "a{sv}"
113
- dbus_attr_reader :my_variant, "v"
110
+ dbus_attr_accessor :my_struct, "(sss)"
111
+ dbus_attr_accessor :my_array, "aq"
112
+ dbus_attr_accessor :my_dict, "a{sv}"
113
+ dbus_attr_accessor :my_variant, "v"
114
114
  end
115
115
 
116
116
  # closing and reopening the same interface