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.
15
// Stripped down Atom feed data structures.
17
func TestUnmarshalFeed(t *testing.T) {
19
if err := Unmarshal([]byte(atomFeedString), &f); err != nil {
20
t.Fatalf("Unmarshal: %s", err)
22
if !reflect.DeepEqual(f, atomFeed) {
23
t.Fatalf("have %#v\nwant %#v", f, atomFeed)
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<></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
36
The server side of the protocol is trivial:
37
1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&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.
42
I have tested this by adding debug prints to a local hub
43
server and checking that the server got the right publish
46
I can&#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&#39;s actual URL in
49
the link rel=&quot;self&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
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).
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
67
The fundamental problem was that the tab code was
68
not being told what column the text began in, so it
69
didn&#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.
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.
81
</summary></entry></feed> `
84
XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
85
Title string `xml:"title"`
87
Link []Link `xml:"link"`
88
Updated time.Time `xml:"updated,attr"`
89
Author Person `xml:"author"`
90
Entry []Entry `xml:"entry"`
94
Title string `xml:"title"`
96
Link []Link `xml:"link"`
97
Updated time.Time `xml:"updated"`
98
Author Person `xml:"author"`
99
Summary Text `xml:"summary"`
103
Rel string `xml:"rel,attr,omitempty"`
104
Href string `xml:"href,attr"`
108
Name string `xml:"name"`
109
URI string `xml:"uri"`
110
Email string `xml:"email"`
111
InnerXML string `xml:",innerxml"`
115
Type string `xml:"type,attr,omitempty"`
116
Body string `xml:",chardata"`
120
XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
121
Title: "Code Review - My issues",
123
{Rel: "alternate", Href: "http://codereview.appspot.com/"},
124
{Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
126
Id: "http://codereview.appspot.com/",
127
Updated: ParseTime("2009-10-04T01:35:58+00:00"),
130
InnerXML: "<name>rietveld<></name>",
134
Title: "rietveld: an attempt at pubsubhubbub\n",
136
{Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
138
Updated: ParseTime("2009-10-04T01:35:58+00:00"),
140
Name: "email-address-removed",
141
InnerXML: "<name>email-address-removed</name>",
143
Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
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
151
The server side of the protocol is trivial:
152
1. add a <link rel="hub" href="hub-server"> 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.
157
I have tested this by adding debug prints to a local hub
158
server and checking that the server got the right publish
161
I can'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's actual URL in
164
the link rel="self", 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!)
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).
181
Title: "rietveld: correct tab handling\n",
183
{Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
185
Updated: ParseTime("2009-10-03T23:02:17+00:00"),
187
Name: "email-address-removed",
188
InnerXML: "<name>email-address-removed</name>",
190
Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
194
This fixes the buggy tab rendering that can be seen at
195
http://codereview.appspot.com/116075/diff/1/2
197
The fundamental problem was that the tab code was
198
not being told what column the text began in, so it
199
didn'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.
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.
217
const pathTestString = `
239
type PathTestItem struct {
243
type PathTestA struct {
244
Items []PathTestItem `xml:">Item1"`
248
type PathTestB struct {
249
Other []PathTestItem `xml:"Items>Item1"`
253
type PathTestC struct {
254
Values1 []string `xml:"Items>Item1>Value"`
255
Values2 []string `xml:"Items>Item2>Value"`
259
type PathTestSet struct {
263
type PathTestD struct {
264
Other PathTestSet `xml:"Items"`
268
type PathTestE struct {
269
Underline string `xml:"Items>_>Value"`
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"},
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)
287
if !reflect.DeepEqual(v, pt) {
288
t.Fatalf("have %#v\nwant %#v", v, pt)
293
type BadPathTestA struct {
294
First string `xml:"items>item1"`
295
Other string `xml:"items>item2"`
296
Second string `xml:"items"`
299
type BadPathTestB struct {
300
Other string `xml:"items>item2>value"`
301
First string `xml:"items>item1"`
302
Second string `xml:"items>item1>value"`
305
type BadPathTestC struct {
307
Second string `xml:"First"`
310
type BadPathTestD struct {
315
type BadPathEmbeddedA struct {
319
type BadPathEmbeddedB struct {
320
Second string `xml:"First"`
323
var badPathTests = []struct {
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"}},
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)
342
const withoutNameTypeData = `
343
<?xml version="1.0" charset="utf-8"?>
346
type TestThree struct {
347
XMLName Name `xml:"Test3"`
348
Attr string `xml:",attr"`
351
func TestUnmarshalWithoutNameType(t *testing.T) {
353
if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil {
354
t.Fatalf("Unmarshal: %s", err)
357
t.Fatalf("have %v\nwant %v", x.Attr, OK)
361
func TestUnmarshalAttr(t *testing.T) {
362
type ParamVal struct {
363
Int int `xml:"int,attr"`
366
type ParamPtr struct {
367
Int *int `xml:"int,attr"`
370
type ParamStringPtr struct {
371
Int *string `xml:"int,attr"`
374
x := []byte(`<Param int="1" />`)
377
if err := Unmarshal(x, p1); err != nil {
378
t.Fatalf("Unmarshal: %s", err)
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)
387
if err := Unmarshal(x, p2); err != nil {
388
t.Fatalf("Unmarshal: %s", err)
391
t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p2.Int, 1)
394
p3 := &ParamStringPtr{}
395
if err := Unmarshal(x, p3); err != nil {
396
t.Fatalf("Unmarshal: %s", err)
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)
406
HTable string `xml:"http://www.w3.org/TR/html4/ table"`
407
FTable string `xml:"http://www.w3schools.com/furniture table"`
410
var tables = []struct {
417
`<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
418
`<table xmlns="http://www.w3schools.com/furniture">world</table>` +
420
tab: Tables{"hello", "world"},
424
`<table xmlns="http://www.w3schools.com/furniture">world</table>` +
425
`<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
427
tab: Tables{"hello", "world"},
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>` +
434
tab: Tables{"hello", "world"},
438
`<table>bogus</table>` +
444
`<table>only</table>` +
446
tab: Tables{HTable: "only"},
447
ns: "http://www.w3.org/TR/html4/",
451
`<table>only</table>` +
453
tab: Tables{FTable: "only"},
454
ns: "http://www.w3schools.com/furniture",
458
`<table>only</table>` +
461
ns: "something else entirely",
465
func TestUnmarshalNS(t *testing.T) {
466
for i, tt := range tables {
470
d := NewDecoder(strings.NewReader(tt.xml))
471
d.DefaultSpace = tt.ns
474
err = Unmarshal([]byte(tt.xml), &dst)
477
t.Errorf("#%d: Unmarshal: %v", i, err)
482
t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
487
func TestMarshalNS(t *testing.T) {
488
dst := Tables{"hello", "world"}
489
data, err := Marshal(&dst)
491
t.Fatalf("Marshal: %v", err)
493
want := `<Tables><table xmlns="http://www.w3.org/TR/html4/">hello</table><table xmlns="http://www.w3schools.com/furniture">world</table></Tables>`
496
t.Errorf("have: %q\nwant: %q\n", str, want)
500
type TableAttrs 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"`
514
var tableAttrs = []struct {
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" ` +
523
tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
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" ` +
529
tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
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/" ` +
535
tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
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" ` +
542
tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
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" ` +
549
tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
552
xml: `<TableAttrs><TAttr ` +
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" ` +
562
tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
563
ns: "http://www.w3schools.com/furniture",
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" ` +
570
tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
571
ns: "http://www.w3.org/TR/html4/",
574
xml: `<TableAttrs><TAttr ` +
578
ns: "something else entirely",
582
func TestUnmarshalNSAttr(t *testing.T) {
583
for i, tt := range tableAttrs {
587
d := NewDecoder(strings.NewReader(tt.xml))
588
d.DefaultSpace = tt.ns
591
err = Unmarshal([]byte(tt.xml), &dst)
594
t.Errorf("#%d: Unmarshal: %v", i, err)
599
t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
604
func TestMarshalNSAttr(t *testing.T) {
605
src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}}
606
data, err := Marshal(&src)
608
t.Fatalf("Marshal: %v", err)
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>`
613
t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want)
617
if err := Unmarshal(data, &dst); err != nil {
618
t.Errorf("Unmarshal: %v", err)
622
t.Errorf("Unmarshal = %q, want %q", dst, src)
626
type MyCharData struct {
630
func (m *MyCharData) UnmarshalXML(d *Decoder, start StartElement) error {
633
if err == io.EOF { // found end of element
639
if char, ok := t.(CharData); ok {
640
m.body += string(char)
646
var _ Unmarshaler = (*MyCharData)(nil)
648
func (m *MyCharData) UnmarshalXMLAttr(attr Attr) error {
649
panic("must not call")
656
func (m *MyAttr) UnmarshalXMLAttr(attr Attr) error {
661
var _ UnmarshalerAttr = (*MyAttr)(nil)
663
type MyStruct struct {
665
Attr *MyAttr `xml:",attr"`
668
Attr2 MyAttr `xml:",attr"`
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>
680
if err := Unmarshal([]byte(xml), &m); err != nil {
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)
694
Pea interface{} `xml:"Pea"`
697
// https://code.google.com/p/go/issues/detail?id=6836
698
func TestUnmarshalIntoInterface(t *testing.T) {
701
xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
702
err := Unmarshal([]byte(xml), pod)
704
t.Fatalf("failed to unmarshal %q: %v", xml, err)
706
pea, ok := pod.Pea.(*Pea)
708
t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
710
have, want := pea.Cotelydon, "Green stuff"
712
t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
716
// https://github.com/vmware/govmomi/issues/246
717
func TestNegativeValuesUnsignedFields(t *testing.T) {
722
U16 uint16 `xml:"u16"`
723
U32 uint32 `xml:"u32"`
724
U64 uint64 `xml:"u64"`
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)},
738
for _, test := range tests {
739
err := Unmarshal([]byte(test.I), &test)
741
t.Errorf("Unmarshal error: %v", err)
745
var expected = test.O
746
var actual interface{}
747
switch reflect.ValueOf(test.O).Type().Kind() {
758
if !reflect.DeepEqual(actual, expected) {
759
t.Errorf("Actual: %v, expected: %v", actual, expected)