1#!/bin/env perl
2
3BEGIN {
4  unless(grep /blib/, @INC) {
5    chdir 't' if -d 't';
6    unshift @INC, '../lib' if -d '../lib';
7  }
8}
9
10use strict;
11use Test;
12
13BEGIN { plan tests => 42; }
14
15use SOAP::Lite;
16
17my($a, $s, $r, $serialized, $deserialized);
18
19{ # check 'use ...'
20  print "'use SOAP::Lite ...' test(s)...\n";
21  eval 'use SOAP::Lite 99.99'; # hm, definitely should fail
22  ok(scalar $@ =~ /99.+required/);
23}
24
25# These tests are for backwards compatibility
26{ # check use of use_prefix and uri together
27  # test 2 - turn OFF default namespace
28  $SIG{__WARN__} = sub { ; }; # turn off deprecation warnings
29  $serialized = SOAP::Serializer->use_prefix(1)->uri("urn:Test")->method(
30    'testMethod', SOAP::Data->name(test => 123)
31  );
32  ok($serialized =~ m!<soap:Body><namesp(\d):testMethod><test xsi:type="xsd:int">123</test></namesp\1:testMethod></soap:Body>!);
33
34  # test 3 - turn ON default namespace
35  $serialized = SOAP::Serializer->use_prefix(0)->uri("urn:Test")->method(
36    'testMethod', SOAP::Data->name(test => 123)
37  );
38  ok($serialized =~ m!<soap:Envelope(?: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"| xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:xsd="http://www.w3.org/2001/XMLSchema"| soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"){5}><soap:Body><testMethod xmlns="urn:Test"><test xsi:type="xsd:int">123</test></testMethod></soap:Body></soap:Envelope>!);
39
40}
41
42{ # check use of default_ns, ns, and use_prefix
43  # test 4
44  $serialized = SOAP::Serializer->ns("urn:Test")->method(
45    'testMethod', SOAP::Data->name(test => 123)
46  );
47  ok($serialized =~ m!<namesp(\d):testMethod><test xsi:type="xsd:int">123</test></namesp\1:testMethod>!);
48
49  # test 5
50  $serialized = SOAP::Serializer->ns("urn:Test","testns")->method(
51    'testMethod', SOAP::Data->name(test => 123)
52  );
53  ok($serialized =~ m!<testns:testMethod><test xsi:type="xsd:int">123</test></testns:testMethod>!);
54
55  # test 6
56  $serialized = SOAP::Serializer->default_ns("urn:Test")->method(
57    'testMethod', SOAP::Data->name(test => 123)
58  );
59  ok($serialized =~ m!<soap:Body><testMethod xmlns="urn:Test"><test xsi:type="xsd:int">123</test></testMethod></soap:Body>!);
60}  
61
62{ # check serialization
63  print "Arrays, structs, refs serialization test(s)...\n";
64  $serialized = SOAP::Serializer->serialize(
65    SOAP::Data->name(test => \SOAP::Data->value(1, [1,2], {a=>3}, \4))
66  );
67  ok($serialized =~ m!<test(?: xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"| xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"| xmlns:xsd="http://www.w3.org/2001/XMLSchema"){4}><c-gensym(\d+) xsi:type="xsd:int">1</c-gensym\1><soapenc:Array(?: xsi:type="soapenc:Array"| soapenc:arrayType="xsd:int\[2\]"){2}><item xsi:type="xsd:int">1</item><item xsi:type="xsd:int">2</item></soapenc:Array><c-gensym(\d+)><a xsi:type="xsd:int">3</a></c-gensym\2><c-gensym(\d+)><c-gensym(\d+) xsi:type="xsd:int">4</c-gensym\4></c-gensym\3></test>!);
68
69}  
70
71{ # check simple circular references
72  print "Simple circular references (\$a=\\\$a) serialization test(s)...\n";
73
74  $a = \$a;
75  $serialized = SOAP::Serializer->namespaces({})->serialize($a);
76
77  ok($serialized =~ m!<c-gensym(\d+) id="ref-(\w+)"><c-gensym(\d+) href="#ref-\2" /></c-gensym\1>!);
78
79  $a = SOAP::Deserializer->deserialize($serialized)->root;
80  ok(0+$a == 0+(values%$a)[0]);
81}
82
83{ # check complex circular references
84  print "Complex circlular references serialization test(s)...\n";
85
86  $a = SOAP::Deserializer->deserialize(<<'EOX')->root;
87<root xmlns="urn:Foo">
88  <a id="id1">
89    <x>1</x>
90    <next id="id2">
91      <x>7</x>
92      <next href="#id3" />
93    </next>
94  </a>
95  <item id="id3">
96    <x>8</x>
97    <next href="#id1" />
98  </item>
99</root>
100EOX
101
102  ok($a->{a}->{next}->{next}->{next}->{next}->{x} == 
103     $a->{a}->{next}->{x});
104
105  $a = { a => 1 }; my $b = { b => $a }; $a->{a} = $b;
106  $serialized = SOAP::Serializer->autotype(0)->namespaces({})->serialize($a);
107
108  ok($serialized =~ m!<c-gensym(\d+) id="ref-(\w+)"><a id="ref-\w+"><b href="#ref-\2" /></a></c-gensym\1>!);
109}
110
111{ # check multirefs
112  print "Multireferences serialization test(s)...\n";
113
114  $a = 1; my $b = \$a;
115
116  $serialized = SOAP::Serializer->new(multirefinplace=>1)->serialize(
117    SOAP::Data->name(test => \SOAP::Data->value($b, $b))
118  );
119
120  ok($serialized =~ m!<test(?: xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"| xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"| xmlns:xsd="http://www.w3.org/2001/XMLSchema"){4}><c-gensym(\d+) id="ref-(\w+)"><c-gensym(\d+) xsi:type="xsd:int">1</c-gensym\3></c-gensym\1><c-gensym\d+ href="#ref-\2" /></test>!);
121
122  $serialized = SOAP::Serializer->namespaces({})->serialize(
123    SOAP::Data->name(test => \SOAP::Data->value($b, $b))
124  );
125print $serialized, "\n";
126  ok($serialized =~ m!<c-gensym\d+ href="#ref-(\w+)" /><c-gensym\d+ href="#ref-\1" /><c-gensym(\d+) id="ref-\1"><c-gensym(\d+) xsi:type="xsd:int">1</c-gensym\3></c-gensym\2>!);
127}
128
129{ # check base64, XML encoding of elements and attributes 
130  print "base64, XML encoding of elements and attributes test(s)...\n";
131
132  $serialized = SOAP::Serializer->serialize(
133    SOAP::Data->name(test => \SOAP::Data->value("\0\1\2\3   \4\5\6", "<123>&amp;\015</123>"))
134  );
135
136  ok($serialized =~ m!<c-gensym(\d+) xsi:type="xsd:base64Binary">AAECAyAgIAQFBg==</c-gensym\1><c-gensym(\d+) xsi:type="xsd:string">&lt;123&gt;&amp;amp;&#xd;&lt;/123&gt;</c-gensym\2>!);
137
138  $serialized = SOAP::Serializer->namespaces({})->serialize(
139    SOAP::Data->name(name=>'value')->attr({attr => '<123>"&amp"</123>'})
140  );
141
142  ok($serialized =~ m!^<\?xml version="1.0" encoding="UTF-8"\?><name(?: xsi:type="xsd:string"| attr="&lt;123&gt;&quot;&amp;amp&quot;&lt;/123&gt;"){2}>value</name>$!);
143}
144
145{ # check objects and SOAP::Data 
146  print "Blessed references and SOAP::Data encoding test(s)...\n";
147
148  $serialized = SOAP::Serializer->serialize(SOAP::Data->uri('some_urn' => bless {a => 1} => 'ObjectType'));
149
150  ok($serialized =~ m!<namesp(\d+):c-gensym(\d+)(:? xsi:type="namesp\d+:ObjectType"| xmlns:namesp\d+="http://namespaces.soaplite.com/perl"| xmlns:namesp\1="some_urn"| xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"| xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"| xmlns:xsd="http://www.w3.org/2001/XMLSchema"){7}><a xsi:type="xsd:int">1</a></namesp\1:c-gensym\2>!);
151}
152
153{ # check serialization/deserialization of simple types
154  print "Serialization/deserialization of simple types test(s)...\n";
155
156  $a = 'abc234xyz';
157
158  $serialized = SOAP::Serializer->serialize(SOAP::Data->type(hex => $a));
159
160  ok($serialized =~ m!<c-gensym(\d+)(?: xsi:type="xsd:hexBinary"| xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"| xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"| xmlns:xsd="http://www.w3.org/2001/XMLSchema"){5}>61626332333478797A</c-gensym(\d+)>!);
161  ok(SOAP::Deserializer->deserialize($serialized)->root eq $a); 
162
163  $a = <<"EOBASE64";
164qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?`1234567890-=\~!@#$%^&*()_+|
165EOBASE64
166
167  $serialized = SOAP::Serializer->serialize($a);
168
169  ok(index($serialized, quotemeta(q!qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM&lt;>?`1234567890-=~\!@#0^&amp;*()_+|!)));
170
171  if (UNIVERSAL::isa(SOAP::Deserializer->parser->parser => 'XML::Parser::Lite')) {
172    skip(q!Entity decoding is not supported in XML::Parser::Lite! => undef);
173  } else {
174    ok(SOAP::Deserializer->deserialize($serialized)->root eq $a);
175  }
176
177  $a = <<"EOBASE64";
178
179qwertyuiop[]asdfghjkl;'zxcvbnm,./
180QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>?
181\x00
182
183EOBASE64
184
185  $serialized = SOAP::Serializer->serialize($a);
186
187  ok($serialized =~ /base64/);
188}
189
190{ # check serialization/deserialization of blessed reference  
191  print "Serialization/deserialization of blessed reference test(s)...\n";
192
193  $serialized = SOAP::Serializer->serialize(bless {a => 1} => 'SOAP::Lite');
194  $a = SOAP::Deserializer->deserialize($serialized)->root;
195
196  ok(ref $a eq 'SOAP::Lite' && UNIVERSAL::isa($a => 'HASH'));
197
198  $a = SOAP::Deserializer->deserialize(
199    SOAP::Serializer->serialize(bless [a => 1] => 'SOAP::Lite')
200  )->root;
201
202  ok(ref $a eq 'SOAP::Lite' && UNIVERSAL::isa($a => 'ARRAY'));
203}
204
205{ # check serialization/deserialization of undef/empty elements  
206  print "Serialization/deserialization of undef/empty elements test(s)...\n";
207
208  { local $^W; # suppress warnings
209    $a = undef;
210    $serialized = SOAP::Serializer->serialize(
211      SOAP::Data->type(negativeInteger => $a)
212    );
213
214    ok(! defined SOAP::Deserializer->deserialize($serialized)->root);
215
216    my $type = 'nonstandardtype';
217    eval {
218      $serialized = SOAP::Serializer->serialize(
219        SOAP::Data->type($type => $a)
220      );
221    };
222    ok($@ =~ /for type '$type' is not specified/);
223
224    $serialized = SOAP::Serializer->serialize(
225      SOAP::Data->type($type => {})
226    );
227
228    ok(ref SOAP::Deserializer->deserialize($serialized)->root eq $type);
229  }
230}
231
232{
233  print "Check for unspecified Transport module test(s)...\n";
234
235  eval { SOAP::Lite->new->abc() };
236  ok($@ =~ /A service address has not been specified/);
237}
238
239{
240  print "Deserialization of CDATA test(s)...\n";
241
242  UNIVERSAL::isa(SOAP::Deserializer->parser->parser => 'XML::Parser::Lite') ?
243    skip(q!CDATA decoding is not supported in XML::Parser::Lite! => undef) :
244    ok(SOAP::Deserializer->deserialize('<root><![CDATA[<123>]]></root>')->root eq '<123>');
245}
246
247{
248  print "Test of XML::Parser External Entity vulnerability...\n";
249  UNIVERSAL::isa(SOAP::Deserializer->parser->parser => 'XML::Parser::Lite') ?
250    skip(q!External entity references are not supported in XML::Parser::Lite! => undef) :
251    ok(!eval { SOAP::Deserializer->deserialize('<?xml version="1.0"?><!DOCTYPE foo [ <!ENTITY ll SYSTEM "foo.txt"> ]><root>&ll;</root>')->root } and $@ =~ /^External entity/);
252}
253
254{
255  print "Test SOAP:: prefix with no +autodispatch option...\n";
256  eval { A->SOAP::b };
257  ok($@ =~ /^SOAP:: prefix/);
258}
259
260{
261  # check deserialization of an array of multiple elements
262  # nested within a complex type
263  print "Deserialization of document/literal arrays nested in complex types...\n";
264  my $input =  '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"><soap:Body><getFooResponse xmlns="http://example.com/v1"><getFooReturn><id>100</id><complexFoo><arrayFoo>one</arrayFoo><arrayFoo>two</arrayFoo></complexFoo></getFooReturn></getFooResponse></soap:Body></soap:Envelope>';
265  my $deserializer = SOAP::Deserializer->new;	
266  my $ret = $deserializer->deserialize($input);
267  my @arr = @{$ret->result->{'complexFoo'}{'arrayFoo'}};
268  ok($#arr == 1);
269  ok("one" eq $arr[0]);
270  ok("two" eq $arr[1]);
271  
272  ok(100 == $ret->result->{"id"});
273  
274  # If only one araryFoo tag is found, it's deserialized as a scalar.
275  $input =  '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"><soap:Body><getFooResponse xmlns="http://example.com/v1"><getFooReturn><id>100</id><complexFoo><arrayFoo>one</arrayFoo></complexFoo></getFooReturn></getFooResponse></soap:Body></soap:Envelope>';
276  $ret = $deserializer->deserialize($input);
277  ok("one" eq $ret->result->{'complexFoo'}{'arrayFoo'});
278}
279
280
281{
282    print "Serialization of document/literal arrays\n";
283    # check array serialization with autotyping disabled
284    my $serializer = SOAP::Serializer->new;
285    $serializer->autotype(0);
286
287    my $hash = {
288	"scalar" => 1,
289	"array" => [ 2, 3],
290	"hash" => {
291	    "scalar" => 4,
292	    "array" => [ 5, 6],
293	}
294    };
295
296    my $xml = $serializer->serialize($hash);
297  
298   ok($xml =~ m{
299	<c-gensym\d+\s[^>]*> 
300	(:?
301            <hash>
302            (:?
303                <array>5</array><array>6</array>
304                |<scalar>4</scalar>
305            ){2}
306            </hash>
307            | <array>2</array><array>3</array>
308            | <scalar>1</scalar>
309        ){3}
310        </c-gensym\d+>
311        }xms 
312    );
313    
314	# deserialize it and check that a similar object is created
315    my $deserializer = SOAP::Deserializer->new;
316    
317    my $obj = $deserializer->deserialize($xml)->root;
318
319    ok(1, $obj->{"scalar"});
320    my @arr= @{$obj->{"array"}};
321    ok(2, $arr[0]);
322    ok(3, $arr[1]);
323    ok(4, $obj->{"hash"}{"scalar"});
324    @arr = @{$obj->{"hash"}{"array"}};
325    ok(5, $arr[0]);
326    ok(6, $arr[1]);
327}
328