savon 0.6.7 → 0.6.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +17 -4
  2. data/README.textile +14 -25
  3. data/Rakefile +7 -30
  4. data/lib/savon.rb +2 -1
  5. data/lib/savon/client.rb +13 -15
  6. data/lib/savon/core_ext.rb +1 -1
  7. data/lib/savon/core_ext/hash.rb +3 -6
  8. data/lib/savon/request.rb +26 -20
  9. data/lib/savon/soap.rb +33 -17
  10. data/lib/savon/wsdl.rb +19 -8
  11. data/spec/endpoint_helper.rb +14 -53
  12. data/spec/fixtures/response/response_fixture.rb +32 -0
  13. data/spec/fixtures/response/xml/authentication.xml +14 -0
  14. data/spec/fixtures/{soap_fault.xml → response/xml/soap_fault.xml} +0 -0
  15. data/spec/fixtures/{soap_fault12.xml → response/xml/soap_fault12.xml} +0 -0
  16. data/spec/fixtures/wsdl/wsdl_fixture.rb +37 -0
  17. data/spec/fixtures/wsdl/xml/authentication.xml +63 -0
  18. data/spec/fixtures/wsdl/xml/namespaced_actions.xml +307 -0
  19. data/spec/fixtures/wsdl/xml/no_namespace.xml +115 -0
  20. data/spec/http_stubs.rb +11 -11
  21. data/spec/savon/client_spec.rb +46 -41
  22. data/spec/savon/core_ext/datetime_spec.rb +2 -2
  23. data/spec/savon/core_ext/hash_spec.rb +10 -10
  24. data/spec/savon/core_ext/object_spec.rb +2 -2
  25. data/spec/savon/core_ext/string_spec.rb +2 -2
  26. data/spec/savon/core_ext/symbol_spec.rb +1 -1
  27. data/spec/savon/core_ext/uri_spec.rb +1 -1
  28. data/spec/savon/request_spec.rb +5 -3
  29. data/spec/savon/response_spec.rb +7 -7
  30. data/spec/savon/savon_spec.rb +3 -4
  31. data/spec/savon/soap_spec.rb +13 -5
  32. data/spec/savon/wsdl_spec.rb +63 -20
  33. data/spec/spec_helper.rb +3 -2
  34. metadata +16 -14
  35. data/VERSION +0 -1
  36. data/spec/fixtures/multiple_user_response.xml +0 -22
  37. data/spec/fixtures/user_fixture.rb +0 -62
  38. data/spec/fixtures/user_response.xml +0 -15
  39. data/spec/fixtures/user_wsdl.xml +0 -124
@@ -0,0 +1,115 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <definitions name="Api" xmlns:typens="urn:ActionWebService" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="urn:ActionWebService" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/">
3
+ <types>
4
+ <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ActionWebService">
5
+ <xsd:complexType name="MpUser">
6
+ <xsd:all>
7
+ <xsd:element name="avatar_thumb_url" type="xsd:string"/>
8
+ <xsd:element name="speciality" type="xsd:string"/>
9
+ <xsd:element name="avatar_icon_url" type="xsd:string"/>
10
+ <xsd:element name="firstname" type="xsd:string"/>
11
+ <xsd:element name="city" type="xsd:string"/>
12
+ <xsd:element name="mp_id" type="xsd:int"/>
13
+ <xsd:element name="lastname" type="xsd:string"/>
14
+ <xsd:element name="login" type="xsd:string"/>
15
+ </xsd:all>
16
+ </xsd:complexType>
17
+ <xsd:complexType name="MpUserArray">
18
+ <xsd:complexContent>
19
+ <xsd:restriction base="soapenc:Array">
20
+ <xsd:attribute wsdl:arrayType="typens:MpUser[]" ref="soapenc:arrayType"/>
21
+ </xsd:restriction>
22
+ </xsd:complexContent>
23
+ </xsd:complexType>
24
+ <xsd:complexType name="McContact">
25
+ <xsd:all>
26
+ <xsd:element name="last_name" type="xsd:string"/>
27
+ <xsd:element name="email" type="xsd:string"/>
28
+ <xsd:element name="mp_id" type="xsd:int"/>
29
+ <xsd:element name="role" type="xsd:int"/>
30
+ <xsd:element name="login" type="xsd:string"/>
31
+ <xsd:element name="first_name" type="xsd:string"/>
32
+ </xsd:all>
33
+ </xsd:complexType>
34
+ <xsd:complexType name="McContactArray">
35
+ <xsd:complexContent>
36
+ <xsd:restriction base="soapenc:Array">
37
+ <xsd:attribute wsdl:arrayType="typens:McContact[]" ref="soapenc:arrayType"/>
38
+ </xsd:restriction>
39
+ </xsd:complexContent>
40
+ </xsd:complexType>
41
+ </xsd:schema>
42
+ </types>
43
+ <message name="GetUserLoginById">
44
+ <part name="api_key" type="xsd:string"/>
45
+ <part name="id" type="xsd:int"/>
46
+ </message>
47
+ <message name="GetUserLoginByIdResponse">
48
+ <part name="return" type="xsd:string"/>
49
+ </message>
50
+ <message name="GetAllContacts">
51
+ <part name="api_key" type="xsd:string"/>
52
+ <part name="login" type="xsd:string"/>
53
+ </message>
54
+ <message name="GetAllContactsResponse">
55
+ <part name="return" type="typens:McContactArray"/>
56
+ </message>
57
+ <message name="SearchUser">
58
+ <part name="api_key" type="xsd:string"/>
59
+ <part name="phrase" type="xsd:string"/>
60
+ <part name="page" type="xsd:string"/>
61
+ <part name="per_page" type="xsd:string"/>
62
+ </message>
63
+ <message name="SearchUserResponse">
64
+ <part name="return" type="typens:MpUserArray"/>
65
+ </message>
66
+ <portType name="ApiApiPort">
67
+ <operation name="GetUserLoginById">
68
+ <input message="typens:GetUserLoginById"/>
69
+ <output message="typens:GetUserLoginByIdResponse"/>
70
+ </operation>
71
+ <operation name="GetAllContacts">
72
+ <input message="typens:GetAllContacts"/>
73
+ <output message="typens:GetAllContactsResponse"/>
74
+ </operation>
75
+ <operation name="SearchUser">
76
+ <input message="typens:SearchUser"/>
77
+ <output message="typens:SearchUserResponse"/>
78
+ </operation>
79
+ </portType>
80
+ <binding name="ApiApiBinding" type="typens:ApiApiPort">
81
+ <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
82
+ <operation name="GetUserLoginById">
83
+ <soap:operation soapAction="/api/api/GetUserLoginById"/>
84
+ <input>
85
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
86
+ </input>
87
+ <output>
88
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
89
+ </output>
90
+ </operation>
91
+ <operation name="GetAllContacts">
92
+ <soap:operation soapAction="/api/api/GetAllContacts"/>
93
+ <input>
94
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
95
+ </input>
96
+ <output>
97
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
98
+ </output>
99
+ </operation>
100
+ <operation name="SearchUser">
101
+ <soap:operation soapAction="/api/api/SearchUser"/>
102
+ <input>
103
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
104
+ </input>
105
+ <output>
106
+ <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
107
+ </output>
108
+ </operation>
109
+ </binding>
110
+ <service name="ApiService">
111
+ <port name="ApiApiPort" binding="typens:ApiApiBinding">
112
+ <soap:address location="http://example.com/api/api"/>
113
+ </port>
114
+ </service>
115
+ </definitions>
data/spec/http_stubs.rb CHANGED
@@ -1,23 +1,23 @@
1
- require "fakeweb"
2
-
3
1
  FakeWeb.allow_net_connect = false
4
2
 
5
3
  # Some WSDL and SOAP request.
6
- FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint, :body => UserFixture.user_wsdl
7
- FakeWeb.register_uri :post, EndpointHelper.soap_endpoint, :body => UserFixture.user_response
8
-
9
- # WSDL and SOAP request with multiple "//return" nodes.
10
- FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:multiple), :body => UserFixture.user_wsdl
11
- FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:multiple), :body => UserFixture.multiple_user_response
4
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint, :body => WSDLFixture.authentication
5
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint, :body => ResponseFixture.authentication
12
6
 
13
7
  # WSDL and SOAP request with a Savon::SOAPFault.
14
- FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:soap_fault), :body => UserFixture.user_wsdl
15
- FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:soap_fault), :body => UserFixture.soap_fault
8
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:soap_fault), :body => WSDLFixture.authentication
9
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:soap_fault), :body => ResponseFixture.soap_fault
16
10
 
17
11
  # WSDL and SOAP request with a Savon::HTTPError.
18
- FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:http_error), :body => UserFixture.user_wsdl
12
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:http_error), :body => WSDLFixture.authentication
19
13
  FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:http_error), :body => "", :status => ["404", "Not Found"]
20
14
 
21
15
  # WSDL and SOAP request with an invalid endpoint.
22
16
  FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:invalid), :body => ""
23
17
  FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:invalid), :body => "", :status => ["404", "Not Found"]
18
+
19
+ # WSDL request returning a WSDL document where the main sections are not namespaced.
20
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:no_namespace), :body => WSDLFixture.no_namespace
21
+
22
+ # WSDL request returning a WSDL document with namespaced SOAP actions.
23
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:namespaced_actions), :body => WSDLFixture.namespaced_actions
@@ -7,10 +7,19 @@ describe Savon::Client do
7
7
  Savon::Client.new EndpointHelper.wsdl_endpoint
8
8
  end
9
9
 
10
- it "accepts an optional proxy URI passed in via options" do
10
+ it "accepts a proxy URI passed in via options" do
11
11
  Savon::Client.new EndpointHelper.wsdl_endpoint, :proxy => 'http://proxy'
12
12
  end
13
13
 
14
+ it "accepts settings for SSL client authentication via options" do
15
+ Savon::Client.new EndpointHelper.wsdl_endpoint, :ssl => {
16
+ :client_cert => "client cert",
17
+ :client_key => "client key",
18
+ :ca_file => "ca file",
19
+ :verify => OpenSSL::SSL::VERIFY_PEER
20
+ }
21
+ end
22
+
14
23
  it "has a getter for accessing the Savon::WSDL" do
15
24
  @client.wsdl.should be_a Savon::WSDL
16
25
  end
@@ -19,48 +28,63 @@ describe Savon::Client do
19
28
  @client.request.should be_a Savon::Request
20
29
  end
21
30
 
22
- it "has a getter for returning whether to use the Savon::WSDL (global setting)" do
23
- @client.wsdl?.should be_true
24
-
25
- Savon::Client.wsdl = false
26
- @client.wsdl?.should be_false
27
- Savon::Client.wsdl = true
28
-
29
- @client.wsdl = false
30
- @client.wsdl?.should be_false
31
- end
32
-
33
31
  it "responds to SOAP actions while still behaving as usual otherwise" do
34
- @client.respond_to?(UserFixture.soap_actions.first).should be_true
32
+ WSDLFixture.authentication(:operations).keys.each do |soap_action|
33
+ @client.respond_to?(soap_action).should be_true
34
+ end
35
+
35
36
  @client.respond_to?(:object_id).should be_true
36
37
  @client.respond_to?(:some_undefined_method).should be_false
37
38
  end
38
39
 
39
40
  it "dispatches SOAP calls via method_missing and returns the Savon::Response" do
40
- @client.find_user.should be_a Savon::Response
41
+ @client.authenticate.should be_a Savon::Response
41
42
  end
42
43
 
43
- it "dispatches SOAP calls via method_missing without using WSDL" do
44
- @client.wsdl = false
45
- @client.find_user.should be_a Savon::Response
44
+ describe "disabling retrieving and parsing the WSDL document" do
45
+ it "can be done globally for every instance of Savon::Client" do
46
+ @client.wsdl?.should be_true
47
+ Savon::Client.wsdl = false
48
+
49
+ expect_the_wsdl_to_be_disabled
50
+ @client.authenticate.should be_a Savon::Response
51
+
52
+ Savon::Client.wsdl = true
53
+ end
54
+
55
+ it "can be done per request" do
56
+ @client.wsdl = false
57
+
58
+ expect_the_wsdl_to_be_disabled
59
+ @client.authenticate.should be_a Savon::Response
60
+ end
61
+
62
+ def expect_the_wsdl_to_be_disabled
63
+ @client.wsdl?.should be_false
64
+ [:respond_to?, :operations, :namespace_uri, :soap_endpoint].each do |method|
65
+ Savon::WSDL.any_instance.expects(method).never
66
+ end
67
+ end
46
68
  end
47
69
 
48
70
  it "raises a Savon::SOAPFault in case of a SOAP fault" do
49
71
  client = Savon::Client.new EndpointHelper.wsdl_endpoint(:soap_fault)
50
- lambda { client.find_user }.should raise_error Savon::SOAPFault
72
+ client.wsdl = false
73
+ lambda { client.authenticate }.should raise_error Savon::SOAPFault
51
74
  end
52
75
 
53
76
  it "raises a Savon::HTTPError in case of an HTTP error" do
54
77
  client = Savon::Client.new EndpointHelper.wsdl_endpoint(:http_error)
55
- lambda { client.find_user }.should raise_error Savon::HTTPError
78
+ client.wsdl = false
79
+ lambda { client.authenticate }.should raise_error Savon::HTTPError
56
80
  end
57
81
 
58
82
  it "yields the SOAP object to a block when it expects one argument" do
59
- @client.find_user { |soap| soap.should be_a Savon::SOAP }
83
+ @client.authenticate { |soap| soap.should be_a Savon::SOAP }
60
84
  end
61
85
 
62
86
  it "yields the SOAP and WSSE object to a block when it expects two argument" do
63
- @client.find_user do |soap, wsse|
87
+ @client.authenticate do |soap, wsse|
64
88
  soap.should be_a Savon::SOAP
65
89
  wsse.should be_a Savon::WSSE
66
90
  end
@@ -70,23 +94,4 @@ describe Savon::Client do
70
94
  lambda { @client.some_undefined_method }.should raise_error NoMethodError
71
95
  end
72
96
 
73
- it "passes ssl options to request" do
74
- @client.request.class.class_eval { attr_reader :ssl }
75
-
76
- client = Savon::Client.new(
77
- EndpointHelper.wsdl_endpoint,
78
- :ssl => {
79
- :client_cert => "client cert",
80
- :client_key => "client key",
81
- :ca_file => "ca file",
82
- :verify => OpenSSL::SSL::VERIFY_PEER
83
- }
84
- )
85
-
86
- client.request.ssl[:client_cert].should == "client cert"
87
- client.request.ssl[:client_key].should == "client key"
88
- client.request.ssl[:ca_file].should == "ca file"
89
- client.request.ssl[:verify].should == OpenSSL::SSL::VERIFY_PEER
90
- end
91
-
92
- end
97
+ end
@@ -4,8 +4,8 @@ describe DateTime do
4
4
 
5
5
  describe "to_soap_value" do
6
6
  it "returns an xs:dateTime compliant String" do
7
- UserFixture.datetime_object.to_soap_value.
8
- should == UserFixture.datetime_string
7
+ DateTime.new(2012, 03, 22, 16, 22, 33).to_soap_value.
8
+ should == "2012-03-22T16:22:33"
9
9
  end
10
10
  end
11
11
 
@@ -65,26 +65,26 @@ describe Hash do
65
65
  end
66
66
 
67
67
  it "converts DateTime objects to xs:dateTime compliant Strings" do
68
- { :before => UserFixture.datetime_object }.to_soap_xml.
69
- should == "<before>" << UserFixture.datetime_string << "</before>"
68
+ { :before => DateTime.new(2012, 03, 22, 16, 22, 33) }.to_soap_xml.
69
+ should == "<before>" << "2012-03-22T16:22:33" << "</before>"
70
70
  end
71
71
 
72
72
  it "converts Objects responding to to_datetime to xs:dateTime compliant Strings" do
73
73
  singleton = Object.new
74
74
  def singleton.to_datetime
75
- UserFixture.datetime_object
75
+ DateTime.new(2012, 03, 22, 16, 22, 33)
76
76
  end
77
77
 
78
78
  { :before => singleton }.to_soap_xml.
79
- should == "<before>" << UserFixture.datetime_string << "</before>"
79
+ should == "<before>" << "2012-03-22T16:22:33" << "</before>"
80
80
  end
81
81
 
82
82
  it "calls to_s on Strings even if they respond to to_datetime" do
83
- singleton = "gorilla"
84
- singleton.expects( :to_s ).returns singleton
85
- singleton.expects( :to_datetime ).never
83
+ object = "gorilla"
84
+ object.expects(:to_s).returns object
85
+ object.expects(:to_datetime).never
86
86
 
87
- { :name => singleton }.to_soap_xml.should == "<name>gorilla</name>"
87
+ { :name => object }.to_soap_xml.should == "<name>gorilla</name>"
88
88
  end
89
89
 
90
90
  it "call to_s on any other Object" do
@@ -116,8 +116,8 @@ describe Hash do
116
116
  end
117
117
 
118
118
  it "converts Hash values matching the xs:dateTime format into DateTime Objects" do
119
- { "response" => { "at" => UserFixture.datetime_string } }.map_soap_response.
120
- should == { :response => { :at => UserFixture.datetime_object } }
119
+ { "response" => { "at" => "2012-03-22T16:22:33" } }.map_soap_response.
120
+ should == { :response => { :at => DateTime.new(2012, 03, 22, 16, 22, 33) } }
121
121
  end
122
122
 
123
123
  it "converts Hash values matching 'true' to TrueClass" do
@@ -26,10 +26,10 @@ describe Object do
26
26
  it "returns an xs:dateTime compliant String for Objects responding to to_datetime" do
27
27
  singleton = Object.new
28
28
  def singleton.to_datetime
29
- UserFixture.datetime_object
29
+ DateTime.new(2012, 03, 22, 16, 22, 33)
30
30
  end
31
31
 
32
- singleton.to_soap_value.should == UserFixture.datetime_string
32
+ singleton.to_soap_value.should == "2012-03-22T16:22:33"
33
33
  end
34
34
 
35
35
  it "calls to_s unless the Object responds to to_datetime" do
@@ -42,8 +42,8 @@ describe String do
42
42
 
43
43
  describe "map_soap_response" do
44
44
  it "returns a DateTime Object for Strings matching the xs:dateTime format" do
45
- UserFixture.datetime_string.map_soap_response.should ==
46
- UserFixture.datetime_object
45
+ "2012-03-22T16:22:33".map_soap_response.should ==
46
+ DateTime.new(2012, 03, 22, 16, 22, 33)
47
47
  end
48
48
 
49
49
  it "returns true for Strings matching 'true'" do
@@ -8,4 +8,4 @@ describe Symbol do
8
8
  end
9
9
  end
10
10
 
11
- end
11
+ end
@@ -12,4 +12,4 @@ describe URI::HTTP do
12
12
  end
13
13
  end
14
14
 
15
- end
15
+ end
@@ -67,14 +67,16 @@ describe Savon::Request do
67
67
  wsdl_response = @request.wsdl
68
68
 
69
69
  wsdl_response.should be_a Net::HTTPResponse
70
- wsdl_response.body.should == UserFixture.user_wsdl
70
+ wsdl_response.body.should == WSDLFixture.authentication
71
71
  end
72
72
 
73
73
  it "executes a SOAP request and returns the Net::HTTPResponse" do
74
- soap_response = @request.soap Savon::SOAP.new
74
+ soap = Savon::SOAP.new
75
+ soap.endpoint = URI EndpointHelper.wsdl_endpoint
76
+ soap_response = @request.soap soap
75
77
 
76
78
  soap_response.should be_a Net::HTTPResponse
77
- soap_response.body.should == UserFixture.user_response
79
+ soap_response.body.should == ResponseFixture.authentication
78
80
  end
79
81
 
80
82
  describe "Savon::Request SSL" do
@@ -94,25 +94,25 @@ describe Savon::Response do
94
94
  end
95
95
 
96
96
  it "can return the SOAP response body as a Hash" do
97
- @response.to_hash.should == UserFixture.response_hash
97
+ @response.to_hash[:return].should == ResponseFixture.authentication(:to_hash)
98
98
  end
99
99
 
100
100
  it "can return the raw SOAP response body" do
101
- @response.to_xml.should == UserFixture.user_response
102
- @response.to_s.should == UserFixture.user_response
101
+ @response.to_xml.should == ResponseFixture.authentication
102
+ @response.to_s.should == ResponseFixture.authentication
103
103
  end
104
104
 
105
105
  def savon_response_with(error_type)
106
106
  mock = case error_type
107
- when :soap_fault then http_response_mock(200, UserFixture.soap_fault)
108
- when :soap_fault12 then http_response_mock(200, UserFixture.soap_fault12)
109
- when :http_error then http_response_mock(404, "", "Not found")
107
+ when :soap_fault then http_response_mock 200, ResponseFixture.soap_fault
108
+ when :soap_fault12 then http_response_mock 200, ResponseFixture.soap_fault12
109
+ when :http_error then http_response_mock 404, "", "Not found"
110
110
  end
111
111
  Savon::Response.new mock
112
112
  end
113
113
 
114
114
  def http_response_mock(code = 200, body = nil, message = "OK")
115
- body ||= UserFixture.user_response
115
+ body ||= ResponseFixture.authentication
116
116
  mock = mock "Net::HTTPResponse"
117
117
  mock.stubs :code => code.to_s, :message => message,
118
118
  :content_type => "text/html", :body => body
@@ -11,14 +11,13 @@ describe Savon do
11
11
  Savon::SOAPDateTimeFormat.should be_a String
12
12
  Savon::SOAPDateTimeFormat.should_not be_empty
13
13
 
14
- UserFixture.datetime_object.strftime(Savon::SOAPDateTimeFormat).
15
- should == UserFixture.datetime_string
14
+ DateTime.new(2012, 03, 22, 16, 22, 33).strftime(Savon::SOAPDateTimeFormat).
15
+ should == "2012-03-22T16:22:33"
16
16
  end
17
17
 
18
18
  it "contains a Regexp matching the xs:dateTime format" do
19
19
  Savon::SOAPDateTimeRegexp.should be_a Regexp
20
- (Savon::SOAPDateTimeRegexp === UserFixture.datetime_string).
21
- should be_true
20
+ (Savon::SOAPDateTimeRegexp === "2012-03-22T16:22:33").should be_true
22
21
  end
23
22
 
24
23
  end