package xml_test
import (
"bytes"
"log"
"sort"
"testing"
"github.com/aws/smithy-go/encoding/xml"
)
var root = xml.StartElement{Name: xml.Name{Local: "root"}}
func TestEncoder(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
root := encoder.RootElement(root)
defer root.Close()
stringKey := xml.StartElement{Name: xml.Name{Local: "stringKey"}}
integerKey := xml.StartElement{Name: xml.Name{Local: "integerKey"}}
floatKey := xml.StartElement{Name: xml.Name{Local: "floatKey"}}
foo := xml.StartElement{Name: xml.Name{Local: "foo"}}
byteSlice := xml.StartElement{Name: xml.Name{Local: "byteSlice"}}
root.MemberElement(stringKey).String("stringValue")
root.MemberElement(integerKey).Integer(1024)
root.MemberElement(floatKey).Float(3.14)
ns := root.MemberElement(foo)
defer ns.Close()
ns.MemberElement(byteSlice).String("Zm9vIGJhcg==")
}()
e := []byte(`stringValue10243.14Zm9vIGJhcg==`)
verify(t, encoder, e)
}
func TestEncodeAttribute(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := xml.StartElement{
Name: xml.Name{Local: "payload", Space: "baz"},
Attr: []xml.Attr{
xml.NewAttribute("attrkey", "value"),
},
}
obj := encoder.RootElement(r)
obj.String("")
}()
expect := ``
verify(t, encoder, []byte(expect))
}
func TestEncodeNamespace(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
root := encoder.RootElement(root)
defer root.Close()
key := xml.StartElement{
Name: xml.Name{Local: "namespace"},
Attr: []xml.Attr{
xml.NewNamespaceAttribute("prefix", "https://example.com"),
},
}
n := root.MemberElement(key)
defer n.Close()
prefix := xml.StartElement{Name: xml.Name{Local: "user"}}
n.MemberElement(prefix).String("abc")
}()
e := []byte(`abc`)
verify(t, encoder, e)
}
func TestEncodeEmptyNamespacePrefix(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
root := encoder.RootElement(root)
defer root.Close()
key := xml.StartElement{
Name: xml.Name{Local: "namespace"},
Attr: []xml.Attr{
xml.NewNamespaceAttribute("", "https://example.com"),
},
}
n := root.MemberElement(key)
defer n.Close()
prefix := xml.StartElement{Name: xml.Name{Local: "user"}}
n.MemberElement(prefix).String("abc")
}()
e := []byte(`abc`)
verify(t, encoder, e)
}
func verify(t *testing.T, encoder *xml.Encoder, e []byte) {
if a := encoder.Bytes(); bytes.Compare(e, a) != 0 {
t.Errorf("expected %+q, but got %+q", e, a)
}
if a := encoder.String(); string(encoder.Bytes()) != a {
t.Errorf("expected %s, but got %s", e, a)
}
}
func TestEncodeNestedShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `nested` shape
nested := xml.StartElement{Name: xml.Name{Local: "nested"}}
n1 := r.MemberElement(nested)
defer n1.Close()
// nested `value` shape
value := xml.StartElement{Name: xml.Name{Local: "value"}}
n1.MemberElement(value).String("expected value")
}()
e := []byte(`expected value`)
defer verify(t, encoder, e)
}
func TestEncodeMapString(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapstr"}}
mapElement := r.MemberElement(mapstr)
defer mapElement.Close()
m := mapElement.Map()
key := xml.StartElement{Name: xml.Name{Local: "key"}}
value := xml.StartElement{Name: xml.Name{Local: "value"}}
e := m.Entry()
defer e.Close()
e.MemberElement(key).String("abc")
e.MemberElement(value).Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeMapFlatten(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapstr"}}
flatElement := r.FlattenedElement(mapstr)
m := flatElement.Map()
e := m.Entry()
defer e.Close()
key := xml.StartElement{Name: xml.Name{Local: "key"}}
e.MemberElement(key).String("abc")
value := xml.StartElement{Name: xml.Name{Local: "value"}}
e.MemberElement(value).Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeMapNamed(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapNamed"}}
mapElement := r.MemberElement(mapstr)
defer mapElement.Close()
m := mapElement.Map()
e := m.Entry()
defer e.Close()
key := xml.StartElement{Name: xml.Name{Local: "namedKey"}}
e.MemberElement(key).String("abc")
value := xml.StartElement{Name: xml.Name{Local: "namedValue"}}
e.MemberElement(value).Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeMapShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapShape"}}
mapElement := r.MemberElement(mapstr)
defer mapElement.Close()
m := mapElement.Map()
e := m.Entry()
defer e.Close()
key := xml.StartElement{Name: xml.Name{Local: "key"}}
e.MemberElement(key).String("abc")
value := xml.StartElement{Name: xml.Name{Local: "value"}}
n1 := e.MemberElement(value)
defer n1.Close()
shapeVal := xml.StartElement{Name: xml.Name{Local: "shapeVal"}}
n1.MemberElement(shapeVal).Integer(1)
}()
ex := []byte(`abc1`)
verify(t, encoder, ex)
}
func TestEncodeMapFlattenShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapShape"}}
flatElement := r.FlattenedElement(mapstr)
m := flatElement.Map()
e := m.Entry()
defer e.Close()
key := xml.StartElement{Name: xml.Name{Local: "key"}}
e.MemberElement(key).String("abc")
value := xml.StartElement{Name: xml.Name{Local: "value"}}
n1 := e.MemberElement(value)
defer n1.Close()
shapeVal := xml.StartElement{Name: xml.Name{Local: "shapeVal"}}
n1.MemberElement(shapeVal).Integer(1)
}()
ex := []byte(`abc1`)
verify(t, encoder, ex)
}
func TestEncodeMapNamedShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// nested `mapStr` shape
mapstr := xml.StartElement{Name: xml.Name{Local: "mapNamedShape"}}
mapElement := r.MemberElement(mapstr)
defer mapElement.Close()
m := mapElement.Map()
e := m.Entry()
defer e.Close()
key := xml.StartElement{Name: xml.Name{Local: "namedKey"}}
e.MemberElement(key).String("abc")
value := xml.StartElement{Name: xml.Name{Local: "namedValue"}}
n1 := e.MemberElement(value)
defer n1.Close()
shapeVal := xml.StartElement{Name: xml.Name{Local: "shapeVal"}}
n1.MemberElement(shapeVal).Integer(1)
}()
ex := []byte(`abc1`)
verify(t, encoder, ex)
}
func TestEncodeListString(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
m := r.MemberElement(liststr)
defer m.Close()
a := m.Array()
a.Member().String("abc")
a.Member().Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeListFlatten(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
m := r.FlattenedElement(liststr)
a := m.Array()
a.Member().String("abc")
a.Member().Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeListNamed(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
namedMember := xml.StartElement{Name: xml.Name{Local: "namedMember"}}
m := r.MemberElement(liststr)
defer m.Close()
a := m.ArrayWithCustomName(namedMember)
a.Member().String("abc")
a.Member().Integer(123)
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
//
func TestEncodeListShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
m := r.MemberElement(liststr)
defer m.Close()
a := m.Array()
value := xml.StartElement{Name: xml.Name{Local: "value"}}
m1 := a.Member()
m1.MemberElement(value).String("abc")
m1.Close()
m2 := a.Member()
m2.MemberElement(value).Integer(123)
m2.Close()
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
//
func TestEncodeListFlattenShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
m := r.FlattenedElement(liststr)
a := m.Array()
value := xml.StartElement{Name: xml.Name{Local: "value"}}
m1 := a.Member()
m1.MemberElement(value).String("abc")
m1.Close()
m2 := a.Member()
m2.MemberElement(value).Integer(123)
m2.Close()
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
//
func TestEncodeListNamedShape(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
namedMember := xml.StartElement{Name: xml.Name{Local: "namedMember"}}
// member element
m := r.MemberElement(liststr)
defer m.Close()
// Build array
a := m.ArrayWithCustomName(namedMember)
value := xml.StartElement{Name: xml.Name{Local: "value"}}
m1 := a.Member()
m1.MemberElement(value).String("abc")
m1.Close()
m2 := a.Member()
m2.MemberElement(value).Integer(123)
m2.Close()
}()
ex := []byte(`abc123`)
verify(t, encoder, ex)
}
func TestEncodeEscaping(t *testing.T) {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
func() {
r := encoder.RootElement(root)
defer r.Close()
cases := map[string]rune{
"quote": '"',
"apos": '\'',
"amp": '&',
"lt": '<',
"gt": '>',
"tab": '\t',
"newLine": '\n',
"carriageReturn": '\r',
"nextLine": '\u0085',
"lineSeparator": '\u2028',
}
var sortedKeys []string
for name := range cases {
sortedKeys = append(sortedKeys, name)
}
sort.Strings(sortedKeys)
for _, name := range sortedKeys {
rr := cases[name]
st := xml.StartElement{Name: xml.Name{Local: name}}
st.Attr = append(st.Attr, xml.Attr{
Name: xml.Name{
Local: "key",
},
Value: name + string(rr) + name,
})
value := r.MemberElement(st)
value.String(name + string(rr) + name)
}
}()
ex := []byte(`amp&apos'aposcarriageReturn
carriageReturngt>gtlineSeparator
lineSeparatorlt<ltnewLine
newLinenextLine
nextLinequote"quote
tab tab`)
verify(t, encoder, ex)
}
// ExampleEncoder is the example function on how to use an encoder
func ExampleEncoder() {
b := bytes.NewBuffer(nil)
encoder := xml.NewEncoder(b)
// expected encoded xml document is :
// `abc123`
defer log.Printf("Encoded xml document: %v", encoder.String())
r := encoder.RootElement(root)
defer r.Close()
// Object key `liststr`
liststr := xml.StartElement{Name: xml.Name{Local: "liststr"}}
namedMember := xml.StartElement{Name: xml.Name{Local: "namedMember"}}
// member element
m := r.MemberElement(liststr)
defer m.Close()
// Build array
a := m.ArrayWithCustomName(namedMember)
value := xml.StartElement{Name: xml.Name{Local: "value"}}
m1 := a.Member()
m1.MemberElement(value).String("abc")
m1.Close()
m2 := a.Member()
m2.MemberElement(value).Integer(123)
m2.Close()
}