ruby-dbus 0.17.0 → 0.18.0.beta3

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