~samwhited/xmpp

67ab7371f4bcb8dda910e6151bf2c82c667cfd7c — Sam Whited 5 years ago fa99f66
Make JIDs satisfy MarshalXML and UnmarshalXML
2 files changed, 107 insertions(+), 5 deletions(-)

M jid/jid.go
M jid/jid_test.go
M jid/jid.go => jid/jid.go +40 -4
@@ 275,8 275,44 @@ func (j *JID) Equal(j2 *JID) bool {
		j.Domainpart() == j2.Domainpart() && j.Resourcepart() == j2.Resourcepart()
}

// MarshalXMLAttr satisfies the MarshalerAttr interface and marshals the JID as
// an XML attribute.
// MarshalXML satisfies the xml.Marshaler interface and marshals the JID as
// XML chardata.
func (j *JID) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
	if err = e.EncodeToken(start); err != nil {
		return
	}
	if err = e.EncodeToken(xml.CharData(j.String())); err != nil {
		return
	}
	if err = e.EncodeToken(start.End()); err != nil {
		return
	}
	err = e.Flush()
	return
}

// UnmarshalXML satisfies the xml.Unmarshaler interface and unmarshals the JID
// from the elements chardata.
func (j *JID) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
	data := struct {
		CharData string `xml:",chardata"`
	}{}
	if err = d.DecodeElement(&data, &start); err != nil {
		return
	}
	j2, err := Parse(data.CharData)

	if err == nil {
		j.localpart = j2.localpart
		j.domainpart = j2.domainpart
		j.resourcepart = j2.resourcepart
	}

	return
}

// MarshalXMLAttr satisfies the xml.MarshalerAttr interface and marshals the JID
// as an XML attribute.
func (j *JID) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	if j == nil {
		return xml.Attr{}, nil


@@ 284,8 320,8 @@ func (j *JID) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
	return xml.Attr{Name: name, Value: j.String()}, nil
}

// UnmarshalXMLAttr satisfies the UnmarshalerAttr interface and unmarshals an
// XML attribute into a valid JID (or returns an error).
// UnmarshalXMLAttr satisfies the xml.UnmarshalerAttr interface and unmarshals
// an XML attribute into a valid JID (or returns an error).
func (j *JID) UnmarshalXMLAttr(attr xml.Attr) error {
	jid, err := Parse(attr.Value)
	j.localpart = jid.localpart

M jid/jid_test.go => jid/jid_test.go +67 -1
@@ 5,6 5,7 @@
package jid

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"net"


@@ 16,6 17,8 @@ import (
var _ fmt.Stringer = (*JID)(nil)
var _ xml.MarshalerAttr = (*JID)(nil)
var _ xml.UnmarshalerAttr = (*JID)(nil)
var _ xml.Marshaler = (*JID)(nil)
var _ xml.Unmarshaler = (*JID)(nil)
var _ net.Addr = (*JID)(nil)

func TestValidJIDs(t *testing.T) {


@@ 90,7 93,7 @@ func TestInvalidNewJIDs(t *testing.T) {
	}
}

func TestMarshalEmpty(t *testing.T) {
func TestMarshalAttrEmpty(t *testing.T) {
	attr, err := ((*JID)(nil)).MarshalXMLAttr(xml.Name{})
	switch {
	case err != nil:


@@ 196,3 199,66 @@ func TestUnescape(t *testing.T) {
		}
	}
}

func TestMarshalXML(t *testing.T) {
	// Test default marshaling
	j := MustParse("feste@shakespeare.lit")
	b, err := xml.Marshal(j)
	switch expected := `<JID>feste@shakespeare.lit</JID>`; {
	case err != nil:
		t.Error(err)
	case string(b) != expected:
		t.Errorf("Error marshaling JID, expected `%s` but got `%s`", expected, string(b))
	}

	// Test encoding with a custom element
	j = MustParse("feste@shakespeare.lit/ilyria")
	var buf bytes.Buffer
	start := xml.StartElement{xml.Name{Space: "", Local: "item"}, []xml.Attr{}}
	e := xml.NewEncoder(&buf)
	err = e.EncodeElement(j, start)
	switch expected := `<item>feste@shakespeare.lit/ilyria</item>`; {
	case err != nil:
		t.Error(err)
	case buf.String() != expected:
		t.Errorf("Error encoding JID, expected `%s` but got `%s`", expected, buf.String())
	}

	// Test encoding a nil JID
	j = (*JID)(nil)
	b, err = xml.Marshal(j)
	switch expected := ``; {
	case err != nil:
		t.Error(err)
	case string(b) != expected:
		t.Errorf("Error marshaling JID, expected `%s` but got `%s`", expected, string(b))
	}
}

func TestUnmarshal(t *testing.T) {
	for _, test := range []struct {
		xml string
		jid *JID
		err bool
	}{
		{`<item>feste@shakespeare.lit/ilyria</item>`, MustParse("feste@shakespeare.lit/ilyria"), false},
		{`<jid>feste@shakespeare.lit</jid>`, MustParse("feste@shakespeare.lit"), false},
		{`<oops>feste@shakespeare.lit</bad>`, nil, true},
		{`<item></item>`, nil, true},
	} {
		j := &JID{}
		err := xml.Unmarshal([]byte(test.xml), j)
		switch {
		case test.err && err == nil:
			t.Errorf("Expected unmarshaling `%s` as a JID to return an error", test.xml)
			continue
		case !test.err && err != nil:
			t.Error(err)
			continue
		case err != nil:
			continue
		case !test.jid.Equal(j):
			t.Errorf("Expected JID to unmarshal to `%s` but got `%s`", test.jid, j)
		}
	}
}