ruby-dbus 0.18.0.beta5 → 0.18.0.beta8

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
@@ -64,7 +193,7 @@ RSpec.shared_examples "constructor rejects values from this list" do |bad_list|
64
193
  describe "#initialize" do
65
194
  bad_list.each do |(value, exc_class, msg_substr)|
66
195
  it "rejects #{value.inspect} with #{exc_class}: #{msg_substr}" do
67
- msg_re = Regexp.new(Regexp.quote(msg_substr))
196
+ msg_re = Regexp.try_convert(msg_substr) || Regexp.new(Regexp.quote(msg_substr))
68
197
  expect { described_class.new(value) }.to raise_error(exc_class, msg_re)
69
198
  end
70
199
  end
@@ -75,7 +204,7 @@ RSpec.shared_examples "constructor (kwargs) rejects values" do |bad_list|
75
204
  describe "#initialize" do
76
205
  bad_list.each do |(value, kwargs_hash, exc_class, msg_substr)|
77
206
  it "rejects #{value.inspect}, #{kwargs_hash.inspect} with #{exc_class}: #{msg_substr}" do
78
- msg_re = Regexp.new(Regexp.quote(msg_substr))
207
+ msg_re = Regexp.try_convert(msg_substr) || Regexp.new(Regexp.quote(msg_substr))
79
208
  expect { described_class.new(value, **kwargs_hash) }.to raise_error(exc_class, msg_re)
80
209
  end
81
210
  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
 
@@ -246,8 +387,9 @@ describe DBus::Data do
246
387
 
247
388
  describe "containers" do
248
389
  describe DBus::Data::Array do
390
+ aq = DBus::Data::Array.new([1, 2, 3], type: "aq")
391
+
249
392
  good = [
250
- # [[1, 2, 3], type: nil],
251
393
  [[1, 2, 3], { type: "aq" }],
252
394
  [[1, 2, 3], { type: T::Array[T::UINT16] }],
253
395
  [[1, 2, 3], { type: T::Array["q"] }],
@@ -257,11 +399,24 @@ describe DBus::Data do
257
399
 
258
400
  bad = [
259
401
  # undesirable type guessing
260
- ## [[1, 2, 3], { type: nil }, DBus::InvalidPacketException, "Unknown type code"],
261
- ## [[1, 2, 3], { type: "!" }, DBus::InvalidPacketException, "Unknown type code"]
262
- # TODO: others
402
+ [[1, 2, 3], { type: nil }, ArgumentError, /Expecting DBus::Type.*got nil/],
403
+ [[1, 2, 3], { type: "!" }, DBus::Type::SignatureException, "Unknown type code"],
404
+ [aq, { type: "q" }, ArgumentError, "Expecting \"a\""],
405
+ [aq, { type: "ao" }, ArgumentError,
406
+ "Specified type is ARRAY: [OBJECT_PATH] but value type is ARRAY: [UINT16]"]
407
+ # TODO: how to handle these?
408
+ # [{1 => 2, 3 => 4}, { type: "aq" }, ArgumentError, "?"],
409
+ # [/i am not an array/, { type: "aq" }, ArgumentError, "?"],
263
410
  ]
264
411
 
412
+ include_examples "#== and #eql? work for container types (inequal)",
413
+ [1, 2, 3], { type: "aq" },
414
+ [3, 2, 1], { type: "aq" }
415
+
416
+ include_examples "#== and #eql? work for container types (inequal)",
417
+ [[1, 2, 3]], { type: "aaq" },
418
+ [[3, 2, 1]], { type: "aaq" }
419
+
265
420
  include_examples "constructor (kwargs) accepts values", good
266
421
  include_examples "constructor (kwargs) rejects values", bad
267
422
 
@@ -315,6 +470,14 @@ describe DBus::Data do
315
470
  # TODO: others
316
471
  ]
317
472
 
473
+ include_examples "#== and #eql? work for container types (inequal)",
474
+ [1, 2, 3], { type: qqq },
475
+ [3, 2, 1], { type: qqq }
476
+
477
+ include_examples "#== and #eql? work for container types (equal)",
478
+ three_words.new(*integers), { type: qqq },
479
+ [1, 2, 3], { type: qqq }
480
+
318
481
  include_examples "constructor (kwargs) accepts values", good
319
482
  # include_examples "constructor (kwargs) rejects values", bad
320
483
 
@@ -325,6 +488,108 @@ describe DBus::Data do
325
488
  .to be_a(described_class)
326
489
  end
327
490
  end
491
+
492
+ describe "#initialize" do
493
+ it "converts type to Type" do
494
+ value = [1, 2, 3]
495
+ type = "(uuu)"
496
+ result = described_class.new(value, type: type)
497
+ expect(result.type).to be_a DBus::Type
498
+ end
499
+
500
+ it "checks that type matches class" do
501
+ value = [1, 2, 3]
502
+ type = T::Array[T::INT32]
503
+ expect { described_class.new(value, type: type) }
504
+ .to raise_error(ArgumentError, /Expecting "r"/)
505
+ end
506
+
507
+ it "checks type of a Data::Struct value" do
508
+ value1 = [1, 2, 3]
509
+ type1 = "(uuu)"
510
+ result1 = described_class.new(value1, type: type1)
511
+
512
+ value2 = result1
513
+ type2 = "(xxx)"
514
+ expect { described_class.new(value2, type: type2) }
515
+ .to raise_error(ArgumentError, /value type is STRUCT.*UINT32/)
516
+ end
517
+
518
+ it "checks that size of type and value match" do
519
+ value = [1, 2, 3, 4]
520
+ type = "(uuu)"
521
+ expect { described_class.new(value, type: type) }
522
+ .to raise_error(ArgumentError, /type has 3 members.*value has 4 members/)
523
+ end
524
+
525
+ it "converts value to ::Array of Data::Base" do
526
+ value = three_words.new(*integers)
527
+ type = T::Struct[T::INT32, T::INT32, T::INT32]
528
+ result = described_class.new(value, type: type)
529
+
530
+ expect(result.exact_value).to be_an(::Array)
531
+ expect(result.exact_value[0]).to be_a(DBus::Data::Base)
532
+ end
533
+ end
534
+ end
535
+
536
+ describe DBus::Data::DictEntry do
537
+ describe ".from_typed" do
538
+ it "creates new instance from given object and type" do
539
+ type = T::Hash[String, T::INT16].child
540
+ expect(described_class.from_typed(["test", 12], type: type))
541
+ .to be_a(described_class)
542
+ end
543
+ end
544
+
545
+ describe "#initialize" do
546
+ it "checks that type matches class" do
547
+ value = [1, 2]
548
+ type = T::Array[T::INT32]
549
+
550
+ expect { described_class.new(value, type: type) }
551
+ .to raise_error(ArgumentError, /Expecting "e"/)
552
+ end
553
+
554
+ it "checks type of a Data::DictEntry value" do
555
+ value1 = [1, 2]
556
+ type1 = T::Hash[T::UINT32, T::UINT32].child
557
+ result1 = described_class.new(value1, type: type1)
558
+
559
+ value2 = result1
560
+ type2 = T::Hash[T::UINT64, T::UINT64].child
561
+ expect { described_class.new(value2, type: type2) }
562
+ .to raise_error(ArgumentError, /value type is DICT_ENTRY.*UINT32/)
563
+ end
564
+
565
+ it "checks that size of type and value match" do
566
+ value = [1, 2, 3]
567
+ type = T::Hash[T::UINT32, T::UINT32].child
568
+ expect { described_class.new(value, type: type) }
569
+ .to raise_error(ArgumentError, /type has 2 members.*value has 3 members/)
570
+ end
571
+
572
+ it "converts value to ::Array of Data::Base" do
573
+ two_words = ::Struct.new(:k, :v)
574
+ value = two_words.new(1, 2)
575
+ type = T::Hash[T::UINT32, T::UINT32].child
576
+ result = described_class.new(value, type: type)
577
+
578
+ expect(result.exact_value).to be_an(::Array)
579
+ expect(result.exact_value[0]).to be_a(DBus::Data::Base)
580
+ end
581
+
582
+ it "takes a plain value" do
583
+ input = ["test", 23]
584
+
585
+ type = T::Hash[String, T::INT16].child
586
+ value = described_class.new(input, type: type)
587
+
588
+ expect(value).to be_a(described_class)
589
+ expect(value.type.to_s).to eq "{sn}"
590
+ expect(value.value).to eql input
591
+ end
592
+ end
328
593
  end
329
594
 
330
595
  describe DBus::Data::Variant do
@@ -337,9 +602,72 @@ describe DBus::Data do
337
602
  expect(value.member_type.to_s).to eq "s"
338
603
  end
339
604
  end
340
- end
341
605
 
342
- describe DBus::Data::DictEntry do
606
+ describe "#initialize" do
607
+ it "takes a plain value" do
608
+ input = 42
609
+
610
+ type = DBus.type(T::INT16)
611
+ value = described_class.new(input, member_type: type)
612
+ expect(value).to be_a(described_class)
613
+ expect(value.type.to_s).to eq "v"
614
+ expect(value.member_type.to_s).to eq "n"
615
+ expect(value.value).to eq 42
616
+ end
617
+
618
+ # FIXME: verify that @value has the correct class
619
+ it "takes an exact value" do
620
+ input = DBus::Data::Int16.new(42)
621
+
622
+ type = DBus.type(T::INT16)
623
+ value = described_class.new(input, member_type: type)
624
+ expect(value).to be_a(described_class)
625
+ expect(value.type.to_s).to eq "v"
626
+ expect(value.member_type.to_s).to eq "n"
627
+ expect(value.value).to eq 42
628
+ end
629
+
630
+ it "checks the type of the exact value" do
631
+ input = DBus::Data::UInt16.new(42)
632
+
633
+ type = DBus.type(T::INT16)
634
+ expect { described_class.new(input, member_type: type) }
635
+ .to raise_error(ArgumentError, /Variant type n does not match value type q/)
636
+ end
637
+ end
638
+
639
+ include_examples "#== and #eql? work for container types (1 value)",
640
+ "/foo", { member_type: DBus.type(T::STRING) }
641
+
642
+ describe "DBus.variant compatibility" do
643
+ let(:v) { DBus.variant("o", "/foo") }
644
+
645
+ describe "#[]" do
646
+ it "returns the type for 0" do
647
+ expect(v[0]).to eq DBus.type(DBus::Type::OBJECT_PATH)
648
+ end
649
+
650
+ it "returns the value for 1" do
651
+ expect(v[1]).to eq DBus::ObjectPath.new("/foo")
652
+ end
653
+
654
+ it "returns an error for other indices" do
655
+ expect { v[2] }.to raise_error(ArgumentError, /DBus.variant can only be indexed with 0 or 1/)
656
+ end
657
+ end
658
+
659
+ describe "#first" do
660
+ it "returns the type" do
661
+ expect(v.first).to eq DBus.type(DBus::Type::OBJECT_PATH)
662
+ end
663
+ end
664
+
665
+ describe "#last" do
666
+ it "returns the value" do
667
+ expect(v.last).to eq DBus::ObjectPath.new("/foo")
668
+ end
669
+ end
670
+ end
343
671
  end
344
672
  end
345
673
  end
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ describe DBus::EmitsChangedSignal do
8
+ describe "#initialize" do
9
+ it "accepts a simple value" do
10
+ expect(described_class.new(:const).value).to eq :const
11
+ end
12
+
13
+ it "avoids nil by asking the interface" do
14
+ ifc = DBus::Interface.new("org.example.Foo")
15
+ ifc.emits_changed_signal = described_class.new(:invalidates)
16
+
17
+ expect(described_class.new(nil, interface: ifc).value).to eq :invalidates
18
+ end
19
+
20
+ it "fails for unknown value" do
21
+ expect { described_class.new(:huh) }.to raise_error(ArgumentError, /Seen :huh/)
22
+ end
23
+
24
+ it "fails for 2 nils" do
25
+ expect { described_class.new(nil, interface: nil) }.to raise_error(ArgumentError, /Both/)
26
+ end
27
+ end
28
+
29
+ describe "#==" do
30
+ it "is true for two different objects with the same value" do
31
+ const_a = described_class.new(:const)
32
+ const_b = described_class.new(:const)
33
+ expect(const_a == const_b).to be true
34
+ end
35
+ end
36
+
37
+ describe "#to_xml" do
38
+ it "uses a string value" do
39
+ expect(described_class.new(:const).to_xml)
40
+ .to eq " <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n"
41
+ end
42
+ end
43
+
44
+ describe "#to_s" do
45
+ it "uses a string value" do
46
+ expect(described_class.new(:const).to_s).to eq "const"
47
+ end
48
+ end
49
+ end
50
+
51
+ describe DBus::Interface do
52
+ describe ".emits_changed_signal=" do
53
+ it "only allows an EmitsChangedSignal as argument" do
54
+ ifc = described_class.new("org.ruby.Interface")
55
+ expect { ifc.emits_changed_signal = :const }.to raise_error(TypeError)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ class ObjectTest < DBus::Object
8
+ T = DBus::Type unless const_defined? "T"
9
+
10
+ dbus_interface "org.ruby.ServerTest" do
11
+ dbus_attr_writer :write_me, T::Struct[String, String]
12
+
13
+ attr_accessor :read_only_for_dbus
14
+
15
+ dbus_reader :read_only_for_dbus, T::STRING, emits_changed_signal: :invalidates
16
+ end
17
+ end
18
+
19
+ describe DBus::Object do
20
+ describe ".dbus_attr_writer" do
21
+ describe "the declared assignment method" do
22
+ # Slightly advanced RSpec:
23
+ # https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html#satisfy-instance_method
24
+ let(:a_struct_in_a_variant) do
25
+ satisfying { |x| x.is_a?(DBus::Data::Variant) && x.member_type.to_s == "(ss)" }
26
+ # ^ This formatting keeps the matcher on a single line
27
+ # which enables RSpec to cite it if it fails, instead of saying "block".
28
+ end
29
+
30
+ it "emits PropertyChanged with correctly typed argument" do
31
+ obj = ObjectTest.new("/test")
32
+ expect(obj).to receive(:PropertiesChanged).with(
33
+ "org.ruby.ServerTest",
34
+ {
35
+ "WriteMe" => a_struct_in_a_variant
36
+ },
37
+ []
38
+ )
39
+ # bug: call PC with simply the assigned value,
40
+ # which will need type guessing
41
+ obj.write_me = ["two", "strings"]
42
+ end
43
+ end
44
+ end
45
+
46
+ describe ".dbus_accessor" do
47
+ it "can only be used within a dbus_interface" do
48
+ expect do
49
+ ObjectTest.instance_exec do
50
+ dbus_accessor :foo, DBus::Type::STRING
51
+ end
52
+ end.to raise_error(DBus::Object::UndefinedInterface)
53
+ end
54
+ end
55
+
56
+ describe ".dbus_reader" do
57
+ it "can only be used within a dbus_interface" do
58
+ expect do
59
+ ObjectTest.instance_exec do
60
+ dbus_reader :foo, DBus::Type::STRING
61
+ end
62
+ end.to raise_error(DBus::Object::UndefinedInterface)
63
+ end
64
+ end
65
+
66
+ describe ".dbus_reader, when paired with attr_accessor" do
67
+ describe "the declared assignment method" do
68
+ it "emits PropertyChanged" do
69
+ obj = ObjectTest.new("/test")
70
+ expect(obj).to receive(:PropertiesChanged).with(
71
+ "org.ruby.ServerTest",
72
+ {},
73
+ ["ReadOnlyForDbus"]
74
+ )
75
+ obj.read_only_for_dbus = "myvalue"
76
+ end
77
+ end
78
+ end
79
+
80
+ describe ".dbus_writer" do
81
+ it "can only be used within a dbus_interface" do
82
+ expect do
83
+ ObjectTest.instance_exec do
84
+ dbus_writer :foo, DBus::Type::STRING
85
+ end
86
+ end.to raise_error(DBus::Object::UndefinedInterface)
87
+ end
88
+ end
89
+
90
+ describe ".dbus_watcher" do
91
+ it "can only be used within a dbus_interface" do
92
+ expect do
93
+ ObjectTest.instance_exec do
94
+ dbus_watcher :foo
95
+ end
96
+ end.to raise_error(DBus::Object::UndefinedInterface)
97
+ end
98
+ end
99
+
100
+ describe ".dbus_method" do
101
+ it "can only be used within a dbus_interface" do
102
+ expect do
103
+ ObjectTest.instance_exec do
104
+ dbus_method :foo do
105
+ end
106
+ end
107
+ end.to raise_error(DBus::Object::UndefinedInterface)
108
+ end
109
+ end
110
+
111
+ describe ".emits_changed_signal" do
112
+ it "raises UndefinedInterface when so" do
113
+ expect { ObjectTest.emits_changed_signal = false }
114
+ .to raise_error DBus::Object::UndefinedInterface
115
+ end
116
+
117
+ it "assigns to the current interface" do
118
+ ObjectTest.instance_exec do
119
+ dbus_interface "org.ruby.Interface" do
120
+ self.emits_changed_signal = false
121
+ end
122
+ end
123
+ ecs = ObjectTest.intfs["org.ruby.Interface"].emits_changed_signal
124
+ expect(ecs).to eq false
125
+ end
126
+
127
+ it "only can be assigned once" do
128
+ expect do
129
+ Class.new(DBus::Object) do
130
+ dbus_interface "org.ruby.Interface" do
131
+ self.emits_changed_signal = false
132
+ self.emits_changed_signal = :invalidates
133
+ end
134
+ end
135
+ end.to raise_error(RuntimeError, /assigned more than once/)
136
+ end
137
+ end
138
+ end