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
@@ -0,0 +1,262 @@
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
+ # Helper to access PacketUnmarshaller internals.
14
+ # Add it to its public API?
15
+ # @param p_u [PacketUnmarshaller]
16
+ # @return [String] the binary string with unconsumed data
17
+ def remaining_buffer(p_u)
18
+ raw_msg = p_u.instance_variable_get(:@raw_msg)
19
+ raw_msg.remaining_bytes
20
+ end
21
+
22
+ RSpec.shared_examples "parses good data" do |cases|
23
+ describe "parses all the instances of good test data" do
24
+ cases.each_with_index do |(buffer, endianness, expected), i|
25
+ it "parses plain data ##{i}" do
26
+ buffer = String.new(buffer, encoding: Encoding::BINARY)
27
+ subject = described_class.new(buffer, endianness)
28
+
29
+ results = subject.unmarshall(signature, mode: :plain)
30
+ # unmarshall works on multiple signatures but we use one
31
+ expect(results).to be_an(Array)
32
+ expect(results.size).to eq(1)
33
+ result = results.first
34
+
35
+ expect(result).to eq(expected)
36
+
37
+ expect(remaining_buffer(subject)).to be_empty
38
+ end
39
+
40
+ it "parses exact data ##{i}" do
41
+ buffer = String.new(buffer, encoding: Encoding::BINARY)
42
+ subject = described_class.new(buffer, endianness)
43
+
44
+ results = subject.unmarshall(signature, mode: :exact)
45
+ # unmarshall works on multiple signatures but we use one
46
+ expect(results).to be_an(Array)
47
+ expect(results.size).to eq(1)
48
+ result = results.first
49
+
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
59
+
60
+ expect(remaining_buffer(subject)).to be_empty
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ # this is necessary because we do an early switch on the signature
67
+ RSpec.shared_examples "reports empty data" do
68
+ it "reports empty data" do
69
+ [:big, :little].each do |endianness|
70
+ subject = described_class.new("", endianness)
71
+ expect { subject.unmarshall(signature) }.to raise_error(DBus::IncompleteBufferException)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe DBus::PacketUnmarshaller do
77
+ context "marshall.yaml" do
78
+ marshall_yaml.each do |test|
79
+ t = OpenStruct.new(test)
80
+ signature = t.sig
81
+ buffer = buffer_from_yaml(t.buf)
82
+ endianness = t.end.to_sym
83
+
84
+ # successful parse
85
+ if !t.val.nil?
86
+ expected = t.val
87
+
88
+ it "parses a '#{signature}' to get #{t.val.inspect} (plain)" do
89
+ subject = described_class.new(buffer, endianness)
90
+ results = subject.unmarshall(signature, mode: :plain)
91
+ # unmarshall works on multiple signatures but we use one
92
+ expect(results).to be_an(Array)
93
+ expect(results.size).to eq(1)
94
+ result = results.first
95
+
96
+ expect(result).to eq(expected)
97
+ expect(remaining_buffer(subject)).to be_empty
98
+ end
99
+
100
+ it "parses a '#{t.sig}' to get #{t.val.inspect} (exact)" do
101
+ subject = described_class.new(buffer, endianness)
102
+ results = subject.unmarshall(signature, mode: :exact)
103
+ # unmarshall works on multiple signatures but we use one
104
+ expect(results).to be_an(Array)
105
+ expect(results.size).to eq(1)
106
+ result = results.first
107
+
108
+ 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
117
+
118
+ expect(remaining_buffer(subject)).to be_empty
119
+ end
120
+ elsif t.exc
121
+ next if t.unmarshall == false
122
+
123
+ exc_class = DBus.const_get(t.exc)
124
+ msg_re = Regexp.new(Regexp.escape(t.msg))
125
+
126
+ # TODO: InvalidPacketException is never rescued.
127
+ # The other end is sending invalid data. Can we do better than crashing?
128
+ # When we can test with peer connections, try it out.
129
+ it "parses a '#{signature}' to report a #{t.exc}" do
130
+ subject = described_class.new(buffer, endianness)
131
+ expect { subject.unmarshall(signature, mode: :plain) }.to raise_error(exc_class, msg_re)
132
+
133
+ subject = described_class.new(buffer, endianness)
134
+ expect { subject.unmarshall(signature, mode: :exact) }.to raise_error(exc_class, msg_re)
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ context "BYTEs" do
141
+ let(:signature) { "y" }
142
+ include_examples "reports empty data"
143
+ end
144
+
145
+ context "BOOLEANs" do
146
+ let(:signature) { "b" }
147
+ include_examples "reports empty data"
148
+ end
149
+
150
+ context "INT16s" do
151
+ let(:signature) { "n" }
152
+ include_examples "reports empty data"
153
+ end
154
+
155
+ context "UINT16s" do
156
+ let(:signature) { "q" }
157
+ include_examples "reports empty data"
158
+ end
159
+
160
+ context "INT32s" do
161
+ let(:signature) { "i" }
162
+ include_examples "reports empty data"
163
+ end
164
+
165
+ context "UINT32s" do
166
+ let(:signature) { "u" }
167
+ include_examples "reports empty data"
168
+ end
169
+
170
+ context "UNIX_FDs" do
171
+ let(:signature) { "h" }
172
+ include_examples "reports empty data"
173
+ end
174
+
175
+ context "INT64s" do
176
+ let(:signature) { "x" }
177
+ include_examples "reports empty data"
178
+ end
179
+
180
+ context "UINT64s" do
181
+ let(:signature) { "t" }
182
+ include_examples "reports empty data"
183
+ end
184
+
185
+ context "DOUBLEs" do
186
+ let(:signature) { "d" }
187
+ # See https://en.wikipedia.org/wiki/Double-precision_floating-point_format
188
+ # for binary representations
189
+ # TODO: figure out IEEE754 comparisons
190
+ good = [
191
+ # But == cant distinguish -0.0
192
+ ["\x00\x00\x00\x00\x00\x00\x00\x80", :little, -0.0],
193
+ # But NaN == NaN is false!
194
+ # ["\xff\xff\xff\xff\xff\xff\xff\xff", :little, Float::NAN],
195
+ ["\x80\x00\x00\x00\x00\x00\x00\x00", :big, -0.0]
196
+ # ["\xff\xff\xff\xff\xff\xff\xff\xff", :big, Float::NAN]
197
+ ]
198
+ include_examples "parses good data", good
199
+ include_examples "reports empty data"
200
+ end
201
+
202
+ context "STRINGs" do
203
+ let(:signature) { "s" }
204
+ include_examples "reports empty data"
205
+ end
206
+
207
+ context "OBJECT_PATHs" do
208
+ let(:signature) { "o" }
209
+ include_examples "reports empty data"
210
+ end
211
+
212
+ context "SIGNATUREs" do
213
+ let(:signature) { "g" }
214
+ include_examples "reports empty data"
215
+ end
216
+
217
+ context "ARRAYs" do
218
+ context "of BYTEs" do
219
+ let(:signature) { "ay" }
220
+ include_examples "reports empty data"
221
+ end
222
+
223
+ context "of UINT64s" do
224
+ let(:signature) { "at" }
225
+ include_examples "reports empty data"
226
+ end
227
+
228
+ context "of STRUCT of 2 UINT16s" do
229
+ let(:signature) { "a(qq)" }
230
+ include_examples "reports empty data"
231
+ end
232
+
233
+ context "of DICT_ENTRIES" do
234
+ let(:signature) { "a{yq}" }
235
+ include_examples "reports empty data"
236
+ end
237
+ end
238
+
239
+ context "STRUCTs" do
240
+ # TODO: this is invalid but does not raise
241
+ context "(generic 'r' struct)" do
242
+ let(:signature) { "r" }
243
+ end
244
+
245
+ context "of two shorts" do
246
+ let(:signature) { "(qq)" }
247
+ include_examples "reports empty data"
248
+ end
249
+ end
250
+
251
+ # makes sense here? or in array? remember invalid sigs are rejected elsewhere
252
+ context "DICT_ENTRYs" do
253
+ context "(generic 'e' dict_entry)" do
254
+ let(:signature) { "e" }
255
+ end
256
+ end
257
+
258
+ context "VARIANTs" do
259
+ let(:signature) { "v" }
260
+ include_examples "reports empty data"
261
+ end
262
+ 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
 
@@ -50,7 +52,7 @@ describe "PropertyTest" do
50
52
 
51
53
  it "tests get all" do
52
54
  all = @iface.all_properties
53
- expect(all.keys.sort).to eq(["ReadMe", "ReadOrWriteMe"])
55
+ expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
54
56
  end
55
57
 
56
58
  it "tests get all on a V1 object" do
@@ -58,7 +60,7 @@ describe "PropertyTest" do
58
60
  iface = obj["org.ruby.SampleInterface"]
59
61
 
60
62
  all = iface.all_properties
61
- expect(all.keys.sort).to eq(["ReadMe", "ReadOrWriteMe"])
63
+ expect(all.keys.sort).to eq(["MyArray", "MyDict", "MyStruct", "MyVariant", "ReadMe", "ReadOrWriteMe"])
62
64
  end
63
65
 
64
66
  it "tests unknown property reading" do
@@ -114,4 +116,60 @@ describe "PropertyTest" do
114
116
 
115
117
  expect(received["ReadOrWriteMe"]).to eq("VALUE")
116
118
  end
119
+
120
+ context "a struct-typed property" do
121
+ it "gets read as a struct, not an array (#97)" do
122
+ struct = @iface["MyStruct"]
123
+ expect(struct).to be_frozen
124
+ end
125
+
126
+ it "Get returns the correctly typed value (check with dbus-send)" do
127
+ # As big as the DBus::Data branch is,
128
+ # it still does not handle the :exact mode on the client/proxy side.
129
+ # So we resort to parsing dbus-send output.
130
+ cmd = "dbus-send --print-reply " \
131
+ "--dest=org.ruby.service " \
132
+ "/org/ruby/MyInstance " \
133
+ "org.freedesktop.DBus.Properties.Get " \
134
+ "string:org.ruby.SampleInterface " \
135
+ "string:MyStruct"
136
+ reply = `#{cmd}`
137
+ expect(reply).to match(/variant\s+struct {\s+string "three"\s+string "strings"\s+string "in a struct"\s+}/)
138
+ end
139
+
140
+ it "GetAll returns the correctly typed value (check with dbus-send)" do
141
+ cmd = "dbus-send --print-reply " \
142
+ "--dest=org.ruby.service " \
143
+ "/org/ruby/MyInstance " \
144
+ "org.freedesktop.DBus.Properties.GetAll " \
145
+ "string:org.ruby.SampleInterface "
146
+ reply = `#{cmd}`
147
+ expect(reply).to match(/variant\s+struct {\s+string "three"\s+string "strings"\s+string "in a struct"\s+}/)
148
+ end
149
+ end
150
+
151
+ context "an array-typed property" do
152
+ it "gets read as an array" do
153
+ val = @iface["MyArray"]
154
+ expect(val).to eq([42, 43])
155
+ end
156
+ end
157
+
158
+ context "an dict-typed property" do
159
+ it "gets read as a hash" do
160
+ val = @iface["MyDict"]
161
+ expect(val).to eq({
162
+ "one" => 1,
163
+ "two" => "dva",
164
+ "three" => [3, 3, 3]
165
+ })
166
+ end
167
+ end
168
+
169
+ context "a variant-typed property" do
170
+ it "gets read at all" do
171
+ val = @iface["MyVariant"]
172
+ expect(val).to eq([42, 43])
173
+ end
174
+ end
117
175
  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
 
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test that a server survives various error cases
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
data/spec/server_spec.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test that a server survives various error cases
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
@@ -1,25 +1,42 @@
1
1
  #!/usr/bin/env ruby
2
- # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
3
 
4
4
  require_relative "spec_helper"
5
5
  SimpleCov.command_name "Service Tests" if Object.const_defined? "SimpleCov"
6
6
  # find the library without external help
7
- $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
7
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
8
8
 
9
9
  require "dbus"
10
10
 
11
- PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties".freeze
11
+ PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
12
12
 
13
13
  class Test < DBus::Object
14
- INTERFACE = "org.ruby.SampleInterface".freeze
14
+ Point2D = Struct.new(:x, :y)
15
+
16
+ attr_writer :main_loop
17
+
18
+ INTERFACE = "org.ruby.SampleInterface"
15
19
  def initialize(path)
16
20
  super path
17
21
  @read_me = "READ ME"
18
22
  @read_or_write_me = "READ OR WRITE ME"
23
+ @my_struct = ["three", "strings", "in a struct"].freeze
24
+ @my_array = [42, 43]
25
+ @my_dict = {
26
+ "one" => 1,
27
+ "two" => "dva",
28
+ "three" => [3, 3, 3]
29
+ }
30
+ @my_variant = @my_array.dup
31
+ @main_loop = nil
19
32
  end
20
33
 
21
34
  # Create an interface aggregating all upcoming dbus_method defines.
22
35
  dbus_interface INTERFACE do
36
+ dbus_method :quit, "" do
37
+ @main_loop&.quit
38
+ end
39
+
23
40
  dbus_method :hello, "in name:s, in name2:s" do |name, name2|
24
41
  puts "hello(#{name}, #{name2})"
25
42
  end
@@ -60,6 +77,16 @@ class Test < DBus::Object
60
77
  [bytes]
61
78
  end
62
79
 
80
+ dbus_method :Coordinates, "out coords:(dd)" do
81
+ coords = [3.0, 4.0].freeze
82
+ [coords]
83
+ end
84
+
85
+ dbus_method :Coordinates2, "out coords:(dd)" do
86
+ coords = Point2D.new(5.0, 12.0)
87
+ [coords]
88
+ end
89
+
63
90
  # Properties:
64
91
  # ReadMe:string, returns "READ ME" at first, then what WriteMe received
65
92
  # WriteMe:string
@@ -79,6 +106,11 @@ class Test < DBus::Object
79
106
  raise "Something failed"
80
107
  end
81
108
  dbus_reader :explosive, "s"
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"
82
114
  end
83
115
 
84
116
  # closing and reopening the same interface
@@ -178,6 +210,7 @@ end
178
210
  puts "listening, with ruby-#{RUBY_VERSION}"
179
211
  main = DBus::Main.new
180
212
  main << bus
213
+ myobj.main_loop = main
181
214
  begin
182
215
  main.run
183
216
  rescue SystemCallError
@@ -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
 
@@ -23,7 +25,7 @@ describe DBus::ASessionBus do
23
25
 
24
26
  before do
25
27
  # mocks of files for address_from_file method
26
- machine_id_path = File.expand_path("/etc/machine-id", __FILE__)
28
+ machine_id_path = File.expand_path("/etc/machine-id", __dir__)
27
29
  expect(Dir).to receive(:[]).with(any_args) { [machine_id_path] }
28
30
  expect(File).to receive(:read).with(machine_id_path) { "baz" }
29
31
  expect(File).to receive(:exist?).with(session_bus_file_path) { true }
@@ -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
 
data/spec/signal_spec.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test the signal handlers
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  coverage = if ENV["COVERAGE"]
2
4
  ENV["COVERAGE"] == "true"
3
5
  else
@@ -7,12 +9,14 @@ coverage = if ENV["COVERAGE"]
7
9
 
8
10
  if coverage
9
11
  require "simplecov"
10
- SimpleCov.root File.expand_path("../..", __FILE__)
12
+ SimpleCov.root File.expand_path("..", __dir__)
11
13
 
12
14
  # do not cover specs
13
15
  SimpleCov.add_filter "_spec.rb"
14
16
  # do not cover the activesupport helpers
15
17
  SimpleCov.add_filter "/core_ext/"
18
+ # measure all if/else branches on a line
19
+ SimpleCov.enable_coverage :branch
16
20
 
17
21
  SimpleCov.start
18
22
 
@@ -34,7 +38,7 @@ if coverage
34
38
  end
35
39
  end
36
40
 
37
- $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
41
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
38
42
 
39
43
  if Object.const_defined? "RSpec"
40
44
  # http://betterspecs.org/#expect
@@ -48,7 +52,7 @@ end
48
52
  require "tempfile"
49
53
  require "timeout"
50
54
 
51
- TOPDIR = File.expand_path("../..", __FILE__)
55
+ TOPDIR = File.expand_path("..", __dir__)
52
56
 
53
57
  # path of config file for a private bus
54
58
  def config_file_path
@@ -116,3 +120,15 @@ def with_service_by_activation(&block)
116
120
 
117
121
  system "pkill -f #{exec}"
118
122
  end
123
+
124
+ # Make a binary string from readable YAML pieces; see data/marshall.yaml
125
+ def buffer_from_yaml(parts)
126
+ strings = parts.flatten.map do |part|
127
+ if part.is_a? Integer
128
+ part.chr
129
+ else
130
+ part
131
+ end
132
+ end
133
+ strings.join.force_encoding(Encoding::BINARY)
134
+ end
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test thread safety
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
data/spec/type_spec.rb CHANGED
@@ -1,18 +1,81 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative "spec_helper"
3
5
  require "dbus"
4
6
 
5
7
  describe DBus do
6
8
  describe ".type" do
7
- ["i", "ai", "a(ii)", "aai"].each do |s|
8
- it "parses some type #{s}" do
9
- expect(DBus.type(s).to_s).to be_eql s
9
+ good = [
10
+ "i",
11
+ "ai",
12
+ "a(ii)",
13
+ "aai"
14
+ ]
15
+
16
+ context "valid single types" do
17
+ good.each do |s|
18
+ it "#{s.inspect} is parsed" do
19
+ expect(DBus.type(s).to_s).to eq(s)
20
+ end
10
21
  end
11
22
  end
12
23
 
13
- ["aa", "(ii", "ii)", "hrmp"].each do |s|
14
- it "raises exception for invalid type #{s}" do
15
- expect { DBus.type(s).to_s }.to raise_error DBus::Type::SignatureException
24
+ bad = [
25
+ ["\x00", "Unknown type code"],
26
+ ["!", "Unknown type code"],
27
+
28
+ # ARRAY related
29
+ ["a", "Empty ARRAY"],
30
+ ["aa", "Empty ARRAY"],
31
+
32
+ # STRUCT related
33
+ ["r", "Abstract STRUCT"],
34
+ ["()", "Empty STRUCT"],
35
+ ["(ii", "STRUCT not closed"],
36
+ ["a{i)", "STRUCT unexpectedly closed"],
37
+
38
+ # TODO: deep nesting arrays, structs, combined
39
+
40
+ # DICT_ENTRY related
41
+ ["e", "Abstract DICT_ENTRY"],
42
+ ["a{}", "DICT_ENTRY must have 2 subtypes, found 0"],
43
+ ["a{s}", "DICT_ENTRY must have 2 subtypes, found 1"],
44
+ ["a{sss}", "DICT_ENTRY must have 2 subtypes, found 3"],
45
+ ["a{vs}", "DICT_ENTRY key must be basic (non-container)"],
46
+ ["{sv}", "DICT_ENTRY not an immediate child of an ARRAY"],
47
+ ["a({sv})", "DICT_ENTRY not an immediate child of an ARRAY"],
48
+ ["a{sv", "DICT_ENTRY not closed"],
49
+ ["}", "DICT_ENTRY unexpectedly closed"],
50
+
51
+ # Too long
52
+ ["(#{"y" * 254})", "longer than 255"],
53
+
54
+ # not Single Complete Types
55
+ ["", "expecting a Single Complete Type"],
56
+ ["ii", "more than a Single Complete Type"]
57
+ ]
58
+ context "invalid single types" do
59
+ bad.each.each do |s, msg|
60
+ it "#{s.inspect} raises an exception mentioning: #{msg}" do
61
+ rx = Regexp.new(Regexp.quote(msg))
62
+ expect { DBus.type(s) }.to raise_error(DBus::Type::SignatureException, rx)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ describe ".types" do
69
+ good = [
70
+ "",
71
+ "ii"
72
+ ]
73
+
74
+ context "valid signatures" do
75
+ good.each do |s|
76
+ it "#{s.inspect} is parsed" do
77
+ expect(DBus.types(s).map(&:to_s).join).to eq(s)
78
+ end
16
79
  end
17
80
  end
18
81
  end
data/spec/value_spec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
- # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
3
4
  require_relative "spec_helper"
4
5
  require "dbus"
5
6
 
@@ -91,4 +92,18 @@ describe "ValueTest" do
91
92
  it "aligns short integers correctly" do
92
93
  expect(@obj.i16_plus(10, -30)[0]).to eq(-20)
93
94
  end
95
+
96
+ context "structs" do
97
+ it "they are returned as FROZEN arrays" do
98
+ struct = @obj.Coordinates[0]
99
+ expect(struct).to be_an(Array)
100
+ expect(struct).to be_frozen
101
+ end
102
+
103
+ it "they are returned also from structs" do
104
+ struct = @obj.Coordinates2[0]
105
+ expect(struct).to be_an(Array)
106
+ expect(struct).to be_frozen
107
+ end
108
+ end
94
109
  end
data/spec/variant_spec.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
2
4
  # Test marshalling variants according to ruby types
3
5
  require_relative "spec_helper"
4
6
  require "dbus"
@@ -9,8 +11,8 @@ describe "VariantTest" do
9
11
  @svc = @bus.service("org.ruby.service")
10
12
  end
11
13
 
12
- def make_variant(a)
13
- DBus::PacketMarshaller.make_variant(a)
14
+ def make_variant(val)
15
+ DBus::PacketMarshaller.make_variant(val)
14
16
  end
15
17
 
16
18
  it "tests make variant scalar" do