~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/govmomi/vim25/xml/read_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2009 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
        "io"
 
9
        "reflect"
 
10
        "strings"
 
11
        "testing"
 
12
        "time"
 
13
)
 
14
 
 
15
// Stripped down Atom feed data structures.
 
16
 
 
17
func TestUnmarshalFeed(t *testing.T) {
 
18
        var f Feed
 
19
        if err := Unmarshal([]byte(atomFeedString), &f); err != nil {
 
20
                t.Fatalf("Unmarshal: %s", err)
 
21
        }
 
22
        if !reflect.DeepEqual(f, atomFeed) {
 
23
                t.Fatalf("have %#v\nwant %#v", f, atomFeed)
 
24
        }
 
25
}
 
26
 
 
27
// hget http://codereview.appspot.com/rss/mine/rsc
 
28
const atomFeedString = `
 
29
<?xml version="1.0" encoding="utf-8"?>
 
30
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us" updated="2009-10-04T01:35:58+00:00"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><author><name>rietveld&lt;&gt;</name></author><entry><title>rietveld: an attempt at pubsubhubbub
 
31
</title><link href="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html">
 
32
  An attempt at adding pubsubhubbub support to Rietveld.
 
33
http://code.google.com/p/pubsubhubbub
 
34
http://code.google.com/p/rietveld/issues/detail?id=155
 
35
 
 
36
The server side of the protocol is trivial:
 
37
  1. add a &amp;lt;link rel=&amp;quot;hub&amp;quot; href=&amp;quot;hub-server&amp;quot;&amp;gt; tag to all
 
38
     feeds that will be pubsubhubbubbed.
 
39
  2. every time one of those feeds changes, tell the hub
 
40
     with a simple POST request.
 
41
 
 
42
I have tested this by adding debug prints to a local hub
 
43
server and checking that the server got the right publish
 
44
requests.
 
45
 
 
46
I can&amp;#39;t quite get the server to work, but I think the bug
 
47
is not in my code.  I think that the server expects to be
 
48
able to grab the feed and see the feed&amp;#39;s actual URL in
 
49
the link rel=&amp;quot;self&amp;quot;, but the default value for that drops
 
50
the :port from the URL, and I cannot for the life of me
 
51
figure out how to get the Atom generator deep inside
 
52
django not to do that, or even where it is doing that,
 
53
or even what code is running to generate the Atom feed.
 
54
(I thought I knew but I added some assert False statements
 
55
and it kept running!)
 
56
 
 
57
Ignoring that particular problem, I would appreciate
 
58
feedback on the right way to get the two values at
 
59
the top of feeds.py marked NOTE(rsc).
 
60
 
 
61
 
 
62
</summary></entry><entry><title>rietveld: correct tab handling
 
63
</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html">
 
64
  This fixes the buggy tab rendering that can be seen at
 
65
http://codereview.appspot.com/116075/diff/1/2
 
66
 
 
67
The fundamental problem was that the tab code was
 
68
not being told what column the text began in, so it
 
69
didn&amp;#39;t know where to put the tab stops.  Another problem
 
70
was that some of the code assumed that string byte
 
71
offsets were the same as column offsets, which is only
 
72
true if there are no tabs.
 
73
 
 
74
In the process of fixing this, I cleaned up the arguments
 
75
to Fold and ExpandTabs and renamed them Break and
 
76
_ExpandTabs so that I could be sure that I found all the
 
77
call sites.  I also wanted to verify that ExpandTabs was
 
78
not being used from outside intra_region_diff.py.
 
79
 
 
80
 
 
81
</summary></entry></feed>          `
 
82
 
 
83
type Feed struct {
 
84
        XMLName Name      `xml:"http://www.w3.org/2005/Atom feed"`
 
85
        Title   string    `xml:"title"`
 
86
        Id      string    `xml:"id"`
 
87
        Link    []Link    `xml:"link"`
 
88
        Updated time.Time `xml:"updated,attr"`
 
89
        Author  Person    `xml:"author"`
 
90
        Entry   []Entry   `xml:"entry"`
 
91
}
 
92
 
 
93
type Entry struct {
 
94
        Title   string    `xml:"title"`
 
95
        Id      string    `xml:"id"`
 
96
        Link    []Link    `xml:"link"`
 
97
        Updated time.Time `xml:"updated"`
 
98
        Author  Person    `xml:"author"`
 
99
        Summary Text      `xml:"summary"`
 
100
}
 
101
 
 
102
type Link struct {
 
103
        Rel  string `xml:"rel,attr,omitempty"`
 
104
        Href string `xml:"href,attr"`
 
105
}
 
106
 
 
107
type Person struct {
 
108
        Name     string `xml:"name"`
 
109
        URI      string `xml:"uri"`
 
110
        Email    string `xml:"email"`
 
111
        InnerXML string `xml:",innerxml"`
 
112
}
 
113
 
 
114
type Text struct {
 
115
        Type string `xml:"type,attr,omitempty"`
 
116
        Body string `xml:",chardata"`
 
117
}
 
118
 
 
119
var atomFeed = Feed{
 
120
        XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
 
121
        Title:   "Code Review - My issues",
 
122
        Link: []Link{
 
123
                {Rel: "alternate", Href: "http://codereview.appspot.com/"},
 
124
                {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
 
125
        },
 
126
        Id:      "http://codereview.appspot.com/",
 
127
        Updated: ParseTime("2009-10-04T01:35:58+00:00"),
 
128
        Author: Person{
 
129
                Name:     "rietveld<>",
 
130
                InnerXML: "<name>rietveld&lt;&gt;</name>",
 
131
        },
 
132
        Entry: []Entry{
 
133
                {
 
134
                        Title: "rietveld: an attempt at pubsubhubbub\n",
 
135
                        Link: []Link{
 
136
                                {Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
 
137
                        },
 
138
                        Updated: ParseTime("2009-10-04T01:35:58+00:00"),
 
139
                        Author: Person{
 
140
                                Name:     "email-address-removed",
 
141
                                InnerXML: "<name>email-address-removed</name>",
 
142
                        },
 
143
                        Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
 
144
                        Summary: Text{
 
145
                                Type: "html",
 
146
                                Body: `
 
147
  An attempt at adding pubsubhubbub support to Rietveld.
 
148
http://code.google.com/p/pubsubhubbub
 
149
http://code.google.com/p/rietveld/issues/detail?id=155
 
150
 
 
151
The server side of the protocol is trivial:
 
152
  1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all
 
153
     feeds that will be pubsubhubbubbed.
 
154
  2. every time one of those feeds changes, tell the hub
 
155
     with a simple POST request.
 
156
 
 
157
I have tested this by adding debug prints to a local hub
 
158
server and checking that the server got the right publish
 
159
requests.
 
160
 
 
161
I can&#39;t quite get the server to work, but I think the bug
 
162
is not in my code.  I think that the server expects to be
 
163
able to grab the feed and see the feed&#39;s actual URL in
 
164
the link rel=&quot;self&quot;, but the default value for that drops
 
165
the :port from the URL, and I cannot for the life of me
 
166
figure out how to get the Atom generator deep inside
 
167
django not to do that, or even where it is doing that,
 
168
or even what code is running to generate the Atom feed.
 
169
(I thought I knew but I added some assert False statements
 
170
and it kept running!)
 
171
 
 
172
Ignoring that particular problem, I would appreciate
 
173
feedback on the right way to get the two values at
 
174
the top of feeds.py marked NOTE(rsc).
 
175
 
 
176
 
 
177
`,
 
178
                        },
 
179
                },
 
180
                {
 
181
                        Title: "rietveld: correct tab handling\n",
 
182
                        Link: []Link{
 
183
                                {Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
 
184
                        },
 
185
                        Updated: ParseTime("2009-10-03T23:02:17+00:00"),
 
186
                        Author: Person{
 
187
                                Name:     "email-address-removed",
 
188
                                InnerXML: "<name>email-address-removed</name>",
 
189
                        },
 
190
                        Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
 
191
                        Summary: Text{
 
192
                                Type: "html",
 
193
                                Body: `
 
194
  This fixes the buggy tab rendering that can be seen at
 
195
http://codereview.appspot.com/116075/diff/1/2
 
196
 
 
197
The fundamental problem was that the tab code was
 
198
not being told what column the text began in, so it
 
199
didn&#39;t know where to put the tab stops.  Another problem
 
200
was that some of the code assumed that string byte
 
201
offsets were the same as column offsets, which is only
 
202
true if there are no tabs.
 
203
 
 
204
In the process of fixing this, I cleaned up the arguments
 
205
to Fold and ExpandTabs and renamed them Break and
 
206
_ExpandTabs so that I could be sure that I found all the
 
207
call sites.  I also wanted to verify that ExpandTabs was
 
208
not being used from outside intra_region_diff.py.
 
209
 
 
210
 
 
211
`,
 
212
                        },
 
213
                },
 
214
        },
 
215
}
 
216
 
 
217
const pathTestString = `
 
218
<Result>
 
219
    <Before>1</Before>
 
220
    <Items>
 
221
        <Item1>
 
222
            <Value>A</Value>
 
223
        </Item1>
 
224
        <Item2>
 
225
            <Value>B</Value>
 
226
        </Item2>
 
227
        <Item1>
 
228
            <Value>C</Value>
 
229
            <Value>D</Value>
 
230
        </Item1>
 
231
        <_>
 
232
            <Value>E</Value>
 
233
        </_>
 
234
    </Items>
 
235
    <After>2</After>
 
236
</Result>
 
237
`
 
238
 
 
239
type PathTestItem struct {
 
240
        Value string
 
241
}
 
242
 
 
243
type PathTestA struct {
 
244
        Items         []PathTestItem `xml:">Item1"`
 
245
        Before, After string
 
246
}
 
247
 
 
248
type PathTestB struct {
 
249
        Other         []PathTestItem `xml:"Items>Item1"`
 
250
        Before, After string
 
251
}
 
252
 
 
253
type PathTestC struct {
 
254
        Values1       []string `xml:"Items>Item1>Value"`
 
255
        Values2       []string `xml:"Items>Item2>Value"`
 
256
        Before, After string
 
257
}
 
258
 
 
259
type PathTestSet struct {
 
260
        Item1 []PathTestItem
 
261
}
 
262
 
 
263
type PathTestD struct {
 
264
        Other         PathTestSet `xml:"Items"`
 
265
        Before, After string
 
266
}
 
267
 
 
268
type PathTestE struct {
 
269
        Underline     string `xml:"Items>_>Value"`
 
270
        Before, After string
 
271
}
 
272
 
 
273
var pathTests = []interface{}{
 
274
        &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
 
275
        &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"},
 
276
        &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"},
 
277
        &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"},
 
278
        &PathTestE{Underline: "E", Before: "1", After: "2"},
 
279
}
 
280
 
 
281
func TestUnmarshalPaths(t *testing.T) {
 
282
        for _, pt := range pathTests {
 
283
                v := reflect.New(reflect.TypeOf(pt).Elem()).Interface()
 
284
                if err := Unmarshal([]byte(pathTestString), v); err != nil {
 
285
                        t.Fatalf("Unmarshal: %s", err)
 
286
                }
 
287
                if !reflect.DeepEqual(v, pt) {
 
288
                        t.Fatalf("have %#v\nwant %#v", v, pt)
 
289
                }
 
290
        }
 
291
}
 
292
 
 
293
type BadPathTestA struct {
 
294
        First  string `xml:"items>item1"`
 
295
        Other  string `xml:"items>item2"`
 
296
        Second string `xml:"items"`
 
297
}
 
298
 
 
299
type BadPathTestB struct {
 
300
        Other  string `xml:"items>item2>value"`
 
301
        First  string `xml:"items>item1"`
 
302
        Second string `xml:"items>item1>value"`
 
303
}
 
304
 
 
305
type BadPathTestC struct {
 
306
        First  string
 
307
        Second string `xml:"First"`
 
308
}
 
309
 
 
310
type BadPathTestD struct {
 
311
        BadPathEmbeddedA
 
312
        BadPathEmbeddedB
 
313
}
 
314
 
 
315
type BadPathEmbeddedA struct {
 
316
        First string
 
317
}
 
318
 
 
319
type BadPathEmbeddedB struct {
 
320
        Second string `xml:"First"`
 
321
}
 
322
 
 
323
var badPathTests = []struct {
 
324
        v, e interface{}
 
325
}{
 
326
        {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items"}},
 
327
        {&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
 
328
        {&BadPathTestC{}, &TagPathError{reflect.TypeOf(BadPathTestC{}), "First", "", "Second", "First"}},
 
329
        {&BadPathTestD{}, &TagPathError{reflect.TypeOf(BadPathTestD{}), "First", "", "Second", "First"}},
 
330
}
 
331
 
 
332
func TestUnmarshalBadPaths(t *testing.T) {
 
333
        for _, tt := range badPathTests {
 
334
                err := Unmarshal([]byte(pathTestString), tt.v)
 
335
                if !reflect.DeepEqual(err, tt.e) {
 
336
                        t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e)
 
337
                }
 
338
        }
 
339
}
 
340
 
 
341
const OK = "OK"
 
342
const withoutNameTypeData = `
 
343
<?xml version="1.0" charset="utf-8"?>
 
344
<Test3 Attr="OK" />`
 
345
 
 
346
type TestThree struct {
 
347
        XMLName Name   `xml:"Test3"`
 
348
        Attr    string `xml:",attr"`
 
349
}
 
350
 
 
351
func TestUnmarshalWithoutNameType(t *testing.T) {
 
352
        var x TestThree
 
353
        if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil {
 
354
                t.Fatalf("Unmarshal: %s", err)
 
355
        }
 
356
        if x.Attr != OK {
 
357
                t.Fatalf("have %v\nwant %v", x.Attr, OK)
 
358
        }
 
359
}
 
360
 
 
361
func TestUnmarshalAttr(t *testing.T) {
 
362
        type ParamVal struct {
 
363
                Int int `xml:"int,attr"`
 
364
        }
 
365
 
 
366
        type ParamPtr struct {
 
367
                Int *int `xml:"int,attr"`
 
368
        }
 
369
 
 
370
        type ParamStringPtr struct {
 
371
                Int *string `xml:"int,attr"`
 
372
        }
 
373
 
 
374
        x := []byte(`<Param int="1" />`)
 
375
 
 
376
        p1 := &ParamPtr{}
 
377
        if err := Unmarshal(x, p1); err != nil {
 
378
                t.Fatalf("Unmarshal: %s", err)
 
379
        }
 
380
        if p1.Int == nil {
 
381
                t.Fatalf("Unmarshal failed in to *int field")
 
382
        } else if *p1.Int != 1 {
 
383
                t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p1.Int, 1)
 
384
        }
 
385
 
 
386
        p2 := &ParamVal{}
 
387
        if err := Unmarshal(x, p2); err != nil {
 
388
                t.Fatalf("Unmarshal: %s", err)
 
389
        }
 
390
        if p2.Int != 1 {
 
391
                t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p2.Int, 1)
 
392
        }
 
393
 
 
394
        p3 := &ParamStringPtr{}
 
395
        if err := Unmarshal(x, p3); err != nil {
 
396
                t.Fatalf("Unmarshal: %s", err)
 
397
        }
 
398
        if p3.Int == nil {
 
399
                t.Fatalf("Unmarshal failed in to *string field")
 
400
        } else if *p3.Int != "1" {
 
401
                t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1)
 
402
        }
 
403
}
 
404
 
 
405
type Tables struct {
 
406
        HTable string `xml:"http://www.w3.org/TR/html4/ table"`
 
407
        FTable string `xml:"http://www.w3schools.com/furniture table"`
 
408
}
 
409
 
 
410
var tables = []struct {
 
411
        xml string
 
412
        tab Tables
 
413
        ns  string
 
414
}{
 
415
        {
 
416
                xml: `<Tables>` +
 
417
                        `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
 
418
                        `<table xmlns="http://www.w3schools.com/furniture">world</table>` +
 
419
                        `</Tables>`,
 
420
                tab: Tables{"hello", "world"},
 
421
        },
 
422
        {
 
423
                xml: `<Tables>` +
 
424
                        `<table xmlns="http://www.w3schools.com/furniture">world</table>` +
 
425
                        `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
 
426
                        `</Tables>`,
 
427
                tab: Tables{"hello", "world"},
 
428
        },
 
429
        {
 
430
                xml: `<Tables xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/">` +
 
431
                        `<f:table>world</f:table>` +
 
432
                        `<h:table>hello</h:table>` +
 
433
                        `</Tables>`,
 
434
                tab: Tables{"hello", "world"},
 
435
        },
 
436
        {
 
437
                xml: `<Tables>` +
 
438
                        `<table>bogus</table>` +
 
439
                        `</Tables>`,
 
440
                tab: Tables{},
 
441
        },
 
442
        {
 
443
                xml: `<Tables>` +
 
444
                        `<table>only</table>` +
 
445
                        `</Tables>`,
 
446
                tab: Tables{HTable: "only"},
 
447
                ns:  "http://www.w3.org/TR/html4/",
 
448
        },
 
449
        {
 
450
                xml: `<Tables>` +
 
451
                        `<table>only</table>` +
 
452
                        `</Tables>`,
 
453
                tab: Tables{FTable: "only"},
 
454
                ns:  "http://www.w3schools.com/furniture",
 
455
        },
 
456
        {
 
457
                xml: `<Tables>` +
 
458
                        `<table>only</table>` +
 
459
                        `</Tables>`,
 
460
                tab: Tables{},
 
461
                ns:  "something else entirely",
 
462
        },
 
463
}
 
464
 
 
465
func TestUnmarshalNS(t *testing.T) {
 
466
        for i, tt := range tables {
 
467
                var dst Tables
 
468
                var err error
 
469
                if tt.ns != "" {
 
470
                        d := NewDecoder(strings.NewReader(tt.xml))
 
471
                        d.DefaultSpace = tt.ns
 
472
                        err = d.Decode(&dst)
 
473
                } else {
 
474
                        err = Unmarshal([]byte(tt.xml), &dst)
 
475
                }
 
476
                if err != nil {
 
477
                        t.Errorf("#%d: Unmarshal: %v", i, err)
 
478
                        continue
 
479
                }
 
480
                want := tt.tab
 
481
                if dst != want {
 
482
                        t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
 
483
                }
 
484
        }
 
485
}
 
486
 
 
487
func TestMarshalNS(t *testing.T) {
 
488
        dst := Tables{"hello", "world"}
 
489
        data, err := Marshal(&dst)
 
490
        if err != nil {
 
491
                t.Fatalf("Marshal: %v", err)
 
492
        }
 
493
        want := `<Tables><table xmlns="http://www.w3.org/TR/html4/">hello</table><table xmlns="http://www.w3schools.com/furniture">world</table></Tables>`
 
494
        str := string(data)
 
495
        if str != want {
 
496
                t.Errorf("have: %q\nwant: %q\n", str, want)
 
497
        }
 
498
}
 
499
 
 
500
type TableAttrs struct {
 
501
        TAttr TAttr
 
502
}
 
503
 
 
504
type TAttr struct {
 
505
        HTable string `xml:"http://www.w3.org/TR/html4/ table,attr"`
 
506
        FTable string `xml:"http://www.w3schools.com/furniture table,attr"`
 
507
        Lang   string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
 
508
        Other1 string `xml:"http://golang.org/xml/ other,attr,omitempty"`
 
509
        Other2 string `xml:"http://golang.org/xmlfoo/ other,attr,omitempty"`
 
510
        Other3 string `xml:"http://golang.org/json/ other,attr,omitempty"`
 
511
        Other4 string `xml:"http://golang.org/2/json/ other,attr,omitempty"`
 
512
}
 
513
 
 
514
var tableAttrs = []struct {
 
515
        xml string
 
516
        tab TableAttrs
 
517
        ns  string
 
518
}{
 
519
        {
 
520
                xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
 
521
                        `h:table="hello" f:table="world" ` +
 
522
                        `/></TableAttrs>`,
 
523
                tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
 
524
        },
 
525
        {
 
526
                xml: `<TableAttrs><TAttr xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` +
 
527
                        `h:table="hello" f:table="world" ` +
 
528
                        `/></TableAttrs>`,
 
529
                tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
 
530
        },
 
531
        {
 
532
                xml: `<TableAttrs><TAttr ` +
 
533
                        `h:table="hello" f:table="world" xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` +
 
534
                        `/></TableAttrs>`,
 
535
                tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
 
536
        },
 
537
        {
 
538
                // Default space does not apply to attribute names.
 
539
                xml: `<TableAttrs xmlns="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
 
540
                        `h:table="hello" table="world" ` +
 
541
                        `/></TableAttrs>`,
 
542
                tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
 
543
        },
 
544
        {
 
545
                // Default space does not apply to attribute names.
 
546
                xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr xmlns="http://www.w3.org/TR/html4/" ` +
 
547
                        `table="hello" f:table="world" ` +
 
548
                        `/></TableAttrs>`,
 
549
                tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
 
550
        },
 
551
        {
 
552
                xml: `<TableAttrs><TAttr ` +
 
553
                        `table="bogus" ` +
 
554
                        `/></TableAttrs>`,
 
555
                tab: TableAttrs{},
 
556
        },
 
557
        {
 
558
                // Default space does not apply to attribute names.
 
559
                xml: `<TableAttrs xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
 
560
                        `h:table="hello" table="world" ` +
 
561
                        `/></TableAttrs>`,
 
562
                tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
 
563
                ns:  "http://www.w3schools.com/furniture",
 
564
        },
 
565
        {
 
566
                // Default space does not apply to attribute names.
 
567
                xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr ` +
 
568
                        `table="hello" f:table="world" ` +
 
569
                        `/></TableAttrs>`,
 
570
                tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
 
571
                ns:  "http://www.w3.org/TR/html4/",
 
572
        },
 
573
        {
 
574
                xml: `<TableAttrs><TAttr ` +
 
575
                        `table="bogus" ` +
 
576
                        `/></TableAttrs>`,
 
577
                tab: TableAttrs{},
 
578
                ns:  "something else entirely",
 
579
        },
 
580
}
 
581
 
 
582
func TestUnmarshalNSAttr(t *testing.T) {
 
583
        for i, tt := range tableAttrs {
 
584
                var dst TableAttrs
 
585
                var err error
 
586
                if tt.ns != "" {
 
587
                        d := NewDecoder(strings.NewReader(tt.xml))
 
588
                        d.DefaultSpace = tt.ns
 
589
                        err = d.Decode(&dst)
 
590
                } else {
 
591
                        err = Unmarshal([]byte(tt.xml), &dst)
 
592
                }
 
593
                if err != nil {
 
594
                        t.Errorf("#%d: Unmarshal: %v", i, err)
 
595
                        continue
 
596
                }
 
597
                want := tt.tab
 
598
                if dst != want {
 
599
                        t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
 
600
                }
 
601
        }
 
602
}
 
603
 
 
604
func TestMarshalNSAttr(t *testing.T) {
 
605
        src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}}
 
606
        data, err := Marshal(&src)
 
607
        if err != nil {
 
608
                t.Fatalf("Marshal: %v", err)
 
609
        }
 
610
        want := `<TableAttrs><TAttr xmlns:html4="http://www.w3.org/TR/html4/" html4:table="hello" xmlns:furniture="http://www.w3schools.com/furniture" furniture:table="world" xml:lang="en_US" xmlns:_xml="http://golang.org/xml/" _xml:other="other1" xmlns:_xmlfoo="http://golang.org/xmlfoo/" _xmlfoo:other="other2" xmlns:json="http://golang.org/json/" json:other="other3" xmlns:json_1="http://golang.org/2/json/" json_1:other="other4"></TAttr></TableAttrs>`
 
611
        str := string(data)
 
612
        if str != want {
 
613
                t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want)
 
614
        }
 
615
 
 
616
        var dst TableAttrs
 
617
        if err := Unmarshal(data, &dst); err != nil {
 
618
                t.Errorf("Unmarshal: %v", err)
 
619
        }
 
620
 
 
621
        if dst != src {
 
622
                t.Errorf("Unmarshal = %q, want %q", dst, src)
 
623
        }
 
624
}
 
625
 
 
626
type MyCharData struct {
 
627
        body string
 
628
}
 
629
 
 
630
func (m *MyCharData) UnmarshalXML(d *Decoder, start StartElement) error {
 
631
        for {
 
632
                t, err := d.Token()
 
633
                if err == io.EOF { // found end of element
 
634
                        break
 
635
                }
 
636
                if err != nil {
 
637
                        return err
 
638
                }
 
639
                if char, ok := t.(CharData); ok {
 
640
                        m.body += string(char)
 
641
                }
 
642
        }
 
643
        return nil
 
644
}
 
645
 
 
646
var _ Unmarshaler = (*MyCharData)(nil)
 
647
 
 
648
func (m *MyCharData) UnmarshalXMLAttr(attr Attr) error {
 
649
        panic("must not call")
 
650
}
 
651
 
 
652
type MyAttr struct {
 
653
        attr string
 
654
}
 
655
 
 
656
func (m *MyAttr) UnmarshalXMLAttr(attr Attr) error {
 
657
        m.attr = attr.Value
 
658
        return nil
 
659
}
 
660
 
 
661
var _ UnmarshalerAttr = (*MyAttr)(nil)
 
662
 
 
663
type MyStruct struct {
 
664
        Data *MyCharData
 
665
        Attr *MyAttr `xml:",attr"`
 
666
 
 
667
        Data2 MyCharData
 
668
        Attr2 MyAttr `xml:",attr"`
 
669
}
 
670
 
 
671
func TestUnmarshaler(t *testing.T) {
 
672
        xml := `<?xml version="1.0" encoding="utf-8"?>
 
673
                <MyStruct Attr="attr1" Attr2="attr2">
 
674
                <Data>hello <!-- comment -->world</Data>
 
675
                <Data2>howdy <!-- comment -->world</Data2>
 
676
                </MyStruct>
 
677
        `
 
678
 
 
679
        var m MyStruct
 
680
        if err := Unmarshal([]byte(xml), &m); err != nil {
 
681
                t.Fatal(err)
 
682
        }
 
683
 
 
684
        if m.Data == nil || m.Attr == nil || m.Data.body != "hello world" || m.Attr.attr != "attr1" || m.Data2.body != "howdy world" || m.Attr2.attr != "attr2" {
 
685
                t.Errorf("m=%#+v\n", m)
 
686
        }
 
687
}
 
688
 
 
689
type Pea struct {
 
690
        Cotelydon string
 
691
}
 
692
 
 
693
type Pod struct {
 
694
        Pea interface{} `xml:"Pea"`
 
695
}
 
696
 
 
697
// https://code.google.com/p/go/issues/detail?id=6836
 
698
func TestUnmarshalIntoInterface(t *testing.T) {
 
699
        pod := new(Pod)
 
700
        pod.Pea = new(Pea)
 
701
        xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
 
702
        err := Unmarshal([]byte(xml), pod)
 
703
        if err != nil {
 
704
                t.Fatalf("failed to unmarshal %q: %v", xml, err)
 
705
        }
 
706
        pea, ok := pod.Pea.(*Pea)
 
707
        if !ok {
 
708
                t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
 
709
        }
 
710
        have, want := pea.Cotelydon, "Green stuff"
 
711
        if have != want {
 
712
                t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
 
713
        }
 
714
}
 
715
 
 
716
// https://github.com/vmware/govmomi/issues/246
 
717
func TestNegativeValuesUnsignedFields(t *testing.T) {
 
718
        type T struct {
 
719
                I   string
 
720
                O   interface{}
 
721
                U8  uint8  `xml:"u8"`
 
722
                U16 uint16 `xml:"u16"`
 
723
                U32 uint32 `xml:"u32"`
 
724
                U64 uint64 `xml:"u64"`
 
725
        }
 
726
 
 
727
        var tests = []T{
 
728
                {I: "<T><u8>-128</u8></T>", O: uint8(0x80)},
 
729
                {I: "<T><u8>-1</u8></T>", O: uint8(0xff)},
 
730
                {I: "<T><u16>-32768</u16></T>", O: uint16(0x8000)},
 
731
                {I: "<T><u16>-1</u16></T>", O: uint16(0xffff)},
 
732
                {I: "<T><u32>-2147483648</u32></T>", O: uint32(0x80000000)},
 
733
                {I: "<T><u32>-1</u32></T>", O: uint32(0xffffffff)},
 
734
                {I: "<T><u64>-9223372036854775808</u64></T>", O: uint64(0x8000000000000000)},
 
735
                {I: "<T><u64>-1</u64></T>", O: uint64(0xffffffffffffffff)},
 
736
        }
 
737
 
 
738
        for _, test := range tests {
 
739
                err := Unmarshal([]byte(test.I), &test)
 
740
                if err != nil {
 
741
                        t.Errorf("Unmarshal error: %v", err)
 
742
                        continue
 
743
                }
 
744
 
 
745
                var expected = test.O
 
746
                var actual interface{}
 
747
                switch reflect.ValueOf(test.O).Type().Kind() {
 
748
                case reflect.Uint8:
 
749
                        actual = test.U8
 
750
                case reflect.Uint16:
 
751
                        actual = test.U16
 
752
                case reflect.Uint32:
 
753
                        actual = test.U32
 
754
                case reflect.Uint64:
 
755
                        actual = test.U64
 
756
                }
 
757
 
 
758
                if !reflect.DeepEqual(actual, expected) {
 
759
                        t.Errorf("Actual: %v, expected: %v", actual, expected)
 
760
                }
 
761
        }
 
762
}