ruby-dbus-openplacos 0.6.0

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