OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [encoding/] [xml/] [marshal_test.go] - Rev 747

Compare with Previous | Blame | View Log

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xml

import (
        "reflect"
        "strconv"
        "strings"
        "testing"
)

type DriveType int

const (
        HyperDrive DriveType = iota
        ImprobabilityDrive
)

type Passenger struct {
        Name   []string `xml:"name"`
        Weight float32  `xml:"weight"`
}

type Ship struct {
        XMLName struct{} `xml:"spaceship"`

        Name      string       `xml:"name,attr"`
        Pilot     string       `xml:"pilot,attr"`
        Drive     DriveType    `xml:"drive"`
        Age       uint         `xml:"age"`
        Passenger []*Passenger `xml:"passenger"`
        secret    string
}

type NamedType string

type Port struct {
        XMLName struct{} `xml:"port"`
        Type    string   `xml:"type,attr"`
        Comment string   `xml:",comment"`
        Number  string   `xml:",chardata"`
}

type Domain struct {
        XMLName struct{} `xml:"domain"`
        Country string   `xml:",attr"`
        Name    []byte   `xml:",chardata"`
        Comment []byte   `xml:",comment"`
}

type Book struct {
        XMLName struct{} `xml:"book"`
        Title   string   `xml:",chardata"`
}

type SecretAgent struct {
        XMLName   struct{} `xml:"agent"`
        Handle    string   `xml:"handle,attr"`
        Identity  string
        Obfuscate string `xml:",innerxml"`
}

type NestedItems struct {
        XMLName struct{} `xml:"result"`
        Items   []string `xml:">item"`
        Item1   []string `xml:"Items>item1"`
}

type NestedOrder struct {
        XMLName struct{} `xml:"result"`
        Field1  string   `xml:"parent>c"`
        Field2  string   `xml:"parent>b"`
        Field3  string   `xml:"parent>a"`
}

type MixedNested struct {
        XMLName struct{} `xml:"result"`
        A       string   `xml:"parent1>a"`
        B       string   `xml:"b"`
        C       string   `xml:"parent1>parent2>c"`
        D       string   `xml:"parent1>d"`
}

type NilTest struct {
        A interface{} `xml:"parent1>parent2>a"`
        B interface{} `xml:"parent1>b"`
        C interface{} `xml:"parent1>parent2>c"`
}

type Service struct {
        XMLName struct{} `xml:"service"`
        Domain  *Domain  `xml:"host>domain"`
        Port    *Port    `xml:"host>port"`
        Extra1  interface{}
        Extra2  interface{} `xml:"host>extra2"`
}

var nilStruct *Ship

type EmbedA struct {
        EmbedC
        EmbedB EmbedB
        FieldA string
}

type EmbedB struct {
        FieldB string
        EmbedC
}

type EmbedC struct {
        FieldA1 string `xml:"FieldA>A1"`
        FieldA2 string `xml:"FieldA>A2"`
        FieldB  string
        FieldC  string
}

type NameCasing struct {
        XMLName struct{} `xml:"casing"`
        Xy      string
        XY      string
        XyA     string `xml:"Xy,attr"`
        XYA     string `xml:"XY,attr"`
}

type NamePrecedence struct {
        XMLName     Name              `xml:"Parent"`
        FromTag     XMLNameWithoutTag `xml:"InTag"`
        FromNameVal XMLNameWithoutTag
        FromNameTag XMLNameWithTag
        InFieldName string
}

type XMLNameWithTag struct {
        XMLName Name   `xml:"InXMLNameTag"`
        Value   string ",chardata"
}

type XMLNameWithoutTag struct {
        XMLName Name
        Value   string ",chardata"
}

type NameInField struct {
        Foo Name `xml:"ns foo"`
}

type AttrTest struct {
        Int   int     `xml:",attr"`
        Lower int     `xml:"int,attr"`
        Float float64 `xml:",attr"`
        Uint8 uint8   `xml:",attr"`
        Bool  bool    `xml:",attr"`
        Str   string  `xml:",attr"`
}

type AnyTest struct {
        XMLName  struct{}  `xml:"a"`
        Nested   string    `xml:"nested>value"`
        AnyField AnyHolder `xml:",any"`
}

type AnyHolder struct {
        XMLName Name
        XML     string `xml:",innerxml"`
}

type RecurseA struct {
        A string
        B *RecurseB
}

type RecurseB struct {
        A *RecurseA
        B string
}

type PresenceTest struct {
        Exists *struct{}
}

type IgnoreTest struct {
        PublicSecret string `xml:"-"`
}

type MyBytes []byte

type Data struct {
        Bytes  []byte
        Attr   []byte `xml:",attr"`
        Custom MyBytes
}

type Plain struct {
        V interface{}
}

// Unless explicitly stated as such (or *Plain), all of the
// tests below are two-way tests. When introducing new tests,
// please try to make them two-way as well to ensure that
// marshalling and unmarshalling are as symmetrical as feasible.
var marshalTests = []struct {
        Value         interface{}
        ExpectXML     string
        MarshalOnly   bool
        UnmarshalOnly bool
}{
        // Test nil marshals to nothing
        {Value: nil, ExpectXML: ``, MarshalOnly: true},
        {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},

        // Test value types
        {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
        {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
        {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
        {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
        {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
        {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
        {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
        {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
        {Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
        {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
        {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
        {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
        {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
        {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},

        // A pointer to struct{} may be used to test for an element's presence.
        {
                Value:     &PresenceTest{new(struct{})},
                ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
        },
        {
                Value:     &PresenceTest{},
                ExpectXML: `<PresenceTest></PresenceTest>`,
        },

        // A pointer to struct{} may be used to test for an element's presence.
        {
                Value:     &PresenceTest{new(struct{})},
                ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
        },
        {
                Value:     &PresenceTest{},
                ExpectXML: `<PresenceTest></PresenceTest>`,
        },

        // A []byte field is only nil if the element was not found.
        {
                Value:         &Data{},
                ExpectXML:     `<Data></Data>`,
                UnmarshalOnly: true,
        },
        {
                Value:         &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
                ExpectXML:     `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
                UnmarshalOnly: true,
        },

        // Check that []byte works, including named []byte types.
        {
                Value:     &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
                ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
        },

        // Test innerxml
        {
                Value: &SecretAgent{
                        Handle:    "007",
                        Identity:  "James Bond",
                        Obfuscate: "<redacted/>",
                },
                ExpectXML:   `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
                MarshalOnly: true,
        },
        {
                Value: &SecretAgent{
                        Handle:    "007",
                        Identity:  "James Bond",
                        Obfuscate: "<Identity>James Bond</Identity><redacted/>",
                },
                ExpectXML:     `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
                UnmarshalOnly: true,
        },

        // Test structs
        {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
        {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
        {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
        {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
        {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
        {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
        {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
        {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
        {Value: atomValue, ExpectXML: atomXml},
        {
                Value: &Ship{
                        Name:  "Heart of Gold",
                        Pilot: "Computer",
                        Age:   1,
                        Drive: ImprobabilityDrive,
                        Passenger: []*Passenger{
                                {
                                        Name:   []string{"Zaphod", "Beeblebrox"},
                                        Weight: 7.25,
                                },
                                {
                                        Name:   []string{"Trisha", "McMillen"},
                                        Weight: 5.5,
                                },
                                {
                                        Name:   []string{"Ford", "Prefect"},
                                        Weight: 7,
                                },
                                {
                                        Name:   []string{"Arthur", "Dent"},
                                        Weight: 6.75,
                                },
                        },
                },
                ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
                        `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
                        `<age>1</age>` +
                        `<passenger>` +
                        `<name>Zaphod</name>` +
                        `<name>Beeblebrox</name>` +
                        `<weight>7.25</weight>` +
                        `</passenger>` +
                        `<passenger>` +
                        `<name>Trisha</name>` +
                        `<name>McMillen</name>` +
                        `<weight>5.5</weight>` +
                        `</passenger>` +
                        `<passenger>` +
                        `<name>Ford</name>` +
                        `<name>Prefect</name>` +
                        `<weight>7</weight>` +
                        `</passenger>` +
                        `<passenger>` +
                        `<name>Arthur</name>` +
                        `<name>Dent</name>` +
                        `<weight>6.75</weight>` +
                        `</passenger>` +
                        `</spaceship>`,
        },

        // Test a>b
        {
                Value: &NestedItems{Items: nil, Item1: nil},
                ExpectXML: `<result>` +
                        `<Items>` +
                        `</Items>` +
                        `</result>`,
        },
        {
                Value: &NestedItems{Items: []string{}, Item1: []string{}},
                ExpectXML: `<result>` +
                        `<Items>` +
                        `</Items>` +
                        `</result>`,
                MarshalOnly: true,
        },
        {
                Value: &NestedItems{Items: nil, Item1: []string{"A"}},
                ExpectXML: `<result>` +
                        `<Items>` +
                        `<item1>A</item1>` +
                        `</Items>` +
                        `</result>`,
        },
        {
                Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
                ExpectXML: `<result>` +
                        `<Items>` +
                        `<item>A</item>` +
                        `<item>B</item>` +
                        `</Items>` +
                        `</result>`,
        },
        {
                Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
                ExpectXML: `<result>` +
                        `<Items>` +
                        `<item>A</item>` +
                        `<item>B</item>` +
                        `<item1>C</item1>` +
                        `</Items>` +
                        `</result>`,
        },
        {
                Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
                ExpectXML: `<result>` +
                        `<parent>` +
                        `<c>C</c>` +
                        `<b>B</b>` +
                        `<a>A</a>` +
                        `</parent>` +
                        `</result>`,
        },
        {
                Value: &NilTest{A: "A", B: nil, C: "C"},
                ExpectXML: `<NilTest>` +
                        `<parent1>` +
                        `<parent2><a>A</a></parent2>` +
                        `<parent2><c>C</c></parent2>` +
                        `</parent1>` +
                        `</NilTest>`,
                MarshalOnly: true, // Uses interface{}
        },
        {
                Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
                ExpectXML: `<result>` +
                        `<parent1><a>A</a></parent1>` +
                        `<b>B</b>` +
                        `<parent1>` +
                        `<parent2><c>C</c></parent2>` +
                        `<d>D</d>` +
                        `</parent1>` +
                        `</result>`,
        },
        {
                Value:     &Service{Port: &Port{Number: "80"}},
                ExpectXML: `<service><host><port>80</port></host></service>`,
        },
        {
                Value:     &Service{},
                ExpectXML: `<service></service>`,
        },
        {
                Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
                ExpectXML: `<service>` +
                        `<host><port>80</port></host>` +
                        `<Extra1>A</Extra1>` +
                        `<host><extra2>B</extra2></host>` +
                        `</service>`,
                MarshalOnly: true,
        },
        {
                Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
                ExpectXML: `<service>` +
                        `<host><port>80</port></host>` +
                        `<host><extra2>example</extra2></host>` +
                        `</service>`,
                MarshalOnly: true,
        },

        // Test struct embedding
        {
                Value: &EmbedA{
                        EmbedC: EmbedC{
                                FieldA1: "", // Shadowed by A.A
                                FieldA2: "", // Shadowed by A.A
                                FieldB:  "A.C.B",
                                FieldC:  "A.C.C",
                        },
                        EmbedB: EmbedB{
                                FieldB: "A.B.B",
                                EmbedC: EmbedC{
                                        FieldA1: "A.B.C.A1",
                                        FieldA2: "A.B.C.A2",
                                        FieldB:  "", // Shadowed by A.B.B
                                        FieldC:  "A.B.C.C",
                                },
                        },
                        FieldA: "A.A",
                },
                ExpectXML: `<EmbedA>` +
                        `<FieldB>A.C.B</FieldB>` +
                        `<FieldC>A.C.C</FieldC>` +
                        `<EmbedB>` +
                        `<FieldB>A.B.B</FieldB>` +
                        `<FieldA>` +
                        `<A1>A.B.C.A1</A1>` +
                        `<A2>A.B.C.A2</A2>` +
                        `</FieldA>` +
                        `<FieldC>A.B.C.C</FieldC>` +
                        `</EmbedB>` +
                        `<FieldA>A.A</FieldA>` +
                        `</EmbedA>`,
        },

        // Test that name casing matters
        {
                Value:     &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
                ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
        },

        // Test the order in which the XML element name is chosen
        {
                Value: &NamePrecedence{
                        FromTag:     XMLNameWithoutTag{Value: "A"},
                        FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
                        FromNameTag: XMLNameWithTag{Value: "C"},
                        InFieldName: "D",
                },
                ExpectXML: `<Parent>` +
                        `<InTag><Value>A</Value></InTag>` +
                        `<InXMLName><Value>B</Value></InXMLName>` +
                        `<InXMLNameTag><Value>C</Value></InXMLNameTag>` +
                        `<InFieldName>D</InFieldName>` +
                        `</Parent>`,
                MarshalOnly: true,
        },
        {
                Value: &NamePrecedence{
                        XMLName:     Name{Local: "Parent"},
                        FromTag:     XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
                        FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
                        FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
                        InFieldName: "D",
                },
                ExpectXML: `<Parent>` +
                        `<InTag><Value>A</Value></InTag>` +
                        `<FromNameVal><Value>B</Value></FromNameVal>` +
                        `<InXMLNameTag><Value>C</Value></InXMLNameTag>` +
                        `<InFieldName>D</InFieldName>` +
                        `</Parent>`,
                UnmarshalOnly: true,
        },

        // xml.Name works in a plain field as well.
        {
                Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
                ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
        },
        {
                Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
                ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
                UnmarshalOnly: true,
        },

        // Marshaling zero xml.Name uses the tag or field name.
        {
                Value:       &NameInField{},
                ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
                MarshalOnly: true,
        },

        // Test attributes
        {
                Value: &AttrTest{
                        Int:   8,
                        Lower: 9,
                        Float: 23.5,
                        Uint8: 255,
                        Bool:  true,
                        Str:   "s",
                },
                ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="s"></AttrTest>`,
        },

        // Test ",any"
        {
                ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
                Value: &AnyTest{
                        Nested: "known",
                        AnyField: AnyHolder{
                                XMLName: Name{Local: "other"},
                                XML:     "<sub>unknown</sub>",
                        },
                },
                UnmarshalOnly: true,
        },
        {
                Value:       &AnyTest{Nested: "known", AnyField: AnyHolder{XML: "<unknown/>"}},
                ExpectXML:   `<a><nested><value>known</value></nested></a>`,
                MarshalOnly: true,
        },

        // Test recursive types.
        {
                Value: &RecurseA{
                        A: "a1",
                        B: &RecurseB{
                                A: &RecurseA{"a2", nil},
                                B: "b1",
                        },
                },
                ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
        },

        // Test ignoring fields via "-" tag
        {
                ExpectXML: `<IgnoreTest></IgnoreTest>`,
                Value:     &IgnoreTest{},
        },
        {
                ExpectXML:   `<IgnoreTest></IgnoreTest>`,
                Value:       &IgnoreTest{PublicSecret: "can't tell"},
                MarshalOnly: true,
        },
        {
                ExpectXML:     `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
                Value:         &IgnoreTest{},
                UnmarshalOnly: true,
        },
}

func TestMarshal(t *testing.T) {
        for idx, test := range marshalTests {
                if test.UnmarshalOnly {
                        continue
                }
                data, err := Marshal(test.Value)
                if err != nil {
                        t.Errorf("#%d: Error: %s", idx, err)
                        continue
                }
                if got, want := string(data), test.ExpectXML; got != want {
                        if strings.Contains(want, "\n") {
                                t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
                        } else {
                                t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
                        }
                }
        }
}

var marshalErrorTests = []struct {
        Value interface{}
        Err   string
        Kind  reflect.Kind
}{
        {
                Value: make(chan bool),
                Err:   "xml: unsupported type: chan bool",
                Kind:  reflect.Chan,
        },
        {
                Value: map[string]string{
                        "question": "What do you get when you multiply six by nine?",
                        "answer":   "42",
                },
                Err:  "xml: unsupported type: map[string]string",
                Kind: reflect.Map,
        },
        {
                Value: map[*Ship]bool{nil: false},
                Err:   "xml: unsupported type: map[*xml.Ship]bool",
                Kind:  reflect.Map,
        },
        {
                Value: &Domain{Comment: []byte("f--bar")},
                Err:   `xml: comments must not contain "--"`,
        },
}

func TestMarshalErrors(t *testing.T) {
        for idx, test := range marshalErrorTests {
                _, err := Marshal(test.Value)
                if err == nil || err.Error() != test.Err {
                        t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
                }
                if test.Kind != reflect.Invalid {
                        if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
                                t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
                        }
                }
        }
}

// Do invertibility testing on the various structures that we test
func TestUnmarshal(t *testing.T) {
        for i, test := range marshalTests {
                if test.MarshalOnly {
                        continue
                }
                if _, ok := test.Value.(*Plain); ok {
                        continue
                }

                vt := reflect.TypeOf(test.Value)
                dest := reflect.New(vt.Elem()).Interface()
                err := Unmarshal([]byte(test.ExpectXML), dest)

                switch fix := dest.(type) {
                case *Feed:
                        fix.Author.InnerXML = ""
                        for i := range fix.Entry {
                                fix.Entry[i].Author.InnerXML = ""
                        }
                }

                if err != nil {
                        t.Errorf("#%d: unexpected error: %#v", i, err)
                } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
                        t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
                }
        }
}

func BenchmarkMarshal(b *testing.B) {
        for i := 0; i < b.N; i++ {
                Marshal(atomValue)
        }
}

func BenchmarkUnmarshal(b *testing.B) {
        xml := []byte(atomXml)
        for i := 0; i < b.N; i++ {
                Unmarshal(xml, &Feed{})
        }
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.