ruby-dbus 0.18.0.beta3 → 0.18.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
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