ruby-dbus 0.17.0 → 0.18.0.beta3

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +38 -0
  3. data/README.md +1 -1
  4. data/Rakefile +3 -11
  5. data/VERSION +1 -1
  6. data/doc/Reference.md +10 -3
  7. data/examples/doc/_extract_examples +2 -0
  8. data/examples/gdbus/gdbus +11 -5
  9. data/examples/no-introspect/nm-test.rb +2 -0
  10. data/examples/no-introspect/tracker-test.rb +3 -1
  11. data/examples/rhythmbox/playpause.rb +2 -1
  12. data/examples/service/call_service.rb +1 -0
  13. data/examples/service/complex-property.rb +21 -0
  14. data/examples/service/service_newapi.rb +1 -1
  15. data/examples/simple/call_introspect.rb +1 -0
  16. data/examples/simple/get_id.rb +2 -1
  17. data/examples/simple/properties.rb +2 -0
  18. data/examples/utils/listnames.rb +1 -0
  19. data/examples/utils/notify.rb +1 -0
  20. data/lib/dbus/api_options.rb +9 -0
  21. data/lib/dbus/auth.rb +12 -7
  22. data/lib/dbus/bus.rb +114 -70
  23. data/lib/dbus/bus_name.rb +12 -8
  24. data/lib/dbus/data.rb +744 -0
  25. data/lib/dbus/error.rb +4 -2
  26. data/lib/dbus/introspect.rb +30 -18
  27. data/lib/dbus/logger.rb +3 -1
  28. data/lib/dbus/marshall.rb +229 -293
  29. data/lib/dbus/matchrule.rb +16 -16
  30. data/lib/dbus/message.rb +44 -37
  31. data/lib/dbus/message_queue.rb +10 -5
  32. data/lib/dbus/object.rb +36 -15
  33. data/lib/dbus/object_path.rb +11 -6
  34. data/lib/dbus/proxy_object.rb +18 -4
  35. data/lib/dbus/proxy_object_factory.rb +11 -7
  36. data/lib/dbus/proxy_object_interface.rb +26 -22
  37. data/lib/dbus/raw_message.rb +91 -0
  38. data/lib/dbus/type.rb +164 -80
  39. data/lib/dbus/xml.rb +28 -17
  40. data/lib/dbus.rb +13 -7
  41. data/ruby-dbus.gemspec +4 -2
  42. data/spec/async_spec.rb +2 -0
  43. data/spec/binding_spec.rb +2 -0
  44. data/spec/bus_and_xml_backend_spec.rb +2 -0
  45. data/spec/bus_driver_spec.rb +2 -0
  46. data/spec/bus_name_spec.rb +3 -1
  47. data/spec/bus_spec.rb +2 -0
  48. data/spec/byte_array_spec.rb +2 -0
  49. data/spec/client_robustness_spec.rb +4 -2
  50. data/spec/data/marshall.yaml +1639 -0
  51. data/spec/data_spec.rb +353 -0
  52. data/spec/err_msg_spec.rb +2 -0
  53. data/spec/introspect_xml_parser_spec.rb +2 -0
  54. data/spec/introspection_spec.rb +2 -0
  55. data/spec/main_loop_spec.rb +2 -0
  56. data/spec/node_spec.rb +23 -0
  57. data/spec/object_path_spec.rb +3 -0
  58. data/spec/packet_marshaller_spec.rb +34 -0
  59. data/spec/packet_unmarshaller_spec.rb +262 -0
  60. data/spec/property_spec.rb +60 -2
  61. data/spec/proxy_object_spec.rb +2 -0
  62. data/spec/server_robustness_spec.rb +2 -0
  63. data/spec/server_spec.rb +2 -0
  64. data/spec/service_newapi.rb +37 -4
  65. data/spec/session_bus_spec.rb +3 -1
  66. data/spec/session_bus_spec_manual.rb +2 -0
  67. data/spec/signal_spec.rb +2 -0
  68. data/spec/spec_helper.rb +19 -3
  69. data/spec/thread_safety_spec.rb +2 -0
  70. data/spec/type_spec.rb +69 -6
  71. data/spec/value_spec.rb +16 -1
  72. data/spec/variant_spec.rb +4 -2
  73. data/spec/zzz_quit_spec.rb +16 -0
  74. metadata +16 -7
data/spec/data_spec.rb ADDED
@@ -0,0 +1,353 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ # The from_raw methods are tested in packet_unmarshaller_spec.rb
8
+
9
+ RSpec.shared_examples "constructor accepts numeric range" do |min, max|
10
+ describe "#initialize" do
11
+ it "accepts the min value #{min}" do
12
+ expect(described_class.new(min).value).to eq(min)
13
+ end
14
+
15
+ it "accepts the max value #{max}" do
16
+ expect(described_class.new(max).value).to eq(max)
17
+ end
18
+
19
+ it "raises on too small a value #{min - 1}" do
20
+ expect { described_class.new(min - 1) }.to raise_error(RangeError)
21
+ end
22
+
23
+ it "raises on too big a value #{max + 1}" do
24
+ expect { described_class.new(max + 1) }.to raise_error(RangeError)
25
+ end
26
+
27
+ it "raises on nil" do
28
+ expect { described_class.new(nil) }.to raise_error(RangeError)
29
+ end
30
+ end
31
+ end
32
+
33
+ RSpec.shared_examples "constructor accepts plain or typed values" do |plain_list|
34
+ describe "#initialize" do
35
+ Array(plain_list).each do |plain|
36
+ it "accepts the plain value #{plain.inspect}" do
37
+ expect(described_class.new(plain).value).to eq(plain)
38
+ end
39
+
40
+ it "accepts the typed value #{plain.inspect}" do
41
+ typed = described_class.new(plain)
42
+ expect(described_class.new(typed).value).to eq(plain)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ RSpec.shared_examples "constructor (kwargs) accepts values" do |list|
49
+ describe "#initialize" do
50
+ list.each do |value, kwargs_hash|
51
+ it "accepts the plain value #{value.inspect}, #{kwargs_hash.inspect}" do
52
+ expect(described_class.new(value, **kwargs_hash).value).to eq(value)
53
+ end
54
+
55
+ it "accepts the typed value #{value.inspect}, #{kwargs_hash.inspect}" do
56
+ typed = described_class.new(value, **kwargs_hash)
57
+ expect(described_class.new(typed, **kwargs_hash).value).to eq(value)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ RSpec.shared_examples "constructor rejects values from this list" do |bad_list|
64
+ describe "#initialize" do
65
+ bad_list.each do |(value, exc_class, msg_substr)|
66
+ it "rejects #{value.inspect} with #{exc_class}: #{msg_substr}" do
67
+ msg_re = Regexp.new(Regexp.quote(msg_substr))
68
+ expect { described_class.new(value) }.to raise_error(exc_class, msg_re)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ RSpec.shared_examples "constructor (kwargs) rejects values" do |bad_list|
75
+ describe "#initialize" do
76
+ bad_list.each do |(value, kwargs_hash, exc_class, msg_substr)|
77
+ it "rejects #{value.inspect}, #{kwargs_hash.inspect} with #{exc_class}: #{msg_substr}" do
78
+ msg_re = Regexp.new(Regexp.quote(msg_substr))
79
+ expect { described_class.new(value, **kwargs_hash) }.to raise_error(exc_class, msg_re)
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ # TODO: Look at conversions? to_str, to_int?
86
+
87
+ describe DBus::Data do
88
+ # test initialization, from user code, or from packet (from_raw)
89
+ # remember to unpack if initializing from Data::Base
90
+ # #value should recurse inside so that the user doesnt have to
91
+ # Kick InvalidPacketException out of here?
92
+
93
+ describe DBus::Data::Byte do
94
+ include_examples "constructor accepts numeric range", 0, 2**8 - 1
95
+ include_examples "constructor accepts plain or typed values", 42
96
+ end
97
+
98
+ describe DBus::Data::Int16 do
99
+ include_examples "constructor accepts numeric range", -2**15, 2**15 - 1
100
+ include_examples "constructor accepts plain or typed values", 42
101
+ end
102
+
103
+ describe DBus::Data::UInt16 do
104
+ include_examples "constructor accepts numeric range", 0, 2**16 - 1
105
+ include_examples "constructor accepts plain or typed values", 42
106
+ end
107
+
108
+ describe DBus::Data::Int32 do
109
+ include_examples "constructor accepts numeric range", -2**31, 2**31 - 1
110
+ include_examples "constructor accepts plain or typed values", 42
111
+ end
112
+
113
+ describe DBus::Data::UInt32 do
114
+ include_examples "constructor accepts numeric range", 0, 2**32 - 1
115
+ include_examples "constructor accepts plain or typed values", 42
116
+ end
117
+
118
+ describe DBus::Data::Int64 do
119
+ include_examples "constructor accepts numeric range", -2**63, 2**63 - 1
120
+ include_examples "constructor accepts plain or typed values", 42
121
+ end
122
+
123
+ describe DBus::Data::UInt64 do
124
+ include_examples "constructor accepts numeric range", 0, 2**64 - 1
125
+ include_examples "constructor accepts plain or typed values", 42
126
+ end
127
+
128
+ describe DBus::Data::Boolean do
129
+ describe "#initialize" do
130
+ it "accepts false and true" do
131
+ expect(described_class.new(false).value).to eq(false)
132
+ expect(described_class.new(true).value).to eq(true)
133
+ end
134
+
135
+ it "accepts truth value of other objects" do
136
+ expect(described_class.new(nil).value).to eq(false)
137
+ expect(described_class.new(0).value).to eq(true) # !
138
+ expect(described_class.new(1).value).to eq(true)
139
+ expect(described_class.new(Time.now).value).to eq(true)
140
+ end
141
+ end
142
+
143
+ include_examples "constructor accepts plain or typed values", false
144
+ end
145
+
146
+ describe DBus::Data::Double do
147
+ include_examples "constructor accepts plain or typed values", Math::PI
148
+
149
+ describe "#initialize" do
150
+ it "raises on values that can't be made a Float" do
151
+ expect { described_class.new(nil) }.to raise_error(TypeError)
152
+ expect { described_class.new("one") }.to raise_error(ArgumentError)
153
+ expect { described_class.new(/itsaregexp/) }.to raise_error(TypeError)
154
+ end
155
+ end
156
+ end
157
+
158
+ describe "basic, string-like types" do
159
+ describe DBus::Data::String do
160
+ # TODO: what about strings with good codepoints but encoded in
161
+ # let's say Encoding::ISO8859_2?
162
+ good = [
163
+ "",
164
+ "Ř",
165
+ # a Noncharacter, but well-formed Unicode
166
+ # https://www.unicode.org/versions/corrigendum9.html
167
+ "\uffff",
168
+ # maximal UTF-8 codepoint U+10FFFF
169
+ "\u{10ffff}"
170
+ ]
171
+
172
+ bad = [
173
+ # NUL in the middle
174
+ # FIXME: InvalidPacketException is wrong here, it should be ArgumentError
175
+ ["a\x00b", DBus::InvalidPacketException, "contains NUL"],
176
+ # invalid UTF-8
177
+ ["\xFF\xFF\xFF\xFF", DBus::InvalidPacketException, "not in UTF-8"],
178
+ # overlong sequence encoding an "A"
179
+ ["\xC1\x81", DBus::InvalidPacketException, "not in UTF-8"],
180
+ # first codepoint outside UTF-8, U+110000
181
+ ["\xF4\x90\xC0\xC0", DBus::InvalidPacketException, "not in UTF-8"]
182
+ ]
183
+
184
+ include_examples "constructor accepts plain or typed values", good
185
+ include_examples "constructor rejects values from this list", bad
186
+
187
+ describe ".alignment" do
188
+ # this overly specific test avoids a redundant alignment call
189
+ # in the production code
190
+ it "returns the correct value" do
191
+ expect(described_class.alignment).to eq 4
192
+ end
193
+ end
194
+ end
195
+
196
+ describe DBus::Data::ObjectPath do
197
+ good = [
198
+ "/"
199
+ # TODO: others
200
+ ]
201
+
202
+ bad = [
203
+ ["", DBus::InvalidPacketException, "Invalid object path"]
204
+ # TODO: others
205
+ ]
206
+
207
+ include_examples "constructor accepts plain or typed values", good
208
+ include_examples "constructor rejects values from this list", bad
209
+
210
+ describe ".alignment" do
211
+ # this overly specific test avoids a redundant alignment call
212
+ # in the production code
213
+ it "returns the correct value" do
214
+ expect(described_class.alignment).to eq 4
215
+ end
216
+ end
217
+ end
218
+
219
+ describe DBus::Data::Signature do
220
+ good = [
221
+ "",
222
+ "i",
223
+ "ii"
224
+ # TODO: others
225
+ ]
226
+
227
+ bad = [
228
+ ["!", DBus::InvalidPacketException, "Unknown type code"]
229
+ # TODO: others
230
+ ]
231
+
232
+ include_examples "constructor accepts plain or typed values", good
233
+ include_examples "constructor rejects values from this list", bad
234
+
235
+ describe ".alignment" do
236
+ # this overly specific test avoids a redundant alignment call
237
+ # in the production code
238
+ it "returns the correct value" do
239
+ expect(described_class.alignment).to eq 1
240
+ end
241
+ end
242
+ end
243
+ end
244
+
245
+ describe "containers" do
246
+ describe DBus::Data::Array do
247
+ 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" }]
253
+ # TODO: others
254
+ ]
255
+
256
+ bad = [
257
+ # 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"]
260
+ # TODO: others
261
+ ]
262
+
263
+ include_examples "constructor (kwargs) accepts values", good
264
+ include_examples "constructor (kwargs) rejects values", bad
265
+
266
+ describe ".from_typed" do
267
+ 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)
270
+ end
271
+ end
272
+ end
273
+
274
+ describe DBus::Data::Struct do
275
+ three_words = ::Struct.new(:a, :b, :c)
276
+
277
+ qqq = ["q", "q", "q"]
278
+ integers = [1, 2, 3]
279
+ uints = [DBus::Data::UInt16.new(1), DBus::Data::UInt16.new(2), DBus::Data::UInt16.new(3)]
280
+
281
+ # TODO: all the reasonable initialization params
282
+ # need to be normalized into one/few internal representation.
283
+ # So check what is the result
284
+ #
285
+ # Internally, it must be Data::Base
286
+ # Perhaps distinguish #value => Data::Base
287
+ # and #plain_value => plain Ruby
288
+ #
289
+ # but then, can they mutate?
290
+ #
291
+ # TODO: also check data ownership: reasonable to own the data?
292
+ # can make it explicit?
293
+ 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") }],
298
+ # plain array of data
299
+ [uints, { member_types: DBus.types("qqq") }],
300
+ # ::Struct
301
+ [three_words.new(*integers), { member_types: qqq }],
302
+ [three_words.new(*uints), { member_types: qqq }]
303
+ # TODO: others
304
+ ]
305
+
306
+ _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
+ # 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, "???"]
316
+ # TODO: others
317
+ ]
318
+
319
+ include_examples "constructor (kwargs) accepts values", good
320
+ # include_examples "constructor (kwargs) rejects values", bad
321
+
322
+ describe ".from_typed" do
323
+ 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]))
326
+ .to be_a(described_class)
327
+ end
328
+ end
329
+ end
330
+
331
+ describe DBus::Data::Variant do
332
+ describe ".from_typed" do
333
+ 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)
336
+ end
337
+
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])
344
+ expect(value.type.to_s).to eq "v"
345
+ expect(value.member_type.to_s).to eq "s"
346
+ end
347
+ end
348
+ end
349
+
350
+ describe DBus::Data::DictEntry do
351
+ end
352
+ end
353
+ end
data/spec/err_msg_spec.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # should report it missing on org.ruby.SampleInterface
3
5
  # (on object...) instead of on DBus::Proxy::ObjectInterface
4
6
  require_relative "spec_helper"
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative "spec_helper"
3
5
  require "dbus"
4
6
 
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative "spec_helper"
3
5
  require "dbus"
4
6
 
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test the main loop
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
data/spec/node_spec.rb ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ describe DBus::Node do
8
+ describe "#inspect" do
9
+ # the behavior needs improvement
10
+ it "shows the node, poorly" do
11
+ parent = described_class.new("parent")
12
+ parent.object = DBus::Object.new("/parent")
13
+
14
+ 3.times do |i|
15
+ child_name = "child#{i}"
16
+ child = described_class.new(child_name)
17
+ parent[child_name] = child
18
+ end
19
+
20
+ expect(parent.inspect).to match(/<DBus::Node [0-9a-f]+ {child0 => {},child1 => {},child2 => {}}>/)
21
+ end
22
+ end
23
+ end
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative "spec_helper"
3
5
  require "dbus"
4
6
 
@@ -18,6 +20,7 @@ describe DBus::ObjectPath do
18
20
  expect(described_class.valid?("/EmptyLastComponent/")).to be_falsey
19
21
  expect(described_class.valid?("/Invalid Character")).to be_falsey
20
22
  expect(described_class.valid?("/Invalid-Character")).to be_falsey
23
+ expect(described_class.valid?("/InválídCháráctér")).to be_falsey
21
24
  end
22
25
  end
23
26
  end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+ require "ostruct"
7
+ require "yaml"
8
+
9
+ data_dir = File.expand_path("data", __dir__)
10
+ marshall_yaml_s = File.read("#{data_dir}/marshall.yaml")
11
+ marshall_yaml = YAML.safe_load(marshall_yaml_s)
12
+
13
+ describe DBus::PacketMarshaller do
14
+ context "marshall.yaml" do
15
+ marshall_yaml.each do |test|
16
+ t = OpenStruct.new(test)
17
+ next if t.marshall == false
18
+ # skip test cases for invalid unmarshalling
19
+ next if t.val.nil?
20
+
21
+ # while the marshaller can use only native endianness, skip the other
22
+ endianness = t.end.to_sym
23
+
24
+ signature = t.sig
25
+ expected = buffer_from_yaml(t.buf)
26
+
27
+ it "writes a '#{signature}' with value #{t.val.inspect} (#{endianness})" do
28
+ subject = described_class.new(endianness: endianness)
29
+ subject.append(signature, t.val)
30
+ expect(subject.packet).to eq(expected)
31
+ end
32
+ end
33
+ end
34
+ end