ruby-dbus-openplacos 0.6.0

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 (51) hide show
  1. data/COPYING +504 -0
  2. data/NEWS +146 -0
  3. data/README +42 -0
  4. data/Rakefile +54 -0
  5. data/VERSION +1 -0
  6. data/doc/tutorial/index.markdown +480 -0
  7. data/examples/gdbus/gdbus +255 -0
  8. data/examples/gdbus/gdbus.glade +184 -0
  9. data/examples/gdbus/launch.sh +4 -0
  10. data/examples/no-introspect/nm-test.rb +21 -0
  11. data/examples/no-introspect/tracker-test.rb +16 -0
  12. data/examples/rhythmbox/playpause.rb +25 -0
  13. data/examples/service/call_service.rb +25 -0
  14. data/examples/service/service_newapi.rb +51 -0
  15. data/examples/simple/call_introspect.rb +34 -0
  16. data/examples/simple/properties.rb +19 -0
  17. data/examples/utils/listnames.rb +11 -0
  18. data/examples/utils/notify.rb +19 -0
  19. data/lib/dbus/auth.rb +258 -0
  20. data/lib/dbus/bus.rb +947 -0
  21. data/lib/dbus/core_ext/class/attribute.rb +91 -0
  22. data/lib/dbus/core_ext/kernel/singleton_class.rb +14 -0
  23. data/lib/dbus/core_ext/module/remove_method.rb +12 -0
  24. data/lib/dbus/error.rb +44 -0
  25. data/lib/dbus/export.rb +124 -0
  26. data/lib/dbus/introspect.rb +570 -0
  27. data/lib/dbus/marshall.rb +443 -0
  28. data/lib/dbus/matchrule.rb +100 -0
  29. data/lib/dbus/message.rb +310 -0
  30. data/lib/dbus/type.rb +222 -0
  31. data/lib/dbus.rb +83 -0
  32. data/ruby-dbus-openplacos.gemspec +17 -0
  33. data/test/binding_test.rb +56 -0
  34. data/test/bus_driver_test.rb +22 -0
  35. data/test/dbus-launch-simple +35 -0
  36. data/test/dbus-limited-session.conf +28 -0
  37. data/test/property_test.rb +55 -0
  38. data/test/server_robustness_test.rb +72 -0
  39. data/test/server_test.rb +53 -0
  40. data/test/service_newapi.rb +197 -0
  41. data/test/session_bus_test_manual.rb +20 -0
  42. data/test/signal_test.rb +64 -0
  43. data/test/t1 +4 -0
  44. data/test/t2.rb +66 -0
  45. data/test/t3-ticket27.rb +18 -0
  46. data/test/t5-report-dbus-interface.rb +58 -0
  47. data/test/t6-loop.rb +82 -0
  48. data/test/test_env +13 -0
  49. data/test/test_server +39 -0
  50. data/test/variant_test.rb +66 -0
  51. metadata +118 -0
@@ -0,0 +1,35 @@
1
+ #! /bin/sh
2
+ # A wrapper for DBus tests
3
+ # Reimplementing dbus-launch because it is in dbus-1-x11.rpm
4
+ # Sets up a private session bus and call the specified program
5
+ set -o errexit
6
+
7
+ # This launches the bus daemon,
8
+ # exports DBUS_SESSION_BUS_ADDRESS and sets DBUS_SESSION_BUS_PID
9
+ my_dbus_launch () {
10
+ # reimplementing dbus-launch because it is in dbus-1-x11.rpm
11
+ PF=`mktemp dbus.pid.XXXXXX` || exit
12
+ AF=`mktemp dbus.addr.XXXXXX` || exit
13
+ RM_FILES="$RM_FILES $PF $AF"
14
+
15
+ dbus-daemon --config-file=dbus-limited-session.conf --print-address=3 3>$AF --print-pid=4 4>$PF &
16
+ # wait for the daemon to print the info
17
+ TRIES=0
18
+ while [ ! -s $AF -o ! -s $PF ]; do
19
+ sleep 0.1
20
+ TRIES=`expr $TRIES + 1`
21
+ if [ $TRIES -gt 100 ]; then echo "dbus-daemon failed?"; exit 1; fi
22
+ done
23
+ DBUS_SESSION_BUS_PID=$(cat $PF)
24
+ export DBUS_SESSION_BUS_ADDRESS=$(cat $AF)
25
+ KILLS="$KILLS $DBUS_SESSION_BUS_PID"
26
+ # dbus-monitor &
27
+ }
28
+
29
+ my_dbus_launch
30
+
31
+ # Clean up at exit.
32
+ trap "kill \$KILLS; rm -rf \$RM_FILES" EXIT TERM INT
33
+
34
+ # run the payload; the return value is passed on
35
+ "$@"
@@ -0,0 +1,28 @@
1
+ <!-- This configuration file controls the testing message bus.
2
+ It is based on a session bus config. -->
3
+
4
+ <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
5
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
6
+ <busconfig>
7
+ <!-- Our well-known bus type, don't change this -->
8
+ <type>session</type>
9
+
10
+ <listen>unix:tmpdir=/tmp</listen>
11
+ <listen>tcp:host=localhost,port=0,family=ipv4</listen>
12
+
13
+ <standard_session_servicedirs />
14
+
15
+ <policy context="default">
16
+ <!-- Allow everything to be sent -->
17
+ <allow send_destination="*" eavesdrop="true"/>
18
+ <!-- Allow everything to be received -->
19
+ <allow eavesdrop="true"/>
20
+ <!-- Allow anyone to own anything -->
21
+ <allow own="*"/>
22
+ </policy>
23
+
24
+ <!-- Do not increase the limits.
25
+ Instead, lower some so that we can test resource leaks. -->
26
+ <limit name="max_match_rules_per_connection">50</limit><!-- was 512 -->
27
+
28
+ </busconfig>
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ require "test/unit"
3
+ require "dbus"
4
+
5
+ class PropertyTest < Test::Unit::TestCase
6
+ def setup
7
+ session_bus = DBus::ASessionBus.new
8
+ svc = session_bus.service("org.ruby.service")
9
+ @obj = svc.object("/org/ruby/MyInstance")
10
+ @obj.introspect
11
+ @iface = @obj["org.ruby.SampleInterface"]
12
+ end
13
+
14
+ def test_property_reading
15
+ assert_equal "READ ME", @iface["ReadMe"]
16
+ end
17
+
18
+ def test_property_nonreading
19
+ e = assert_raises DBus::Error do
20
+ @iface["WriteMe"]
21
+ end
22
+ assert_match(/not readable/, e.to_s)
23
+ end
24
+
25
+ def test_property_writing
26
+ @iface["ReadOrWriteMe"] = "VALUE"
27
+ assert_equal "VALUE", @iface["ReadOrWriteMe"]
28
+ end
29
+
30
+ def test_property_nonwriting
31
+ e = assert_raises DBus::Error do
32
+ @iface["ReadMe"] = "WROTE"
33
+ end
34
+ assert_match(/not writable/, e.to_s)
35
+ end
36
+
37
+ def test_get_all
38
+ all = @iface.all_properties
39
+ assert_equal ["ReadMe", "ReadOrWriteMe"], all.keys.sort
40
+ end
41
+
42
+ def test_unknown_property_reading
43
+ e = assert_raises DBus::Error do
44
+ @iface["Spoon"]
45
+ end
46
+ assert_match(/not found/, e.to_s)
47
+ end
48
+
49
+ def test_unknown_property_writing
50
+ e = assert_raises DBus::Error do
51
+ @iface["Spoon"] = "FORK"
52
+ end
53
+ assert_match(/not found/, e.to_s)
54
+ end
55
+ end
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ # Test that a server survives various error cases
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ class ServerRobustnessTest < Test::Unit::TestCase
7
+ def setup
8
+ @bus = DBus::ASessionBus.new
9
+ @svc = @bus.service("org.ruby.service")
10
+ end
11
+
12
+ # https://trac.luon.net/ruby-dbus/ticket/31
13
+ # the server should not crash
14
+ def test_no_such_path_with_introspection
15
+ obj = @svc.object "/org/ruby/NotMyInstance"
16
+ obj.introspect
17
+ assert false, "should have raised"
18
+ rescue DBus::Error => e
19
+ assert_no_match(/timeout/, e.to_s)
20
+ end
21
+
22
+ def test_no_such_path_without_introspection
23
+ obj = @svc.object "/org/ruby/NotMyInstance"
24
+ ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
25
+ ifc.define_method("the_answer", "out n:i")
26
+ ifc.the_answer
27
+ assert false, "should have raised"
28
+ rescue DBus::Error => e
29
+ assert_no_match(/timeout/, e.to_s)
30
+ end
31
+
32
+ def test_a_method_that_raises
33
+ obj = @svc.object "/org/ruby/MyInstance"
34
+ obj.introspect
35
+ obj.default_iface = "org.ruby.SampleInterface"
36
+ obj.will_raise
37
+ assert false, "should have raised"
38
+ rescue DBus::Error => e
39
+ assert_no_match(/timeout/, e.to_s)
40
+ end
41
+
42
+ def test_a_method_that_raises_name_error
43
+ obj = @svc.object "/org/ruby/MyInstance"
44
+ obj.introspect
45
+ obj.default_iface = "org.ruby.SampleInterface"
46
+ obj.will_raise_name_error
47
+ assert false, "should have raised"
48
+ rescue DBus::Error => e
49
+ assert_no_match(/timeout/, e.to_s)
50
+ end
51
+
52
+ # https://trac.luon.net/ruby-dbus/ticket/31#comment:3
53
+ def test_no_such_method_without_introspection
54
+ obj = @svc.object "/org/ruby/MyInstance"
55
+ ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
56
+ ifc.define_method("not_the_answer", "out n:i")
57
+ ifc.not_the_answer
58
+ assert false, "should have raised"
59
+ rescue DBus::Error => e
60
+ assert_no_match(/timeout/, e)
61
+ end
62
+
63
+ def test_no_such_interface_without_introspection
64
+ obj = @svc.object "/org/ruby/MyInstance"
65
+ ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.NoSuchInterface")
66
+ ifc.define_method("the_answer", "out n:i")
67
+ ifc.the_answer
68
+ assert false, "should have raised"
69
+ rescue DBus::Error => e
70
+ assert_no_match(/timeout/, e)
71
+ end
72
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # Test that a server survives various error cases
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ class Foo < DBus::Object
7
+ dbus_interface "org.ruby.ServerTest" do
8
+ dbus_signal :signal_without_arguments
9
+ dbus_signal :signal_with_argument, "epsilon:d"
10
+ end
11
+
12
+ dbus_signal :signal_without_interface
13
+ rescue DBus::Object::UndefinedInterface => e
14
+ # raised by the preceding signal declaration
15
+ end
16
+
17
+ class Bar < DBus::Object
18
+ dbus_interface "org.ruby.ServerTest" do
19
+ # a valid Ruby symbol but an invalid DBus name; Ticket#38
20
+ dbus_signal :signal_with_a_bang!
21
+ end
22
+ rescue DBus::InvalidMethodName
23
+ # raised by the preceding signal declaration
24
+ end
25
+
26
+ class ServerTest < Test::Unit::TestCase
27
+ def setup
28
+ @bus = DBus::ASessionBus.new
29
+ @svc = @bus.request_service "org.ruby.server-test"
30
+ end
31
+
32
+ def teardown
33
+ @bus.proxy.ReleaseName "org.ruby.server-test"
34
+ end
35
+
36
+ def test_unexporting_an_object
37
+ obj = Foo.new "/org/ruby/Foo"
38
+ @svc.export obj
39
+ assert @svc.unexport(obj)
40
+ end
41
+
42
+ def test_unexporting_an_object_not_exported
43
+ obj = Foo.new "/org/ruby/Foo"
44
+ assert !@svc.unexport(obj)
45
+ end
46
+
47
+ def test_emiting_signals
48
+ obj = Foo.new "/org/ruby/Foo"
49
+ @svc.export obj
50
+ obj.signal_without_arguments
51
+ obj.signal_with_argument(-0.1)
52
+ end
53
+ end
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # find the library without external help
4
+ $:.unshift File.expand_path("../../lib", __FILE__)
5
+
6
+ require 'dbus'
7
+
8
+ def d(msg)
9
+ puts "#{$$} #{msg}" if $DEBUG
10
+ end
11
+
12
+ PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
13
+
14
+ class Test < DBus::Object
15
+ INTERFACE = "org.ruby.SampleInterface"
16
+ def initialize(path)
17
+ super path
18
+ @read_me = "READ ME"
19
+ @read_or_write_me = "READ OR WRITE ME"
20
+ end
21
+
22
+ # Create an interface aggregating all upcoming dbus_method defines.
23
+ dbus_interface INTERFACE do
24
+ dbus_method :hello, "in name:s, in name2:s" do |name, name2|
25
+ puts "hello(#{name}, #{name2})"
26
+ end
27
+
28
+ dbus_method :test_variant, "in stuff:v" do |variant|
29
+ p variant
30
+ end
31
+
32
+ dbus_method :bounce_variant, "in stuff:v, out chaff:v" do |variant|
33
+ [variant]
34
+ end
35
+
36
+ dbus_method :variant_size, "in stuff:v, out size:u" do |variant|
37
+ [variant.size]
38
+ end
39
+
40
+ dbus_method :the_answer, "out answer:i" do
41
+ 42
42
+ end
43
+
44
+ dbus_method :will_raise, "" do
45
+ raise "Handle this"
46
+ end
47
+
48
+ dbus_method :will_raise_error_failed, "" do
49
+ raise DBus.error, "failed as designed"
50
+ end
51
+
52
+ dbus_method :will_raise_name_error, "" do
53
+ "foo".frobnicate
54
+ end
55
+
56
+ dbus_method :Error, "in name:s, in description:s" do |name, description|
57
+ raise DBus.error(name), description
58
+ end
59
+
60
+ dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
61
+ end
62
+
63
+ dbus_interface "org.ruby.AnotherInterface" do
64
+ dbus_method :ThatsALongMethodNameIThink do
65
+ puts "ThatsALongMethodNameIThink"
66
+ end
67
+ dbus_method :Reverse, "in instr:s, out outstr:s" do |instr|
68
+ outstr = instr.split(//).reverse.join
69
+ puts "got: #{instr}, replying: #{outstr}"
70
+ [outstr]
71
+ end
72
+ end
73
+
74
+ dbus_interface "org.ruby.Ticket30" do
75
+ dbus_method :Sybilla, 'in choices:av, out advice:s' do |choices|
76
+ ["Do #{choices[0]}"]
77
+ end
78
+ end
79
+
80
+ dbus_interface "org.ruby.Loop" do
81
+ # starts doing something long, but returns immediately
82
+ # and sends a signal when done
83
+ dbus_method :LongTaskBegin, 'in delay:i' do |delay|
84
+ # FIXME did not complain about mismatch between signature and block args
85
+ d "Long task began"
86
+ task = Thread.new do
87
+ d "Long task thread started (#{delay}s)"
88
+ sleep delay
89
+ d "Long task will signal end"
90
+ self.LongTaskEnd
91
+ end
92
+ task.abort_on_exception = true # protect from test case bugs
93
+ end
94
+
95
+ dbus_signal :LongTaskEnd
96
+ end
97
+
98
+ # Properties:
99
+ # ReadMe:string, returns "READ ME" at first, then what WriteMe received
100
+ # WriteMe:string
101
+ # ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
102
+ dbus_interface PROPERTY_INTERFACE do
103
+ dbus_method :Get, "in interface:s, in propname:s, out value:v" do |interface, propname|
104
+ if interface == INTERFACE
105
+ if propname == "ReadMe"
106
+ [@read_me]
107
+ elsif propname == "ReadOrWriteMe"
108
+ [@read_or_write_me]
109
+ elsif propname == "WriteMe"
110
+ raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"), "Property '#{interface}.#{propname}' (on object '#{@path}') is not readable"
111
+ else
112
+ raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"), "Property '#{interface}.#{propname}' not found on object '#{@path}'"
113
+ end
114
+ else
115
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"), "Interface '#{interface}' not found on object '#{@path}'"
116
+ end
117
+ # what should happen for unknown properties
118
+ # plasma: InvalidArgs (propname), UnknownInterface (interface)
119
+ end
120
+
121
+ dbus_method :Set, "in interface:s, in propname:s, in value:v" do |interface, propname, value|
122
+ if interface == INTERFACE
123
+ if propname == "ReadMe"
124
+ raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"), "Property '#{interface}.#{propname}' (on object '#{@path}') is not writable"
125
+ elsif propname == "ReadOrWriteMe"
126
+ @read_or_write_me = value
127
+ self.PropertiesChanged(interface, {propname => value}, [])
128
+ elsif propname == "WriteMe"
129
+ @read_me = value
130
+ self.PropertiesChanged(interface, {"ReadMe" => value}, [])
131
+ else
132
+ raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"), "Property '#{interface}.#{propname}' not found on object '#{@path}'"
133
+ end
134
+ else
135
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"), "Interface '#{interface}' not found on object '#{@path}'"
136
+ end
137
+ end
138
+
139
+ dbus_method :GetAll, "in interface:s, out value:a{sv}" do |interface|
140
+ if interface == INTERFACE
141
+ [ {
142
+ "ReadMe" => @read_me,
143
+ "ReadOrWriteMe" =>@read_or_write_me,
144
+ } ]
145
+ else
146
+ raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"), "Interface '#{interface}' not found on object '#{@path}'"
147
+ end
148
+ end
149
+
150
+ dbus_signal :PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
151
+ end
152
+ end
153
+
154
+ class Derived < Test
155
+ end
156
+
157
+ class Test2 < DBus::Object
158
+ dbus_interface "org.ruby.Test2" do
159
+ dbus_method :hi, "in name:s, out greeting:s" do |name|
160
+ "Hi, #{name}!"
161
+ end
162
+ end
163
+ end
164
+
165
+ bus = DBus::SessionBus.instance
166
+ service = bus.request_service("org.ruby.service")
167
+ myobj = Test.new("/org/ruby/MyInstance")
168
+ service.export(myobj)
169
+ derived = Derived.new "/org/ruby/MyDerivedInstance"
170
+ service.export derived
171
+ test2 = Test2.new "/org/ruby/MyInstance2"
172
+ service.export test2
173
+
174
+ # introspect every other connection, Ticket #34
175
+ # (except the one that activates us - it has already emitted
176
+ # NOC by the time we run this. Therefore the test for #34 will not work
177
+ # by running t2.rb alone, one has to run t1 before it; 'rake' does it)
178
+ mr = DBus::MatchRule.new.from_s "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
179
+ bus.add_match(mr) do |msg|
180
+ new_unique_name = msg.params[2]
181
+ unless new_unique_name.empty?
182
+ d "RRRING #{new_unique_name}"
183
+ bus.introspect_data(new_unique_name, "/") do
184
+ # ignore the result
185
+ end
186
+ end
187
+ end
188
+
189
+ puts "listening"
190
+ main = DBus::Main.new
191
+ main << bus
192
+ begin
193
+ main.run
194
+ rescue SystemCallError
195
+ # the test driver will kill the bus, that's OK
196
+ end
197
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require "test/unit"
3
+ require "dbus"
4
+
5
+ def d(msg)
6
+ puts msg if $DEBUG
7
+ end
8
+
9
+ class SessionBusAddressTest < Test::Unit::TestCase
10
+ def setup
11
+ # test getting the session bus address even if unset in ENV (Issue#4)
12
+ ENV.delete "DBUS_SESSION_BUS_ADDRESS"
13
+ @bus = DBus::ASessionBus.new
14
+ @svc = @bus.service("org.freedesktop.DBus")
15
+ end
16
+
17
+ def test_connection
18
+ assert @svc.exists?
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # Test the signal handlers
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ def d(msg)
7
+ puts "#{$$} #{msg}" if $DEBUG
8
+ end
9
+
10
+ class SignalHandlerTest < Test::Unit::TestCase
11
+ def setup
12
+ @session_bus = DBus::ASessionBus.new
13
+ svc = @session_bus.service("org.ruby.service")
14
+ @obj = svc.object("/org/ruby/MyInstance")
15
+ @obj.introspect # necessary
16
+ @obj.default_iface = "org.ruby.Loop"
17
+
18
+ @loop = DBus::Main.new
19
+ @loop << @session_bus
20
+ end
21
+
22
+ # testing for commit 017c83 (kkaempf)
23
+ def test_overriding_a_handler
24
+ counter = 0
25
+
26
+ @obj.on_signal "LongTaskEnd" do
27
+ d "+10"
28
+ counter += 10
29
+ end
30
+ @obj.on_signal "LongTaskEnd" do
31
+ d "+1"
32
+ counter += 1
33
+ end
34
+
35
+ d "will begin"
36
+ @obj.LongTaskBegin 3
37
+
38
+ quitter = Thread.new do
39
+ d "sleep before quit"
40
+ # FIXME if we sleep for too long
41
+ # the socket will be drained and we deadlock in a select.
42
+ # It could be worked around by sending ourselves a Unix signal
43
+ # (with a dummy handler) to interrupt the select
44
+ sleep 1
45
+ d "will quit"
46
+ @loop.quit
47
+ end
48
+ @loop.run
49
+
50
+ assert_equal 1, counter
51
+ end
52
+
53
+ def test_too_many_rules
54
+ 100.times do
55
+ @obj.on_signal "Whichever" do
56
+ puts "not called"
57
+ end
58
+ end
59
+ end
60
+
61
+ def test_removing_a_nonexistent_rule
62
+ @obj.on_signal "DoesNotExist"
63
+ end
64
+ end
data/test/t1 ADDED
@@ -0,0 +1,4 @@
1
+ #! /bin/sh
2
+ SEND0="dbus-send --session --dest=org.ruby.service"
3
+ CALL="$SEND0 --type=method_call --print-reply"
4
+ $CALL /org/ruby/MyInstance org.ruby.AnotherInterface.Reverse string:Hello
data/test/t2.rb ADDED
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+ require "test/unit"
3
+ require "dbus"
4
+
5
+ class ValueTest < Test::Unit::TestCase
6
+ def setup
7
+ session_bus = DBus::ASessionBus.new
8
+ svc = session_bus.service("org.ruby.service")
9
+ @obj = svc.object("/org/ruby/MyInstance")
10
+ @obj.introspect # necessary
11
+ @obj.default_iface = "org.ruby.SampleInterface"
12
+ end
13
+
14
+ def test_passing_an_array_through_a_variant
15
+ # old explicit typing
16
+ @obj.test_variant(["as", ["coucou", "kuku"]])
17
+ # automatic typing
18
+ @obj.test_variant(["coucou", "kuku"])
19
+ @obj.test_variant(["saint", "was that a word or a signature?"])
20
+ end
21
+
22
+ def test_bouncing_a_variant
23
+ assert_equal "cuckoo", @obj.bounce_variant("cuckoo")[0]
24
+ assert_equal ["coucou", "kuku"], @obj.bounce_variant(["coucou", "kuku"])[0]
25
+ assert_equal [], @obj.bounce_variant([])[0]
26
+ empty_hash = {}
27
+ assert_equal empty_hash, @obj.bounce_variant(empty_hash)[0]
28
+ end
29
+
30
+ # these are ambiguous
31
+ def test_pairs_with_a_string
32
+
33
+ # deprecated
34
+ assert_equal "foo", @obj.bounce_variant(["s", "foo"])[0]
35
+
36
+ assert_equal "foo", @obj.bounce_variant(DBus.variant("s", "foo"))[0]
37
+ assert_equal "foo", @obj.bounce_variant([DBus.type("s"), "foo"])[0]
38
+
39
+ # does not work, because the server side forgets the explicit typing
40
+ # assert_equal ["s", "foo"], @obj.bounce_variant(["av", ["s", "foo"]])[0]
41
+ # assert_equal ["s", "foo"], @obj.bounce_variant(["as", ["s", "foo"]])[0]
42
+
43
+ # instead, use this to demonstrate that the variant is passed as expected
44
+ assert_equal 4, @obj.variant_size(["s", "four"])[0]
45
+ # "av" is the simplest thing that will work,
46
+ # shifting the heuristic from a pair to the individual items
47
+ assert_equal 2, @obj.variant_size(["av", ["s", "four"]])[0]
48
+ end
49
+
50
+ def test_marshalling_an_array_of_variants
51
+ # https://trac.luon.net/ruby-dbus/ticket/30
52
+ @obj.default_iface = "org.ruby.Ticket30"
53
+ choices = []
54
+ choices << ['s', 'Plan A']
55
+ choices << ['s', 'Plan B']
56
+ # old explicit typing
57
+ assert_equal "Do Plan A", @obj.Sybilla(choices)[0]
58
+ # automatic typing
59
+ assert_equal "Do Plan A", @obj.Sybilla(["Plan A", "Plan B"])[0]
60
+ end
61
+
62
+ def test_service_returning_nonarray
63
+ # "warning: default `to_a' will be obsolete"
64
+ @obj.the_answer
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # Test passing a particular struct array through a variant
3
+ # https://trac.luon.net/ruby-dbus/ticket/27
4
+ require "dbus"
5
+ session_bus = DBus::ASessionBus.new
6
+ svc = session_bus.service("org.ruby.service")
7
+ obj = svc.object("/org/ruby/MyInstance")
8
+ obj.introspect # necessary
9
+ obj.default_iface = "org.ruby.SampleInterface"
10
+ # The bug is probably alignment related so whether it triggers
11
+ # depends also on the combined length of service, interface,
12
+ # and method names. Luckily here it works out.
13
+ triple = ['a(uuu)', []]
14
+ obj.test_variant(triple)
15
+ quadruple = ['a(uuuu)', []] # a(uuu) works fine
16
+ # The bus disconnects us because of malformed message,
17
+ # code 12: DBUS_INVALID_TOO_MUCH_DATA
18
+ obj.test_variant(quadruple)
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ # should report it missing on org.ruby.SampleInterface
3
+ # (on object...) instead of on DBus::Proxy::ObjectInterface
4
+ require "test/unit"
5
+ require "dbus"
6
+
7
+ class ErrMsgTest < Test::Unit::TestCase
8
+ def setup
9
+ session_bus = DBus::ASessionBus.new
10
+ svc = session_bus.service("org.ruby.service")
11
+ @obj = svc.object("/org/ruby/MyInstance")
12
+ @obj.introspect # necessary
13
+ @obj.default_iface = "org.ruby.SampleInterface"
14
+ end
15
+
16
+ def test_report_dbus_interface
17
+ begin
18
+ @obj.NoSuchMethod
19
+ # a specific exception...
20
+ rescue NameError => e
21
+ # mentioning DBus and the interface
22
+ assert_match(/DBus interface.*#{@obj.default_iface}/, e.to_s)
23
+ end
24
+ end
25
+
26
+ def test_report_short_struct
27
+ begin
28
+ @obj.test_variant ["(ss)", ["too few"] ]
29
+ rescue DBus::TypeException => e
30
+ assert_match(/1 elements but type info for 2/, e.to_s)
31
+ end
32
+ end
33
+
34
+ def test_report_long_struct
35
+ begin
36
+ @obj.test_variant ["(ss)", ["a", "b", "too many"] ]
37
+ rescue DBus::TypeException => e
38
+ assert_match(/3 elements but type info for 2/, e.to_s)
39
+ end
40
+ end
41
+
42
+ def test_report_nil
43
+ nils = [
44
+ ["(s)", [nil] ], # would get disconnected
45
+ ["i", nil ],
46
+ ["a{ss}", {"foo" => nil} ],
47
+ ]
48
+ nils.each do |has_nil|
49
+ begin
50
+ @obj.test_variant has_nil
51
+ rescue DBus::TypeException => e
52
+ # TODO want backtrace from the perspective of the caller:
53
+ # rescue/reraise in send_sync?
54
+ assert_match(/Cannot send nil/, e.to_s)
55
+ end
56
+ end
57
+ end
58
+ end