Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions float64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,50 @@ import (
"testing"
)

func float64NullValue() nullTestValue {
func float64NullValue() interface{} {
return &Float64{}
}

func newFloat64NullValueXmlWrapper() interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: float64NullValue()}
}

func newFloat64ValueXmlWrapper(value *Float64) interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: value}
}

func TestFloat64(t *testing.T) {
tests := []nullTest{
{float64NullValue, float64NullValue(), `null`, float64NullValue(), ``, float64NullValue(), `<Float64 xsi:nil="true"></Float64>`},
{float64NullValue, NewFloat64Ptr(0.0), `0`, NewFloat64Ptr(0.0), `0`, NewFloat64Ptr(0.0), `<Float64>0</Float64>`},
{float64NullValue, NewFloat64Ptr(1.12), `1.12`, NewFloat64Ptr(1.12), `1.12`, NewFloat64Ptr(1.12), `<Float64>1.12</Float64>`},
// null values
{testTypeJson, float64NullValue, float64NullValue(), `null`},
{testTypeText, float64NullValue, float64NullValue(), ``},
{testTypeXml, float64NullValue, float64NullValue(), `<Float64 xsi:nil="true"></Float64>`},
{
testTypeXml,
newFloat64NullValueXmlWrapper,
newFloat64NullValueXmlWrapper(),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:nil="true"></Value></nullTestValueXmlWrapper>`,
},
// 0.0 values
{testTypeJson, float64NullValue, NewFloat64Ptr(0.0), `0`},
{testTypeText, float64NullValue, NewFloat64Ptr(0.0), `0`},
{testTypeXml, float64NullValue, NewFloat64Ptr(0.0), `<Float64>0</Float64>`},
{
testTypeXml,
newFloat64NullValueXmlWrapper,
newFloat64ValueXmlWrapper(NewFloat64Ptr(0.0)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value>0</Value></nullTestValueXmlWrapper>`,
},
// 1.12 values
{testTypeJson, float64NullValue, NewFloat64Ptr(1.12), `1.12`},
{testTypeText, float64NullValue, NewFloat64Ptr(1.12), `1.12`},
{testTypeXml, float64NullValue, NewFloat64Ptr(1.12), `<Float64>1.12</Float64>`},
{
testTypeXml,
newFloat64NullValueXmlWrapper,
newFloat64ValueXmlWrapper(NewFloat64Ptr(1.12)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value>1.12</Value></nullTestValueXmlWrapper>`,
},
}

nullTestRun(t, tests)
Expand Down
47 changes: 40 additions & 7 deletions int64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,52 @@

package null

import (
"testing"
)
import "testing"

func int64NullValue() nullTestValue {
func int64NullValue() interface{} {
return &Int64{}
}

func newInt64NullValueXmlWrapper() interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: int64NullValue()}
}

func newInt64ValueXmlWrapper(value *Int64) interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: value}
}

func TestInt64(t *testing.T) {
tests := []nullTest{
{int64NullValue, int64NullValue(), `null`, int64NullValue(), ``, int64NullValue(), `<Int64 xsi:nil="true"></Int64>`},
{int64NullValue, NewInt64Ptr(0), `0`, NewInt64Ptr(0), `0`, NewInt64Ptr(0), `<Int64>0</Int64>`},
{int64NullValue, NewInt64Ptr(1), `1`, NewInt64Ptr(1), `1`, NewInt64Ptr(1), `<Int64>1</Int64>`},
// null values
{testTypeJson, int64NullValue, int64NullValue(), `null`},
{testTypeText, int64NullValue, int64NullValue(), ``},
{testTypeXml, int64NullValue, int64NullValue(), `<Int64 xsi:nil="true"></Int64>`},
{
testTypeXml,
newInt64NullValueXmlWrapper,
newInt64NullValueXmlWrapper(),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:nil="true"></Value></nullTestValueXmlWrapper>`,
},
// 0 values
{testTypeJson, int64NullValue, NewInt64Ptr(0), `0`},
{testTypeText, int64NullValue, NewInt64Ptr(0), `0`},
{testTypeXml, int64NullValue, NewInt64Ptr(0), `<Int64>0</Int64>`},
{
testTypeXml,
newInt64NullValueXmlWrapper,
newInt64ValueXmlWrapper(NewInt64Ptr(0)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value>0</Value></nullTestValueXmlWrapper>`,
},
// 1 values
{testTypeJson, int64NullValue, NewInt64Ptr(1), `1`},
{testTypeText, int64NullValue, NewInt64Ptr(1), `1`},
{testTypeXml, int64NullValue, NewInt64Ptr(1), `<Int64>1</Int64>`},
{
testTypeXml,
newInt64NullValueXmlWrapper,
newInt64ValueXmlWrapper(NewInt64Ptr(1)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value>1</Value></nullTestValueXmlWrapper>`,
},
}

nullTestRun(t, tests)
Expand Down
8 changes: 6 additions & 2 deletions null.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ package null

import "encoding/xml"

const jsonNull = "null"
const (
jsonNull = "null"
xsiNamespace = "http://www.w3.org/2001/XMLSchema-instance"
)

var xsiNilAttr = xml.Attr{
Name: xml.Name{Local: "xsi:nil"},
Value: "true",
}

func isXsiNilAttr(attr xml.Attr) bool {
return attr.Name.Space == "xsi" && attr.Name.Local == "nil" && attr.Value == "true"
return (attr.Name.Space == "xsi" || attr.Name.Space == xsiNamespace) &&
attr.Name.Local == "nil" && attr.Value == "true"
}
100 changes: 63 additions & 37 deletions null_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import (
"testing"
)

const (
testTypeJson testType = "json"
testTypeText testType = "text"
testTypeXml testType = "xml"
)

type testType string

type nullTestValue interface {
json.Marshaler
json.Unmarshaler
Expand All @@ -19,86 +27,104 @@ type nullTestValue interface {
xml.Unmarshaler
}

type nullTestValueXmlWrapper struct {
Namespace string `xml:"xmlns:xsi,attr"`
Value interface{} `xml:"Value"` // *nullTestValue
}

type nullTest struct {
new func() nullTestValue
jsonValue nullTestValue
json string
textValue nullTestValue
text string
xmlValue nullTestValue
xml string
Type testType
New func() interface{} // Generator of *nullTestValue (and their wrappers)
Unmarshaled interface{}
Marshaled string
}

func nullTestMarshalJSON(t *testing.T, tt nullTest) {
got, err := json.Marshal(tt.jsonValue)
got, err := json.Marshal(tt.Unmarshaled)
if err != nil {
t.Error(err)
}
if string(got) != tt.json {
t.Errorf("got %s; expected %s", got, tt.json)
if string(got) != tt.Marshaled {
t.Errorf("got %s; expected %s", got, tt.Marshaled)
}
}

func nullTestUnmarshalJSON(t *testing.T, tt nullTest) {
got := tt.new()
if err := json.Unmarshal([]byte(tt.json), got); err != nil {
got := tt.New()
if err := json.Unmarshal([]byte(tt.Marshaled), got); err != nil {
t.Error(err)
}
if !reflect.DeepEqual(got, tt.jsonValue) {
t.Errorf("got %v; expected %v", got, tt.jsonValue)
if !reflect.DeepEqual(got, tt.Unmarshaled) {
t.Errorf("got %v; expected %v", got, tt.Unmarshaled)
}
}

func nullTestMarshalText(t *testing.T, tt nullTest) {
got, err := tt.textValue.MarshalText()
got, err := tt.Unmarshaled.(nullTestValue).MarshalText()
if err != nil {
t.Error(err)
}
if string(got) != tt.text {
t.Errorf("got %s; expected %s", got, tt.text)
if string(got) != tt.Marshaled {
t.Errorf("got %s; expected %s", got, tt.Marshaled)
}
}

func nullTestUnmarshalText(t *testing.T, tt nullTest) {
got := tt.new()
if err := got.UnmarshalText([]byte(tt.text)); err != nil {
got := tt.New().(nullTestValue)
if err := got.UnmarshalText([]byte(tt.Marshaled)); err != nil {
t.Error(err)
}
if !reflect.DeepEqual(got, tt.textValue) {
t.Errorf("got %v; expected %v", got, tt.textValue)
if !reflect.DeepEqual(got, tt.Unmarshaled) {
t.Errorf("got %v; expected %v", got, tt.Unmarshaled)
}
}

func nullTestMarshalXML(t *testing.T, tt nullTest) {
got, err := xml.Marshal(tt.xmlValue)
got, err := xml.Marshal(tt.Unmarshaled)
if err != nil {
t.Error(err)
}
if string(got) != tt.xml {
t.Errorf("got %s; expected %s", got, tt.xml)
if string(got) != tt.Marshaled {
t.Errorf("got %s; expected %s", got, tt.Marshaled)
}
}

func nullTestUnmarshalXML(t *testing.T, tt nullTest) {
got := tt.new()
if err := xml.Unmarshal([]byte(tt.xml), got); err != nil {
got := tt.New()
if err := xml.Unmarshal([]byte(tt.Marshaled), got); err != nil {
t.Error(err)
}
if !reflect.DeepEqual(got, tt.xmlValue) {
t.Errorf("got %v; expected %v", got, tt.xmlValue)
if !reflect.DeepEqual(got, tt.Unmarshaled) {
t.Errorf("got %v; expected %v", got, tt.Unmarshaled)
}
}

func nullTestRun(t *testing.T, tests []nullTest) {
for _, tt := range tests {
tt := tt
t.Run("", func(t *testing.T) {
nullTestMarshalJSON(t, tt)
nullTestUnmarshalJSON(t, tt)
nullTestMarshalText(t, tt)
nullTestUnmarshalText(t, tt)
nullTestMarshalXML(t, tt)
nullTestUnmarshalXML(t, tt)
})
switch tt.Type {
case testTypeJson:
t.Run("MarshalJSON", func(t *testing.T) {
nullTestMarshalJSON(t, tt)
})
t.Run("UnmarshalJSON", func(t *testing.T) {
nullTestUnmarshalJSON(t, tt)
})
case testTypeText:
t.Run("MarshalText", func(t *testing.T) {
nullTestMarshalText(t, tt)
})
t.Run("UnmarshalText", func(t *testing.T) {
nullTestUnmarshalText(t, tt)
})
case testTypeXml:
t.Run("MarshalXML", func(t *testing.T) {
nullTestMarshalXML(t, tt)
})
t.Run("UnmarshalXML", func(t *testing.T) {
nullTestUnmarshalXML(t, tt)
})
default:
t.Errorf("Unsupported testType: %#v", tt.Type)
}
}
}
47 changes: 40 additions & 7 deletions string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,52 @@

package null

import (
"testing"
)
import "testing"

func stringNullValue() nullTestValue {
func stringNullValue() interface{} {
return &String{}
}

func newStringNullValueXmlWrapper() interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: stringNullValue()}
}

func newStringValueXmlWrapper(value *String) interface{} {
return &nullTestValueXmlWrapper{Namespace: xsiNamespace, Value: value}
}

func TestString(t *testing.T) {
tests := []nullTest{
{stringNullValue, stringNullValue(), `null`, NewStringPtr(``), ``, stringNullValue(), `<String xsi:nil="true"></String>`},
{stringNullValue, NewStringPtr(``), `""`, NewStringPtr(``), ``, NewStringPtr(``), `<String></String>`},
{stringNullValue, NewStringPtr(`foo`), `"foo"`, NewStringPtr(`foo`), `foo`, NewStringPtr(`foo`), `<String>foo</String>`},
// null values
{testTypeJson, stringNullValue, stringNullValue(), `null`},
{testTypeText, stringNullValue, NewStringPtr(``), ``},
{testTypeXml, stringNullValue, stringNullValue(), `<String xsi:nil="true"></String>`},
{
testTypeXml,
newStringNullValueXmlWrapper,
newStringNullValueXmlWrapper(),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value xsi:nil="true"></Value></nullTestValueXmlWrapper>`,
},
// `` values
{testTypeJson, stringNullValue, NewStringPtr(``), `""`},
{testTypeText, stringNullValue, NewStringPtr(``), ``},
{testTypeXml, stringNullValue, NewStringPtr(``), `<String></String>`},
{
testTypeXml,
newStringNullValueXmlWrapper,
newStringValueXmlWrapper(NewStringPtr(``)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value></Value></nullTestValueXmlWrapper>`,
},
// `foo` values
{testTypeJson, stringNullValue, NewStringPtr(`foo`), `"foo"`},
{testTypeText, stringNullValue, NewStringPtr(`foo`), `foo`},
{testTypeXml, stringNullValue, NewStringPtr(`foo`), `<String>foo</String>`},
{
testTypeXml,
newStringNullValueXmlWrapper,
newStringValueXmlWrapper(NewStringPtr(`foo`)),
`<nullTestValueXmlWrapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Value>foo</Value></nullTestValueXmlWrapper>`,
},
}

nullTestRun(t, tests)
Expand Down