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.
18 HyperDrive DriveType = iota
22 type Passenger struct {
23 Name []string `xml:"name"`
24 Weight float32 `xml:"weight"`
28 XMLName Name `xml:"spaceship"`
30 Name string `xml:"attr"`
31 Pilot string `xml:"attr"`
32 Drive DriveType `xml:"drive"`
34 Passenger []*Passenger `xml:"passenger"`
40 func (rx RawXML) MarshalXML() ([]byte, error) {
41 return []byte(rx), nil
47 XMLName Name `xml:"port"`
48 Type string `xml:"attr"`
49 Number string `xml:"chardata"`
53 XMLName Name `xml:"domain"`
54 Country string `xml:"attr"`
55 Name []byte `xml:"chardata"`
59 XMLName Name `xml:"book"`
60 Title string `xml:"chardata"`
63 type SecretAgent struct {
64 XMLName Name `xml:"agent"`
65 Handle string `xml:"attr"`
67 Obfuscate string `xml:"innerxml"`
70 type NestedItems struct {
71 XMLName Name `xml:"result"`
72 Items []string `xml:">item"`
73 Item1 []string `xml:"Items>item1"`
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"`
83 type MixedNested struct {
84 XMLName Name `xml:"result"`
85 A string `xml:"parent1>a"`
87 C string `xml:"parent1>parent2>c"`
88 D string `xml:"parent1>d"`
92 A interface{} `xml:"parent1>parent2>a"`
93 B interface{} `xml:"parent1>b"`
94 C interface{} `xml:"parent1>parent2>c"`
98 XMLName Name `xml:"service"`
99 Domain *Domain `xml:"host>domain"`
100 Port *Port `xml:"host>port"`
102 Extra2 interface{} `xml:"host>extra2"`
107 var marshalTests = []struct {
111 // Test nil marshals to nothing
112 {Value: nil, ExpectXML: ``},
113 {Value: nilStruct, ExpectXML: ``},
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: `<???></></???>`},
131 {Value: []byte("</>"), ExpectXML: `<???></></???>`},
132 {Value: [3]byte{'<', '/', '>'}, ExpectXML: `<???></></???>`},
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</???>`},
138 {Value: RawXML("</>"), ExpectXML: `</>`},
142 Identity: "James Bond",
143 Obfuscate: "<redacted/>",
145 //ExpectXML: `<agent handle="007"><redacted/></agent>`,
146 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
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="<unix>"></port>`},
153 {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`},
154 {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride & Prejudice</book>`},
155 {Value: atomValue, ExpectXML: atomXml},
158 Name: "Heart of Gold",
161 Drive: ImprobabilityDrive,
162 Passenger: []*Passenger{
164 Name: []string{"Zaphod", "Beeblebrox"},
168 Name: []string{"Trisha", "McMillen"},
172 Name: []string{"Ford", "Prefect"},
176 Name: []string{"Arthur", "Dent"},
181 ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
182 `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
185 `<name>Zaphod</name>` +
186 `<name>Beeblebrox</name>` +
187 `<weight>7.25</weight>` +
190 `<name>Trisha</name>` +
191 `<name>McMillen</name>` +
192 `<weight>5.5</weight>` +
195 `<name>Ford</name>` +
196 `<name>Prefect</name>` +
197 `<weight>7</weight>` +
200 `<name>Arthur</name>` +
201 `<name>Dent</name>` +
202 `<weight>6.75</weight>` +
208 Value: NestedItems{Items: []string{}, Item1: []string{}},
209 ExpectXML: `<result>` +
215 Value: NestedItems{Items: []string{}, Item1: []string{"A"}},
216 ExpectXML: `<result>` +
223 Value: NestedItems{Items: []string{"A", "B"}, Item1: []string{}},
224 ExpectXML: `<result>` +
232 Value: NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
233 ExpectXML: `<result>` +
242 Value: NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
243 ExpectXML: `<result>` +
252 Value: NilTest{A: "A", B: nil, C: "C"},
255 `<parent2><a>A</a></parent2>` +
256 `<parent2><c>C</c></parent2>` +
261 Value: MixedNested{A: "A", B: "B", C: "C", D: "D"},
262 ExpectXML: `<result>` +
263 `<parent1><a>A</a></parent1>` +
266 `<parent2><c>C</c></parent2>` +
272 Value: Service{Port: &Port{Number: "80"}},
273 ExpectXML: `<service><host><port>80</port></host></service>`,
277 ExpectXML: `<service></service>`,
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>` +
288 Value: Service{Port: &Port{Number: "80"}, Extra2: "example"},
289 ExpectXML: `<service>` +
290 `<host><port>80</port></host>` +
291 `<host><extra2>example</extra2></host>` +
296 func TestMarshal(t *testing.T) {
297 for idx, test := range marshalTests {
298 buf := bytes.NewBuffer(nil)
299 err := Marshal(buf, test.Value)
301 t.Errorf("#%d: Error: %s", idx, err)
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)
308 t.Errorf("#%d: marshal(%#v) = %#q want %#q", idx, test.Value, got, want)
314 var marshalErrorTests = []struct {
320 Value: make(chan bool),
321 Err: "xml: unsupported type: chan bool",
325 Value: map[string]string{
326 "question": "What do you get when you multiply six by nine?",
329 Err: "xml: unsupported type: map[string]string",
333 Value: map[*Ship]bool{nil: false},
334 Err: "xml: unsupported type: map[*xml.Ship]bool",
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)
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)
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
362 switch test.Value.(type) {
367 case *Domain, Domain:
375 buffer := bytes.NewBufferString(test.ExpectXML)
376 err := Unmarshal(buffer, dest)
378 // Don't compare XMLNames
379 switch fix := dest.(type) {
388 fix.Author.InnerXML = ""
389 for i := range fix.Entry {
390 fix.Entry[i].Author.InnerXML = ""
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)
402 func BenchmarkMarshal(b *testing.B) {
403 idx := len(marshalTests) - 1
404 test := marshalTests[idx]
406 buf := bytes.NewBuffer(nil)
407 for i := 0; i < b.N; i++ {
408 Marshal(buf, test.Value)
413 func BenchmarkUnmarshal(b *testing.B) {
414 idx := len(marshalTests) - 1
415 test := marshalTests[idx]
417 xml := []byte(test.ExpectXML)
419 for i := 0; i < b.N; i++ {
420 buffer := bytes.NewBuffer(xml)
421 Unmarshal(buffer, sm)