ruby-dbus 0.16.0 → 0.18.0.beta2

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +46 -0
  3. data/README.md +3 -5
  4. data/Rakefile +18 -8
  5. data/VERSION +1 -1
  6. data/doc/Reference.md +94 -4
  7. data/examples/doc/_extract_examples +7 -0
  8. data/examples/gdbus/gdbus +31 -24
  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 +2 -1
  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 +20 -15
  22. data/lib/dbus/bus.rb +126 -74
  23. data/lib/dbus/bus_name.rb +12 -8
  24. data/lib/dbus/core_ext/class/attribute.rb +1 -1
  25. data/lib/dbus/data.rb +725 -0
  26. data/lib/dbus/error.rb +4 -2
  27. data/lib/dbus/introspect.rb +91 -30
  28. data/lib/dbus/logger.rb +3 -1
  29. data/lib/dbus/marshall.rb +228 -294
  30. data/lib/dbus/matchrule.rb +16 -16
  31. data/lib/dbus/message.rb +44 -37
  32. data/lib/dbus/message_queue.rb +16 -10
  33. data/lib/dbus/object.rb +296 -24
  34. data/lib/dbus/object_path.rb +11 -6
  35. data/lib/dbus/proxy_object.rb +22 -1
  36. data/lib/dbus/proxy_object_factory.rb +11 -7
  37. data/lib/dbus/proxy_object_interface.rb +26 -21
  38. data/lib/dbus/raw_message.rb +91 -0
  39. data/lib/dbus/type.rb +182 -80
  40. data/lib/dbus/xml.rb +28 -17
  41. data/lib/dbus.rb +13 -7
  42. data/ruby-dbus.gemspec +7 -3
  43. data/spec/async_spec.rb +2 -0
  44. data/spec/binding_spec.rb +2 -0
  45. data/spec/bus_and_xml_backend_spec.rb +2 -0
  46. data/spec/bus_driver_spec.rb +2 -0
  47. data/spec/bus_name_spec.rb +3 -1
  48. data/spec/bus_spec.rb +2 -0
  49. data/spec/byte_array_spec.rb +2 -0
  50. data/spec/client_robustness_spec.rb +4 -2
  51. data/spec/data/marshall.yaml +1639 -0
  52. data/spec/data_spec.rb +298 -0
  53. data/spec/err_msg_spec.rb +2 -0
  54. data/spec/introspect_xml_parser_spec.rb +2 -0
  55. data/spec/introspection_spec.rb +2 -0
  56. data/spec/main_loop_spec.rb +3 -1
  57. data/spec/node_spec.rb +23 -0
  58. data/spec/object_path_spec.rb +3 -0
  59. data/spec/packet_marshaller_spec.rb +34 -0
  60. data/spec/packet_unmarshaller_spec.rb +262 -0
  61. data/spec/property_spec.rb +88 -5
  62. data/spec/proxy_object_spec.rb +2 -0
  63. data/spec/server_robustness_spec.rb +2 -0
  64. data/spec/server_spec.rb +2 -0
  65. data/spec/service_newapi.rb +39 -70
  66. data/spec/session_bus_spec.rb +3 -1
  67. data/spec/session_bus_spec_manual.rb +2 -0
  68. data/spec/signal_spec.rb +5 -3
  69. data/spec/spec_helper.rb +35 -9
  70. data/spec/thread_safety_spec.rb +2 -0
  71. data/spec/tools/dbus-limited-session.conf +4 -0
  72. data/spec/type_spec.rb +69 -6
  73. data/spec/value_spec.rb +16 -1
  74. data/spec/variant_spec.rb +4 -2
  75. metadata +32 -10
@@ -1,11 +1,13 @@
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 "PropertyTest" do
6
8
  before(:each) do
7
- session_bus = DBus::ASessionBus.new
8
- @svc = session_bus.service("org.ruby.service")
9
+ @session_bus = DBus::ASessionBus.new
10
+ @svc = @session_bus.service("org.ruby.service")
9
11
  @obj = @svc.object("/org/ruby/MyInstance")
10
12
  @iface = @obj["org.ruby.SampleInterface"]
11
13
  end
@@ -21,6 +23,10 @@ describe "PropertyTest" do
21
23
  expect(iface["ReadMe"]).to eq("READ ME")
22
24
  end
23
25
 
26
+ it "gets an error when reading a property whose implementation raises" do
27
+ expect { @iface["Explosive"] }.to raise_error(DBus::Error, /Something failed/)
28
+ end
29
+
24
30
  it "tests property nonreading" do
25
31
  expect { @iface["WriteMe"] }.to raise_error(DBus::Error, /not readable/)
26
32
  end
@@ -31,7 +37,7 @@ describe "PropertyTest" do
31
37
  end
32
38
 
33
39
  # https://github.com/mvidner/ruby-dbus/pull/19
34
- it "tests service select timeout" do
40
+ it "tests service select timeout", slow: true do
35
41
  @iface["ReadOrWriteMe"] = "VALUE"
36
42
  expect(@iface["ReadOrWriteMe"]).to eq("VALUE")
37
43
  # wait for the service to become idle
@@ -46,7 +52,7 @@ describe "PropertyTest" do
46
52
 
47
53
  it "tests get all" do
48
54
  all = @iface.all_properties
49
- expect(all.keys.sort).to eq(["ReadMe", "ReadOrWriteMe"])
55
+ expect(all.keys.sort).to eq(["MyStruct", "ReadMe", "ReadOrWriteMe"])
50
56
  end
51
57
 
52
58
  it "tests get all on a V1 object" do
@@ -54,7 +60,7 @@ describe "PropertyTest" do
54
60
  iface = obj["org.ruby.SampleInterface"]
55
61
 
56
62
  all = iface.all_properties
57
- expect(all.keys.sort).to eq(["ReadMe", "ReadOrWriteMe"])
63
+ expect(all.keys.sort).to eq(["MyStruct", "ReadMe", "ReadOrWriteMe"])
58
64
  end
59
65
 
60
66
  it "tests unknown property reading" do
@@ -64,4 +70,81 @@ describe "PropertyTest" do
64
70
  it "tests unknown property writing" do
65
71
  expect { @iface["Spoon"] = "FPRK" }.to raise_error(DBus::Error, /not found/)
66
72
  end
73
+
74
+ it "errors for a property on an unknown interface" do
75
+ # our idiomatic way would error out on interface lookup already,
76
+ # so do it the low level way
77
+ prop_if = @obj[DBus::PROPERTY_INTERFACE]
78
+ expect { prop_if.Get("org.ruby.NoSuchInterface", "SomeProperty") }.to raise_error(DBus::Error) do |e|
79
+ expect(e.name).to match(/UnknownProperty/)
80
+ expect(e.message).to match(/no such interface/)
81
+ end
82
+ end
83
+
84
+ it "errors for GetAll on an unknown interface" do
85
+ # no idiomatic way?
86
+ # so do it the low level way
87
+ prop_if = @obj[DBus::PROPERTY_INTERFACE]
88
+ expect { prop_if.GetAll("org.ruby.NoSuchInterface") }.to raise_error(DBus::Error) do |e|
89
+ expect(e.name).to match(/UnknownProperty/)
90
+ expect(e.message).to match(/no such interface/)
91
+ end
92
+ end
93
+
94
+ it "receives a PropertiesChanged signal", slow: true do
95
+ received = {}
96
+
97
+ # TODO: for client side, provide a helper on_properties_changed,
98
+ # or automate it even more in ProxyObject, ProxyObjectInterface
99
+ prop_if = @obj[DBus::PROPERTY_INTERFACE]
100
+ prop_if.on_signal("PropertiesChanged") do |_interface_name, changed_props, _invalidated_props|
101
+ received.merge!(changed_props)
102
+ end
103
+
104
+ @iface["ReadOrWriteMe"] = "VALUE"
105
+
106
+ # loop to process the signal. complicated :-( see signal_spec.rb
107
+ loop = DBus::Main.new
108
+ loop << @session_bus
109
+ quitter = Thread.new do
110
+ sleep 1
111
+ loop.quit
112
+ end
113
+ loop.run
114
+ # quitter has told loop.run to quit
115
+ quitter.join
116
+
117
+ expect(received["ReadOrWriteMe"]).to eq("VALUE")
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
67
150
  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,21 +1,24 @@
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
+ INTERFACE = "org.ruby.SampleInterface"
15
17
  def initialize(path)
16
18
  super path
17
19
  @read_me = "READ ME"
18
20
  @read_or_write_me = "READ OR WRITE ME"
21
+ @my_struct = ["three", "strings", "in a struct"].freeze
19
22
  end
20
23
 
21
24
  # Create an interface aggregating all upcoming dbus_method defines.
@@ -59,6 +62,38 @@ class Test < DBus::Object
59
62
  dbus_method :mirror_byte_array, "in bytes:ay, out mirrored:ay" do |bytes|
60
63
  [bytes]
61
64
  end
65
+
66
+ dbus_method :Coordinates, "out coords:(dd)" do
67
+ coords = [3.0, 4.0].freeze
68
+ [coords]
69
+ end
70
+
71
+ dbus_method :Coordinates2, "out coords:(dd)" do
72
+ coords = Point2D.new(5.0, 12.0)
73
+ [coords]
74
+ end
75
+
76
+ # Properties:
77
+ # ReadMe:string, returns "READ ME" at first, then what WriteMe received
78
+ # WriteMe:string
79
+ # ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
80
+ dbus_attr_accessor :read_or_write_me, "s"
81
+ dbus_attr_reader :read_me, "s"
82
+
83
+ def write_me=(value)
84
+ @read_me = value
85
+ end
86
+ dbus_writer :write_me, "s"
87
+
88
+ dbus_attr_writer :password, "s"
89
+
90
+ # a property that raises when client tries to read it
91
+ def explosive
92
+ raise "Something failed"
93
+ end
94
+ dbus_reader :explosive, "s"
95
+
96
+ dbus_attr_reader :my_struct, "(sss)"
62
97
  end
63
98
 
64
99
  # closing and reopening the same interface
@@ -118,72 +153,6 @@ class Test < DBus::Object
118
153
  dbus_signal :LongTaskStart
119
154
  dbus_signal :LongTaskEnd
120
155
  end
121
-
122
- # Properties:
123
- # ReadMe:string, returns "READ ME" at first, then what WriteMe received
124
- # WriteMe:string
125
- # ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
126
- dbus_interface PROPERTY_INTERFACE do
127
- dbus_method :Get, "in interface:s, in propname:s, out value:v" do |interface, propname|
128
- unless interface == INTERFACE
129
- raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
130
- "Interface '#{interface}' not found on object '#{@path}'"
131
- end
132
-
133
- case propname
134
- when "ReadMe"
135
- [@read_me]
136
- when "ReadOrWriteMe"
137
- [@read_or_write_me]
138
- when "WriteMe"
139
- raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
140
- "Property '#{interface}.#{propname}' (on object '#{@path}') is not readable"
141
- else
142
- # what should happen for unknown properties
143
- # plasma: InvalidArgs (propname), UnknownInterface (interface)
144
- raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
145
- "Property '#{interface}.#{propname}' not found on object '#{@path}'"
146
- end
147
- end
148
-
149
- dbus_method :Set, "in interface:s, in propname:s, in value:v" do |interface, propname, value|
150
- unless interface == INTERFACE
151
- raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
152
- "Interface '#{interface}' not found on object '#{@path}'"
153
- end
154
-
155
- case propname
156
- when "ReadMe"
157
- raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
158
- "Property '#{interface}.#{propname}' (on object '#{@path}') is not writable"
159
- when "ReadOrWriteMe"
160
- @read_or_write_me = value
161
- self.PropertiesChanged(interface, { propname => value }, [])
162
- when "WriteMe"
163
- @read_me = value
164
- self.PropertiesChanged(interface, { "ReadMe" => value }, [])
165
- else
166
- raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
167
- "Property '#{interface}.#{propname}' not found on object '#{@path}'"
168
- end
169
- end
170
-
171
- dbus_method :GetAll, "in interface:s, out value:a{sv}" do |interface|
172
- unless interface == INTERFACE
173
- raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
174
- "Interface '#{interface}' not found on object '#{@path}'"
175
- end
176
-
177
- [
178
- {
179
- "ReadMe" => @read_me,
180
- "ReadOrWriteMe" => @read_or_write_me
181
- }
182
- ]
183
- end
184
-
185
- dbus_signal :PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
186
- end
187
156
  end
188
157
 
189
158
  class Derived < Test
@@ -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"
@@ -29,7 +31,7 @@ describe "SignalHandlerTest" do
29
31
  end
30
32
 
31
33
  # testing for commit 017c83 (kkaempf)
32
- it "tests overriding a handler" do
34
+ it "tests overriding a handler", slow: true do
33
35
  DBus.logger.debug "Inside test_overriding_a_handler"
34
36
  counter = 0
35
37
 
@@ -52,7 +54,7 @@ describe "SignalHandlerTest" do
52
54
  expect(counter).to eq(1)
53
55
  end
54
56
 
55
- it "tests on signal overload" do
57
+ it "tests on signal overload", slow: true do
56
58
  DBus.logger.debug "Inside test_on_signal_overload"
57
59
  counter = 0
58
60
  started = false
@@ -74,7 +76,7 @@ describe "SignalHandlerTest" do
74
76
  expect { @intf.on_signal "to", "many", "yarrrrr!" }.to raise_error(ArgumentError)
75
77
  end
76
78
 
77
- it "is possible to add signal handlers from within handlers" do
79
+ it "is possible to add signal handlers from within handlers", slow: true do
78
80
  ended = false
79
81
  @intf.on_signal "LongTaskStart" do
80
82
  @intf.on_signal "LongTaskEnd" do
data/spec/spec_helper.rb CHANGED
@@ -1,28 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  coverage = if ENV["COVERAGE"]
2
4
  ENV["COVERAGE"] == "true"
3
5
  else
4
6
  # heuristics: enable for interactive builds (but not in OBS)
5
- # or in Travis
6
- ENV["DISPLAY"] || ENV["TRAVIS"]
7
+ ENV["DISPLAY"]
7
8
  end
8
9
 
9
10
  if coverage
10
11
  require "simplecov"
11
- SimpleCov.root File.expand_path("../..", __FILE__)
12
+ SimpleCov.root File.expand_path("..", __dir__)
12
13
 
13
14
  # do not cover specs
14
15
  SimpleCov.add_filter "_spec.rb"
15
16
  # do not cover the activesupport helpers
16
17
  SimpleCov.add_filter "/core_ext/"
17
18
 
18
- # use coveralls for on-line code coverage reporting at Travis CI
19
- if ENV["TRAVIS"]
20
- require "coveralls"
21
- end
22
19
  SimpleCov.start
20
+
21
+ # additionally use the LCOV format for on-line code coverage reporting at CI
22
+ if ENV["COVERAGE_LCOV"] == "true"
23
+ require "simplecov-lcov"
24
+
25
+ SimpleCov::Formatter::LcovFormatter.config do |c|
26
+ c.report_with_single_file = true
27
+ # this is the default Coveralls GitHub Action location
28
+ # https://github.com/marketplace/actions/coveralls-github-action
29
+ c.single_report_path = "coverage/lcov.info"
30
+ end
31
+
32
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
33
+ SimpleCov::Formatter::HTMLFormatter,
34
+ SimpleCov::Formatter::LcovFormatter
35
+ ]
36
+ end
23
37
  end
24
38
 
25
- $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
39
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
26
40
 
27
41
  if Object.const_defined? "RSpec"
28
42
  # http://betterspecs.org/#expect
@@ -36,7 +50,7 @@ end
36
50
  require "tempfile"
37
51
  require "timeout"
38
52
 
39
- TOPDIR = File.expand_path("../..", __FILE__)
53
+ TOPDIR = File.expand_path("..", __dir__)
40
54
 
41
55
  # path of config file for a private bus
42
56
  def config_file_path
@@ -104,3 +118,15 @@ def with_service_by_activation(&block)
104
118
 
105
119
  system "pkill -f #{exec}"
106
120
  end
121
+
122
+ # Make a binary string from readable YAML pieces; see data/marshall.yaml
123
+ def buffer_from_yaml(parts)
124
+ strings = parts.flatten.map do |part|
125
+ if part.is_a? Integer
126
+ part.chr
127
+ else
128
+ part
129
+ end
130
+ end
131
+ strings.join.force_encoding(Encoding::BINARY)
132
+ 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"
@@ -25,4 +25,8 @@
25
25
  Instead, lower some so that we can test resource leaks. -->
26
26
  <limit name="max_match_rules_per_connection">50</limit><!-- was 512 -->
27
27
 
28
+ <!--
29
+ dbus-daemon[1700]: [session uid=1001 pid=1700] Unable to set up new connection: Failed to get AppArmor confinement information of socket peer: Protocol not available
30
+ -->
31
+ <apparmor mode="disabled"/>
28
32
  </busconfig>
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