actionwebservice 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/{ChangeLog → CHANGELOG} +20 -0
  2. data/README +45 -1
  3. data/Rakefile +12 -10
  4. data/TODO +8 -9
  5. data/lib/action_web_service.rb +10 -6
  6. data/lib/action_web_service/api.rb +1 -2
  7. data/lib/action_web_service/api/{abstract.rb → base.rb} +14 -71
  8. data/lib/action_web_service/base.rb +0 -3
  9. data/lib/action_web_service/client/base.rb +1 -12
  10. data/lib/action_web_service/client/soap_client.rb +49 -17
  11. data/lib/action_web_service/client/xmlrpc_client.rb +20 -15
  12. data/lib/action_web_service/container.rb +3 -85
  13. data/lib/action_web_service/{api/action_controller.rb → container/action_controller_container.rb} +2 -2
  14. data/lib/action_web_service/container/delegated_container.rb +87 -0
  15. data/lib/action_web_service/container/direct_container.rb +70 -0
  16. data/lib/action_web_service/dispatcher/abstract.rb +100 -102
  17. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +199 -137
  18. data/lib/action_web_service/protocol.rb +1 -1
  19. data/lib/action_web_service/protocol/abstract.rb +14 -112
  20. data/lib/action_web_service/protocol/discovery.rb +37 -0
  21. data/lib/action_web_service/protocol/soap_protocol.rb +32 -458
  22. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +29 -149
  23. data/lib/action_web_service/struct.rb +2 -5
  24. data/lib/action_web_service/test_invoke.rb +130 -0
  25. data/lib/action_web_service/vendor/ws.rb +4 -0
  26. data/lib/action_web_service/vendor/ws/common.rb +8 -0
  27. data/lib/action_web_service/vendor/ws/encoding.rb +3 -0
  28. data/lib/action_web_service/vendor/ws/encoding/abstract.rb +26 -0
  29. data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +90 -0
  30. data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +53 -0
  31. data/lib/action_web_service/vendor/ws/marshaling.rb +3 -0
  32. data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +17 -0
  33. data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +277 -0
  34. data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +116 -0
  35. data/lib/action_web_service/vendor/ws/types.rb +162 -0
  36. data/test/abstract_client.rb +8 -11
  37. data/test/abstract_dispatcher.rb +370 -0
  38. data/test/abstract_unit.rb +1 -0
  39. data/test/api_test.rb +18 -1
  40. data/test/apis/auto_load_api.rb +3 -0
  41. data/test/apis/broken_auto_load_api.rb +2 -0
  42. data/test/client_soap_test.rb +16 -3
  43. data/test/client_xmlrpc_test.rb +16 -4
  44. data/test/container_test.rb +28 -8
  45. data/test/dispatcher_action_controller_soap_test.rb +106 -0
  46. data/test/dispatcher_action_controller_xmlrpc_test.rb +44 -0
  47. data/test/gencov +1 -1
  48. data/test/invocation_test.rb +39 -3
  49. data/test/run +4 -4
  50. data/test/test_invoke_test.rb +77 -0
  51. data/test/ws/abstract_encoding.rb +68 -0
  52. data/test/ws/abstract_unit.rb +13 -0
  53. data/test/ws/gencov +3 -0
  54. data/test/ws/run +5 -0
  55. data/test/ws/soap_marshaling_test.rb +91 -0
  56. data/test/ws/soap_rpc_encoding_test.rb +47 -0
  57. data/test/ws/types_test.rb +41 -0
  58. data/test/ws/xmlrpc_encoding_test.rb +34 -0
  59. metadata +48 -19
  60. data/lib/action_web_service/protocol/registry.rb +0 -55
  61. data/lib/action_web_service/support/signature.rb +0 -100
  62. data/test/abstract_soap.rb +0 -58
  63. data/test/dispatcher_action_controller_test.rb +0 -186
  64. data/test/protocol_registry_test.rb +0 -53
  65. data/test/protocol_soap_test.rb +0 -252
  66. data/test/protocol_xmlrpc_test.rb +0 -147
@@ -1,4 +1,5 @@
1
1
  $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib/action_web_service/vendor')
2
3
 
3
4
  require 'test/unit'
4
5
  require 'action_web_service'
@@ -41,7 +41,7 @@ class TC_API < Test::Unit::TestCase
41
41
  assert_equal({:expects=>nil, :returns=>[Integer, [String]]}, API.api_methods[:returns])
42
42
  assert_equal({:expects=>[{:appkey=>Integer}, {:publish=>TrueClass}], :returns=>nil}, API.api_methods[:named_signature])
43
43
  assert_equal({:expects=>[Integer, String, TrueClass], :returns=>nil}, API.api_methods[:string_types])
44
- assert_equal({:expects=>[TrueClass, Bignum, String], :returns=>nil}, API.api_methods[:class_types])
44
+ assert_equal({:expects=>[TrueClass, Integer, String], :returns=>nil}, API.api_methods[:class_types])
45
45
  end
46
46
 
47
47
  def test_not_instantiable
@@ -49,4 +49,21 @@ class TC_API < Test::Unit::TestCase
49
49
  API.new
50
50
  end
51
51
  end
52
+
53
+ def test_api_errors
54
+ assert_raises(ActionWebService::ActionWebServiceError) do
55
+ klass = Class.new(ActionWebService::API::Base) do
56
+ api_method :test, :expects => [ActiveRecord::Base]
57
+ end
58
+ end
59
+ klass = Class.new(ActionWebService::API::Base) do
60
+ allow_active_record_expects true
61
+ api_method :test2, :expects => [ActiveRecord::Base]
62
+ end
63
+ assert_raises(ActionWebService::ActionWebServiceError) do
64
+ klass = Class.new(ActionWebService::API::Base) do
65
+ api_method :test, :invalid => [:int]
66
+ end
67
+ end
68
+ end
52
69
  end
@@ -0,0 +1,3 @@
1
+ class AutoLoadAPI < ActionWebService::API::Base
2
+ api_method :void
3
+ end
@@ -12,10 +12,10 @@ module ClientSoapTest
12
12
  test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
13
13
  test_request.env['HTTP_SOAPACTION'] = req.header['soapaction'][0]
14
14
  test_request.env['RAW_POST_DATA'] = req.body
15
- protocol_request = @controller.protocol_request(test_request)
16
- response = @controller.dispatch_request(protocol_request)
15
+ response = ActionController::TestResponse.new
16
+ @controller.process(test_request, response)
17
17
  res.header['content-type'] = 'text/xml'
18
- res.body = response.raw_body
18
+ res.body = response.body
19
19
  rescue Exception => e
20
20
  $stderr.puts e.message
21
21
  $stderr.puts e.backtrace.join("\n")
@@ -24,10 +24,15 @@ module ClientSoapTest
24
24
 
25
25
  class ClientContainer < ActionController::Base
26
26
  web_client_api :client, :soap, "http://localhost:#{PORT}/client/api", :api => ClientTest::API
27
+ web_client_api :invalid, :null, "", :api => true
27
28
 
28
29
  def get_client
29
30
  client
30
31
  end
32
+
33
+ def get_invalid
34
+ invalid
35
+ end
31
36
  end
32
37
 
33
38
  class SoapServer < ClientTest::AbstractServer
@@ -83,6 +88,7 @@ class TC_ClientSoap < Test::Unit::TestCase
83
88
 
84
89
  def test_client_container
85
90
  assert_equal(50, ClientContainer.new.get_client.client_container)
91
+ assert(ClientContainer.new.get_invalid.nil?)
86
92
  end
87
93
 
88
94
  def test_named_parameters
@@ -90,4 +96,11 @@ class TC_ClientSoap < Test::Unit::TestCase
90
96
  assert(@client.named_parameters("key", 5).nil?)
91
97
  assert_equal(["key", 5], @container.value_named_parameters)
92
98
  end
99
+
100
+ def test_capitalized_method_name
101
+ @container.value_normal = nil
102
+ assert_equal(5, @client.Normal(5, 6))
103
+ assert_equal([5, 6], @container.value_normal)
104
+ @container.value_normal = nil
105
+ end
93
106
  end
@@ -9,12 +9,12 @@ module ClientXmlRpcTest
9
9
  test_request = ActionController::TestRequest.new
10
10
  test_request.request_parameters['action'] = req.path.gsub(/^\//, '').split(/\//)[1]
11
11
  test_request.env['REQUEST_METHOD'] = "POST"
12
- test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
12
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
13
13
  test_request.env['RAW_POST_DATA'] = req.body
14
- protocol_request = @controller.protocol_request(test_request)
15
- response = @controller.dispatch_request(protocol_request)
14
+ response = ActionController::TestResponse.new
15
+ @controller.process(test_request, response)
16
16
  res.header['content-type'] = 'text/xml'
17
- res.body = response.raw_body
17
+ res.body = response.body
18
18
  rescue Exception => e
19
19
  $stderr.puts e.message
20
20
  $stderr.puts e.backtrace.join("\n")
@@ -89,4 +89,16 @@ class TC_ClientXmlRpc < Test::Unit::TestCase
89
89
  assert_equal(true, @client.named_parameters("xxx", 7))
90
90
  assert_equal(["xxx", 7], @container.value_named_parameters)
91
91
  end
92
+
93
+ def test_exception
94
+ assert_raises(ActionWebService::Client::ClientError) do
95
+ assert(@client.thrower)
96
+ end
97
+ end
98
+
99
+ def test_invalid_signature
100
+ assert_raises(ActionWebService::Client::ClientError) do
101
+ @client.normal
102
+ end
103
+ end
92
104
  end
@@ -1,7 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/abstract_unit'
2
2
 
3
3
  module ContainerTest
4
-
5
4
  $immediate_service = Object.new
6
5
  $deferred_service = Object.new
7
6
 
@@ -22,22 +21,34 @@ module ContainerTest
22
21
 
23
22
  class DirectContainer < ActionController::Base
24
23
  web_service_dispatching_mode :direct
25
- end
24
+ end
25
+
26
+ class InvalidContainer
27
+ include ActionWebService::Container::Direct
28
+ end
26
29
  end
27
30
 
28
31
  class TC_Container < Test::Unit::TestCase
32
+ include ContainerTest
33
+
29
34
  def setup
30
- @delegate_container = ContainerTest::DelegateContainer.new
31
- @direct_container = ContainerTest::DirectContainer.new
35
+ @delegate_container = DelegateContainer.new
36
+ @direct_container = DirectContainer.new
32
37
  end
33
38
 
34
39
  def test_registration
35
- assert(ContainerTest::DelegateContainer.has_web_service?(:immediate_service))
36
- assert(ContainerTest::DelegateContainer.has_web_service?(:deferred_service))
37
- assert(!ContainerTest::DelegateContainer.has_web_service?(:fake_service))
40
+ assert(DelegateContainer.has_web_service?(:immediate_service))
41
+ assert(DelegateContainer.has_web_service?(:deferred_service))
42
+ assert(!DelegateContainer.has_web_service?(:fake_service))
43
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
44
+ DelegateContainer.web_service('invalid')
45
+ end
38
46
  end
39
47
 
40
48
  def test_service_object
49
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
50
+ @delegate_container.web_service_object(:nonexistent)
51
+ end
41
52
  assert(@delegate_container.flag == true)
42
53
  assert(@delegate_container.web_service_object(:immediate_service) == $immediate_service)
43
54
  assert(@delegate_container.previous_flag.nil?)
@@ -48,6 +59,15 @@ class TC_Container < Test::Unit::TestCase
48
59
  end
49
60
 
50
61
  def test_direct_container
51
- assert(ContainerTest::DirectContainer.web_service_dispatching_mode == :direct)
62
+ assert(DirectContainer.web_service_dispatching_mode == :direct)
63
+ end
64
+
65
+ def test_validity
66
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
67
+ InvalidContainer.web_service_api :test
68
+ end
69
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
70
+ InvalidContainer.web_service_api 50.0
71
+ end
52
72
  end
53
73
  end
@@ -0,0 +1,106 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/apis')
2
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
3
+ require 'wsdl/parser'
4
+
5
+ class AutoLoadController < ActionController::Base; end
6
+ class FailingAutoLoadController < ActionController::Base; end
7
+ class BrokenAutoLoadController < ActionController::Base; end
8
+
9
+ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
10
+ include DispatcherTest
11
+ include DispatcherCommonTests
12
+
13
+ def setup
14
+ @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
15
+ @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
16
+ @direct_controller = DirectController.new
17
+ @delegated_controller = DelegatedController.new
18
+ @virtual_controller = VirtualController.new
19
+ end
20
+
21
+ def test_wsdl_generation
22
+ ensure_valid_wsdl_generation DelegatedController.new
23
+ ensure_valid_wsdl_generation DirectController.new
24
+ end
25
+
26
+ def test_wsdl_action
27
+ delegated_types = ensure_valid_wsdl_action DelegatedController.new
28
+ delegated_names = delegated_types.map{|x| x.name.name}
29
+ assert(delegated_names.include?('DispatcherTest..NodeArray'))
30
+ assert(delegated_names.include?('DispatcherTest..Node'))
31
+ direct_types = ensure_valid_wsdl_action DirectController.new
32
+ direct_names = direct_types.map{|x| x.name.name}
33
+ assert(direct_names.include?('DispatcherTest..NodeArray'))
34
+ assert(direct_names.include?('DispatcherTest..Node'))
35
+ assert(direct_names.include?('IntegerArray'))
36
+ end
37
+
38
+ def test_autoloading
39
+ assert(!AutoLoadController.web_service_api.nil?)
40
+ assert(AutoLoadController.web_service_api.has_public_api_method?('Void'))
41
+ assert(FailingAutoLoadController.web_service_api.nil?)
42
+ assert_raises(LoadError, NameError) do
43
+ FailingAutoLoadController.require_web_service_api :blah
44
+ end
45
+ assert_raises(ArgumentError) do
46
+ FailingAutoLoadController.require_web_service_api 50.0
47
+ end
48
+ assert(BrokenAutoLoadController.web_service_api.nil?)
49
+ end
50
+
51
+ protected
52
+ def exception_message(soap_fault_exception)
53
+ soap_fault_exception.detail.cause.message
54
+ end
55
+
56
+ def is_exception?(obj)
57
+ obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
58
+ obj.detail.cause.is_a?(Exception)
59
+ end
60
+
61
+ def create_ap_request(container, body, public_method_name, *args)
62
+ test_request = ActionController::TestRequest.new
63
+ test_request.request_parameters['action'] = service_name(container)
64
+ test_request.env['REQUEST_METHOD'] = "POST"
65
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
66
+ test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name(container)}/#{public_method_name}"
67
+ test_request.env['RAW_POST_DATA'] = body
68
+ test_request
69
+ end
70
+
71
+ def service_name(container)
72
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
73
+ end
74
+
75
+ def ensure_valid_wsdl_generation(controller)
76
+ wsdl = controller.generate_wsdl
77
+ ensure_valid_wsdl(wsdl)
78
+ end
79
+
80
+ def ensure_valid_wsdl(wsdl)
81
+ definitions = WSDL::Parser.new.parse(wsdl)
82
+ assert(definitions.is_a?(WSDL::Definitions))
83
+ definitions.bindings.each do |binding|
84
+ assert(binding.name.name.index(':').nil?)
85
+ end
86
+ definitions.services.each do |service|
87
+ service.ports.each do |port|
88
+ assert(port.name.name.index(':').nil?)
89
+ end
90
+ end
91
+ types = definitions.collect_complextypes.map{|x| x.name}
92
+ types.each do |type|
93
+ assert(type.namespace == 'urn:ActionWebService')
94
+ end
95
+ definitions.collect_complextypes
96
+ end
97
+
98
+ def ensure_valid_wsdl_action(controller)
99
+ test_request = ActionController::TestRequest.new({ 'action' => 'wsdl' })
100
+ test_request.env['REQUEST_METHOD'] = 'GET'
101
+ test_request.env['HTTP_HOST'] = 'localhost:3000'
102
+ test_response = ActionController::TestResponse.new
103
+ wsdl = controller.process(test_request, test_response).body
104
+ ensure_valid_wsdl(wsdl)
105
+ end
106
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
2
+
3
+ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
4
+ include DispatcherTest
5
+ include DispatcherCommonTests
6
+
7
+ def setup
8
+ @encoder = WS::Encoding::XmlRpcEncoding.new
9
+ @marshaler = WS::Marshaling::XmlRpcMarshaler.new
10
+ @direct_controller = DirectController.new
11
+ @delegated_controller = DelegatedController.new
12
+ @layered_controller = LayeredController.new
13
+ @virtual_controller = VirtualController.new
14
+ end
15
+
16
+ def test_layered_dispatching
17
+ mt_cats = do_method_call(@layered_controller, 'mt.getCategories')
18
+ assert_equal(["mtCat1", "mtCat2"], mt_cats)
19
+ blogger_cats = do_method_call(@layered_controller, 'blogger.getCategories')
20
+ assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
21
+ end
22
+
23
+ protected
24
+ def exception_message(xmlrpc_fault_exception)
25
+ xmlrpc_fault_exception.faultString
26
+ end
27
+
28
+ def is_exception?(obj)
29
+ obj.is_a?(XMLRPC::FaultException)
30
+ end
31
+
32
+ def create_ap_request(container, body, public_method_name, *args)
33
+ test_request = ActionController::TestRequest.new
34
+ test_request.request_parameters['action'] = service_name(container)
35
+ test_request.env['REQUEST_METHOD'] = "POST"
36
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
37
+ test_request.env['RAW_POST_DATA'] = body
38
+ test_request
39
+ end
40
+
41
+ def service_name(container)
42
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  #!/bin/sh
2
2
 
3
- rcov -x '.*_test\.rb,rubygems,abstract_,/run' ./run
3
+ rcov -x '.*_test\.rb,rubygems,abstract_,/run,/apis' ./run
@@ -12,23 +12,46 @@ module InvocationTest
12
12
  api_method :only_two
13
13
  end
14
14
 
15
+ class Interceptor
16
+ attr :args
17
+
18
+ def initialize
19
+ @args = nil
20
+ end
21
+
22
+ def intercept(*args)
23
+ @args = args
24
+ end
25
+ end
26
+
27
+ InterceptorClass = Interceptor.new
28
+
15
29
  class Service < ActionWebService::Base
16
30
  web_service_api API
17
31
 
18
32
  before_invocation :intercept_before, :except => [:no_before]
19
33
  after_invocation :intercept_after, :except => [:no_after]
20
- before_invocation :intercept_only, :only => [:only_one, :only_two]
34
+ prepend_after_invocation :intercept_after_first, :except => [:no_after]
35
+ prepend_before_invocation :intercept_only, :only => [:only_one, :only_two]
36
+ after_invocation(:only => [:only_one]) do |*args|
37
+ args[0].instance_variable_set('@block_invoked', args[1])
38
+ end
39
+ after_invocation InterceptorClass, :only => [:only_one]
21
40
 
22
41
  attr_accessor :before_invoked
23
42
  attr_accessor :after_invoked
43
+ attr_accessor :after_first_invoked
24
44
  attr_accessor :only_invoked
45
+ attr_accessor :block_invoked
25
46
  attr_accessor :invocation_result
26
47
 
27
48
  def initialize
28
49
  @before_invoked = nil
29
50
  @after_invoked = nil
51
+ @after_first_invoked = nil
30
52
  @only_invoked = nil
31
53
  @invocation_result = nil
54
+ @block_invoked = nil
32
55
  end
33
56
 
34
57
  def add(a, b)
@@ -69,6 +92,10 @@ module InvocationTest
69
92
  @after_invoked = name
70
93
  @invocation_result = result
71
94
  end
95
+
96
+ def intercept_after_first(name, args, result)
97
+ @after_first_invoked = name
98
+ end
72
99
 
73
100
  def intercept_only(name, args)
74
101
  raise "Interception error" unless name == :only_one || name == :only_two
@@ -94,11 +121,17 @@ class TC_Invocation < Test::Unit::TestCase
94
121
 
95
122
  def test_interceptor_registration
96
123
  assert(InvocationTest::Service.before_invocation_interceptors.length == 2)
97
- assert(InvocationTest::Service.after_invocation_interceptors.length == 1)
124
+ assert(InvocationTest::Service.after_invocation_interceptors.length == 4)
125
+ assert_equal(:intercept_only, InvocationTest::Service.before_invocation_interceptors[0])
126
+ assert_equal(:intercept_after_first, InvocationTest::Service.after_invocation_interceptors[0])
98
127
  end
99
128
 
100
129
  def test_interception
101
- assert(@service.before_invoked.nil? && @service.after_invoked.nil? && @service.only_invoked.nil? && @service.invocation_result.nil?)
130
+ assert(@service.before_invoked.nil?)
131
+ assert(@service.after_invoked.nil?)
132
+ assert(@service.only_invoked.nil?)
133
+ assert(@service.block_invoked.nil?)
134
+ assert(@service.invocation_result.nil?)
102
135
  perform_invocation(:add, 20, 50)
103
136
  assert(@service.before_invoked == :add)
104
137
  assert(@service.after_invoked == :add)
@@ -124,6 +157,7 @@ class TC_Invocation < Test::Unit::TestCase
124
157
  def test_interception_except_conditions
125
158
  perform_invocation(:no_before)
126
159
  assert(@service.before_invoked.nil?)
160
+ assert(@service.after_first_invoked == :no_before)
127
161
  assert(@service.after_invoked == :no_before)
128
162
  assert(@service.invocation_result == 5)
129
163
  @service.before_invoked = @service.after_invoked = @service.invocation_result = nil
@@ -137,6 +171,8 @@ class TC_Invocation < Test::Unit::TestCase
137
171
  assert(@service.only_invoked.nil?)
138
172
  perform_invocation(:only_one)
139
173
  assert(@service.only_invoked == :only_one)
174
+ assert(@service.block_invoked == :only_one)
175
+ assert(InvocationTest::InterceptorClass.args[1] == :only_one)
140
176
  @service.only_invoked = nil
141
177
  perform_invocation(:only_two)
142
178
  assert(@service.only_invoked == :only_two)
data/test/run CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- Dir[File.join(File.dirname(__FILE__), '*_test.rb')].each do |f|
4
- require f
5
- end
2
+ require 'test/unit'
3
+ args = Dir[File.join(File.dirname(__FILE__), '*_test.rb')] + Dir[File.join(File.dirname(__FILE__), 'ws/*_test.rb')]
4
+ (r = Test::Unit::AutoRunner.new(true)).process_args(args)
5
+ exit r.run