OSDN Git Service

804076580155a77dd22ea07bcf028905a2be4ac4
[pf3gnuchains/gcc-fork.git] / libgo / go / encoding / xml / marshal_test.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package xml
6
7 import (
8         "bytes"
9         "reflect"
10         "strconv"
11         "strings"
12         "testing"
13 )
14
15 type DriveType int
16
17 const (
18         HyperDrive DriveType = iota
19         ImprobabilityDrive
20 )
21
22 type Passenger struct {
23         Name   []string `xml:"name"`
24         Weight float32  `xml:"weight"`
25 }
26
27 type Ship struct {
28         XMLName Name `xml:"spaceship"`
29
30         Name      string       `xml:"attr"`
31         Pilot     string       `xml:"attr"`
32         Drive     DriveType    `xml:"drive"`
33         Age       uint         `xml:"age"`
34         Passenger []*Passenger `xml:"passenger"`
35         secret    string
36 }
37
38 type RawXML string
39
40 func (rx RawXML) MarshalXML() ([]byte, error) {
41         return []byte(rx), nil
42 }
43
44 type NamedType string
45
46 type Port struct {
47         XMLName Name   `xml:"port"`
48         Type    string `xml:"attr"`
49         Number  string `xml:"chardata"`
50 }
51
52 type Domain struct {
53         XMLName Name   `xml:"domain"`
54         Country string `xml:"attr"`
55         Name    []byte `xml:"chardata"`
56 }
57
58 type Book struct {
59         XMLName Name   `xml:"book"`
60         Title   string `xml:"chardata"`
61 }
62
63 type SecretAgent struct {
64         XMLName   Name   `xml:"agent"`
65         Handle    string `xml:"attr"`
66         Identity  string
67         Obfuscate string `xml:"innerxml"`
68 }
69
70 type NestedItems struct {
71         XMLName Name     `xml:"result"`
72         Items   []string `xml:">item"`
73         Item1   []string `xml:"Items>item1"`
74 }
75
76 type NestedOrder struct {
77         XMLName Name   `xml:"result"`
78         Field1  string `xml:"parent>c"`
79         Field2  string `xml:"parent>b"`
80         Field3  string `xml:"parent>a"`
81 }
82
83 type MixedNested struct {
84         XMLName Name   `xml:"result"`
85         A       string `xml:"parent1>a"`
86         B       string `xml:"b"`
87         C       string `xml:"parent1>parent2>c"`
88         D       string `xml:"parent1>d"`
89 }
90
91 type NilTest struct {
92         A interface{} `xml:"parent1>parent2>a"`
93         B interface{} `xml:"parent1>b"`
94         C interface{} `xml:"parent1>parent2>c"`
95 }
96
97 type Service struct {
98         XMLName Name    `xml:"service"`
99         Domain  *Domain `xml:"host>domain"`
100         Port    *Port   `xml:"host>port"`
101         Extra1  interface{}
102         Extra2  interface{} `xml:"host>extra2"`
103 }
104
105 var nilStruct *Ship
106
107 var marshalTests = []struct {
108         Value     interface{}
109         ExpectXML string
110 }{
111         // Test nil marshals to nothing
112         {Value: nil, ExpectXML: ``},
113         {Value: nilStruct, ExpectXML: ``},
114
115         // Test value types (no tag name, so ???)
116         {Value: true, ExpectXML: `<???>true</???>`},
117         {Value: int(42), ExpectXML: `<???>42</???>`},
118         {Value: int8(42), ExpectXML: `<???>42</???>`},
119         {Value: int16(42), ExpectXML: `<???>42</???>`},
120         {Value: int32(42), ExpectXML: `<???>42</???>`},
121         {Value: uint(42), ExpectXML: `<???>42</???>`},
122         {Value: uint8(42), ExpectXML: `<???>42</???>`},
123         {Value: uint16(42), ExpectXML: `<???>42</???>`},
124         {Value: uint32(42), ExpectXML: `<???>42</???>`},
125         {Value: float32(1.25), ExpectXML: `<???>1.25</???>`},
126         {Value: float64(1.25), ExpectXML: `<???>1.25</???>`},
127         {Value: uintptr(0xFFDD), ExpectXML: `<???>65501</???>`},
128         {Value: "gopher", ExpectXML: `<???>gopher</???>`},
129         {Value: []byte("gopher"), ExpectXML: `<???>gopher</???>`},
130         {Value: "</>", ExpectXML: `<???>&lt;/&gt;</???>`},
131         {Value: []byte("</>"), ExpectXML: `<???>&lt;/&gt;</???>`},
132         {Value: [3]byte{'<', '/', '>'}, ExpectXML: `<???>&lt;/&gt;</???>`},
133         {Value: NamedType("potato"), ExpectXML: `<???>potato</???>`},
134         {Value: []int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
135         {Value: [3]int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
136
137         // Test innerxml
138         {Value: RawXML("</>"), ExpectXML: `</>`},
139         {
140                 Value: &SecretAgent{
141                         Handle:    "007",
142                         Identity:  "James Bond",
143                         Obfuscate: "<redacted/>",
144                 },
145                 //ExpectXML: `<agent handle="007"><redacted/></agent>`,
146                 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
147         },
148
149         // Test structs
150         {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
151         {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
152         {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
153         {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
154         {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
155         {Value: atomValue, ExpectXML: atomXml},
156         {
157                 Value: &Ship{
158                         Name:  "Heart of Gold",
159                         Pilot: "Computer",
160                         Age:   1,
161                         Drive: ImprobabilityDrive,
162                         Passenger: []*Passenger{
163                                 {
164                                         Name:   []string{"Zaphod", "Beeblebrox"},
165                                         Weight: 7.25,
166                                 },
167                                 {
168                                         Name:   []string{"Trisha", "McMillen"},
169                                         Weight: 5.5,
170                                 },
171                                 {
172                                         Name:   []string{"Ford", "Prefect"},
173                                         Weight: 7,
174                                 },
175                                 {
176                                         Name:   []string{"Arthur", "Dent"},
177                                         Weight: 6.75,
178                                 },
179                         },
180                 },
181                 ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
182                         `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
183                         `<age>1</age>` +
184                         `<passenger>` +
185                         `<name>Zaphod</name>` +
186                         `<name>Beeblebrox</name>` +
187                         `<weight>7.25</weight>` +
188                         `</passenger>` +
189                         `<passenger>` +
190                         `<name>Trisha</name>` +
191                         `<name>McMillen</name>` +
192                         `<weight>5.5</weight>` +
193                         `</passenger>` +
194                         `<passenger>` +
195                         `<name>Ford</name>` +
196                         `<name>Prefect</name>` +
197                         `<weight>7</weight>` +
198                         `</passenger>` +
199                         `<passenger>` +
200                         `<name>Arthur</name>` +
201                         `<name>Dent</name>` +
202                         `<weight>6.75</weight>` +
203                         `</passenger>` +
204                         `</spaceship>`,
205         },
206         // Test a>b
207         {
208                 Value: NestedItems{Items: []string{}, Item1: []string{}},
209                 ExpectXML: `<result>` +
210                         `<Items>` +
211                         `</Items>` +
212                         `</result>`,
213         },
214         {
215                 Value: NestedItems{Items: []string{}, Item1: []string{"A"}},
216                 ExpectXML: `<result>` +
217                         `<Items>` +
218                         `<item1>A</item1>` +
219                         `</Items>` +
220                         `</result>`,
221         },
222         {
223                 Value: NestedItems{Items: []string{"A", "B"}, Item1: []string{}},
224                 ExpectXML: `<result>` +
225                         `<Items>` +
226                         `<item>A</item>` +
227                         `<item>B</item>` +
228                         `</Items>` +
229                         `</result>`,
230         },
231         {
232                 Value: NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
233                 ExpectXML: `<result>` +
234                         `<Items>` +
235                         `<item>A</item>` +
236                         `<item>B</item>` +
237                         `<item1>C</item1>` +
238                         `</Items>` +
239                         `</result>`,
240         },
241         {
242                 Value: NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
243                 ExpectXML: `<result>` +
244                         `<parent>` +
245                         `<c>C</c>` +
246                         `<b>B</b>` +
247                         `<a>A</a>` +
248                         `</parent>` +
249                         `</result>`,
250         },
251         {
252                 Value: NilTest{A: "A", B: nil, C: "C"},
253                 ExpectXML: `<???>` +
254                         `<parent1>` +
255                         `<parent2><a>A</a></parent2>` +
256                         `<parent2><c>C</c></parent2>` +
257                         `</parent1>` +
258                         `</???>`,
259         },
260         {
261                 Value: MixedNested{A: "A", B: "B", C: "C", D: "D"},
262                 ExpectXML: `<result>` +
263                         `<parent1><a>A</a></parent1>` +
264                         `<b>B</b>` +
265                         `<parent1>` +
266                         `<parent2><c>C</c></parent2>` +
267                         `<d>D</d>` +
268                         `</parent1>` +
269                         `</result>`,
270         },
271         {
272                 Value:     Service{Port: &Port{Number: "80"}},
273                 ExpectXML: `<service><host><port>80</port></host></service>`,
274         },
275         {
276                 Value:     Service{},
277                 ExpectXML: `<service></service>`,
278         },
279         {
280                 Value: Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
281                 ExpectXML: `<service>` +
282                         `<host><port>80</port></host>` +
283                         `<Extra1>A</Extra1>` +
284                         `<host><extra2>B</extra2></host>` +
285                         `</service>`,
286         },
287         {
288                 Value: Service{Port: &Port{Number: "80"}, Extra2: "example"},
289                 ExpectXML: `<service>` +
290                         `<host><port>80</port></host>` +
291                         `<host><extra2>example</extra2></host>` +
292                         `</service>`,
293         },
294 }
295
296 func TestMarshal(t *testing.T) {
297         for idx, test := range marshalTests {
298                 buf := bytes.NewBuffer(nil)
299                 err := Marshal(buf, test.Value)
300                 if err != nil {
301                         t.Errorf("#%d: Error: %s", idx, err)
302                         continue
303                 }
304                 if got, want := buf.String(), test.ExpectXML; got != want {
305                         if strings.Contains(want, "\n") {
306                                 t.Errorf("#%d: marshal(%#v) - GOT:\n%s\nWANT:\n%s", idx, test.Value, got, want)
307                         } else {
308                                 t.Errorf("#%d: marshal(%#v) = %#q want %#q", idx, test.Value, got, want)
309                         }
310                 }
311         }
312 }
313
314 var marshalErrorTests = []struct {
315         Value interface{}
316         Err   string
317         Kind  reflect.Kind
318 }{
319         {
320                 Value: make(chan bool),
321                 Err:   "xml: unsupported type: chan bool",
322                 Kind:  reflect.Chan,
323         },
324         {
325                 Value: map[string]string{
326                         "question": "What do you get when you multiply six by nine?",
327                         "answer":   "42",
328                 },
329                 Err:  "xml: unsupported type: map[string]string",
330                 Kind: reflect.Map,
331         },
332         {
333                 Value: map[*Ship]bool{nil: false},
334                 Err:   "xml: unsupported type: map[*xml.Ship]bool",
335                 Kind:  reflect.Map,
336         },
337 }
338
339 func TestMarshalErrors(t *testing.T) {
340         for idx, test := range marshalErrorTests {
341                 buf := bytes.NewBuffer(nil)
342                 err := Marshal(buf, test.Value)
343                 if err == nil || err.Error() != test.Err {
344                         t.Errorf("#%d: marshal(%#v) = [error] %q, want %q", idx, test.Value, err, test.Err)
345                 }
346                 if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
347                         t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
348                 }
349         }
350 }
351
352 // Do invertibility testing on the various structures that we test
353 func TestUnmarshal(t *testing.T) {
354         for i, test := range marshalTests {
355                 // Skip the nil pointers
356                 if i <= 1 {
357                         continue
358                 }
359
360                 var dest interface{}
361
362                 switch test.Value.(type) {
363                 case *Ship, Ship:
364                         dest = &Ship{}
365                 case *Port, Port:
366                         dest = &Port{}
367                 case *Domain, Domain:
368                         dest = &Domain{}
369                 case *Feed, Feed:
370                         dest = &Feed{}
371                 default:
372                         continue
373                 }
374
375                 buffer := bytes.NewBufferString(test.ExpectXML)
376                 err := Unmarshal(buffer, dest)
377
378                 // Don't compare XMLNames
379                 switch fix := dest.(type) {
380                 case *Ship:
381                         fix.XMLName = Name{}
382                 case *Port:
383                         fix.XMLName = Name{}
384                 case *Domain:
385                         fix.XMLName = Name{}
386                 case *Feed:
387                         fix.XMLName = Name{}
388                         fix.Author.InnerXML = ""
389                         for i := range fix.Entry {
390                                 fix.Entry[i].Author.InnerXML = ""
391                         }
392                 }
393
394                 if err != nil {
395                         t.Errorf("#%d: unexpected error: %#v", i, err)
396                 } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
397                         t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
398                 }
399         }
400 }
401
402 func BenchmarkMarshal(b *testing.B) {
403         idx := len(marshalTests) - 1
404         test := marshalTests[idx]
405
406         buf := bytes.NewBuffer(nil)
407         for i := 0; i < b.N; i++ {
408                 Marshal(buf, test.Value)
409                 buf.Truncate(0)
410         }
411 }
412
413 func BenchmarkUnmarshal(b *testing.B) {
414         idx := len(marshalTests) - 1
415         test := marshalTests[idx]
416         sm := &Ship{}
417         xml := []byte(test.ExpectXML)
418
419         for i := 0; i < b.N; i++ {
420                 buffer := bytes.NewBuffer(xml)
421                 Unmarshal(buffer, sm)
422         }
423 }