diff --git a/float64_test.go b/float64_test.go index a9ce53c..14e5f9e 100644 --- a/float64_test.go +++ b/float64_test.go @@ -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(), ``}, - {float64NullValue, NewFloat64Ptr(0.0), `0`, NewFloat64Ptr(0.0), `0`, NewFloat64Ptr(0.0), `0`}, - {float64NullValue, NewFloat64Ptr(1.12), `1.12`, NewFloat64Ptr(1.12), `1.12`, NewFloat64Ptr(1.12), `1.12`}, + // null values + {testTypeJson, float64NullValue, float64NullValue(), `null`}, + {testTypeText, float64NullValue, float64NullValue(), ``}, + {testTypeXml, float64NullValue, float64NullValue(), ``}, + { + testTypeXml, + newFloat64NullValueXmlWrapper, + newFloat64NullValueXmlWrapper(), + ``, + }, + // 0.0 values + {testTypeJson, float64NullValue, NewFloat64Ptr(0.0), `0`}, + {testTypeText, float64NullValue, NewFloat64Ptr(0.0), `0`}, + {testTypeXml, float64NullValue, NewFloat64Ptr(0.0), `0`}, + { + testTypeXml, + newFloat64NullValueXmlWrapper, + newFloat64ValueXmlWrapper(NewFloat64Ptr(0.0)), + `0`, + }, + // 1.12 values + {testTypeJson, float64NullValue, NewFloat64Ptr(1.12), `1.12`}, + {testTypeText, float64NullValue, NewFloat64Ptr(1.12), `1.12`}, + {testTypeXml, float64NullValue, NewFloat64Ptr(1.12), `1.12`}, + { + testTypeXml, + newFloat64NullValueXmlWrapper, + newFloat64ValueXmlWrapper(NewFloat64Ptr(1.12)), + `1.12`, + }, } nullTestRun(t, tests) diff --git a/int64_test.go b/int64_test.go index 704a9ac..22d2009 100644 --- a/int64_test.go +++ b/int64_test.go @@ -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(), ``}, - {int64NullValue, NewInt64Ptr(0), `0`, NewInt64Ptr(0), `0`, NewInt64Ptr(0), `0`}, - {int64NullValue, NewInt64Ptr(1), `1`, NewInt64Ptr(1), `1`, NewInt64Ptr(1), `1`}, + // null values + {testTypeJson, int64NullValue, int64NullValue(), `null`}, + {testTypeText, int64NullValue, int64NullValue(), ``}, + {testTypeXml, int64NullValue, int64NullValue(), ``}, + { + testTypeXml, + newInt64NullValueXmlWrapper, + newInt64NullValueXmlWrapper(), + ``, + }, + // 0 values + {testTypeJson, int64NullValue, NewInt64Ptr(0), `0`}, + {testTypeText, int64NullValue, NewInt64Ptr(0), `0`}, + {testTypeXml, int64NullValue, NewInt64Ptr(0), `0`}, + { + testTypeXml, + newInt64NullValueXmlWrapper, + newInt64ValueXmlWrapper(NewInt64Ptr(0)), + `0`, + }, + // 1 values + {testTypeJson, int64NullValue, NewInt64Ptr(1), `1`}, + {testTypeText, int64NullValue, NewInt64Ptr(1), `1`}, + {testTypeXml, int64NullValue, NewInt64Ptr(1), `1`}, + { + testTypeXml, + newInt64NullValueXmlWrapper, + newInt64ValueXmlWrapper(NewInt64Ptr(1)), + `1`, + }, } nullTestRun(t, tests) diff --git a/null.go b/null.go index 58ad980..80f3230 100644 --- a/null.go +++ b/null.go @@ -4,7 +4,10 @@ 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"}, @@ -12,5 +15,6 @@ var xsiNilAttr = xml.Attr{ } 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" } diff --git a/null_test.go b/null_test.go index faa81fd..4dc509c 100644 --- a/null_test.go +++ b/null_test.go @@ -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 @@ -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) + } } } diff --git a/string_test.go b/string_test.go index df1e288..dfc0ce7 100644 --- a/string_test.go +++ b/string_test.go @@ -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(), ``}, - {stringNullValue, NewStringPtr(``), `""`, NewStringPtr(``), ``, NewStringPtr(``), ``}, - {stringNullValue, NewStringPtr(`foo`), `"foo"`, NewStringPtr(`foo`), `foo`, NewStringPtr(`foo`), `foo`}, + // null values + {testTypeJson, stringNullValue, stringNullValue(), `null`}, + {testTypeText, stringNullValue, NewStringPtr(``), ``}, + {testTypeXml, stringNullValue, stringNullValue(), ``}, + { + testTypeXml, + newStringNullValueXmlWrapper, + newStringNullValueXmlWrapper(), + ``, + }, + // `` values + {testTypeJson, stringNullValue, NewStringPtr(``), `""`}, + {testTypeText, stringNullValue, NewStringPtr(``), ``}, + {testTypeXml, stringNullValue, NewStringPtr(``), ``}, + { + testTypeXml, + newStringNullValueXmlWrapper, + newStringValueXmlWrapper(NewStringPtr(``)), + ``, + }, + // `foo` values + {testTypeJson, stringNullValue, NewStringPtr(`foo`), `"foo"`}, + {testTypeText, stringNullValue, NewStringPtr(`foo`), `foo`}, + {testTypeXml, stringNullValue, NewStringPtr(`foo`), `foo`}, + { + testTypeXml, + newStringNullValueXmlWrapper, + newStringValueXmlWrapper(NewStringPtr(`foo`)), + `foo`, + }, } nullTestRun(t, tests)