Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added XML support for NullDecimal #192

Merged
merged 1 commit into from Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 27 additions & 0 deletions decimal.go
Expand Up @@ -1381,6 +1381,33 @@ func (d NullDecimal) MarshalJSON() ([]byte, error) {
return d.Decimal.MarshalJSON()
}

// UnmarshalText implements the encoding.TextUnmarshaler interface for XML
// deserialization
func (d *NullDecimal) UnmarshalText(text []byte) error {
str := string(text)

// check for empty XML or XML without body e.g., <tag></tag>
if str == "" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is basically the case for empty XMLs and XMLs withotu the body e.g <test></test>?
Could you add a short comment that would denote that, so it will be easier to refactor in the future if needed? :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

d.Valid = false
return nil
}
Comment on lines +1390 to +1393
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this case necessary? Wouldn't the below if statement be enough?

Copy link
Contributor Author

@bharath23 bharath23 Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decimal.Unmarshal returns error. For NullDecimal it is not an error as NullDecimal.Valid will be set to false.

https://play.golang.org/p/YJWM2pykj75

Also, we cannot assume that if its an errors its null. There could be other reasons why Decimal.Unmarshal could fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is similar to how NullDecimal.UnmarshalJSON works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, got it :3 Thanks!
I will get back to your PR tomorrow if you don't mind :) I would love to check the unit test too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any updates?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm so sorry :<. I completely forgot about your pull request Bharath. I'm leaving in about an hour for holiday dinner with family, but I will check those unit test tomorrow.
I'm adding this to my TODO list, so I will not forget about it :D

if err := d.Decimal.UnmarshalText(text); err != nil {
d.Valid = false
return err
}
d.Valid = true
return nil
}

// MarshalText implements the encoding.TextMarshaler interface for XML
// serialization.
func (d NullDecimal) MarshalText() (text []byte, err error) {
if !d.Valid {
return []byte{}, nil
}
return d.Decimal.MarshalText()
}

// Trig functions

// Atan returns the arctangent, in radians, of x.
Expand Down
90 changes: 90 additions & 0 deletions decimal_test.go
Expand Up @@ -766,6 +766,96 @@ func TestBadXML(t *testing.T) {
}
}

func TestNullDecimalXML(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you've based those unit test on NullDecimal JSON tests and there is 3 uni test combined into one. It's not a bad thing in my opinion, but could you separate them by adding a one-liner comment before each section? So next contributors would know what test cases are covered here :3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments.

// test valid values
for _, x := range testTable {
s := x.short
var doc struct {
XMLName xml.Name `xml:"account"`
Amount NullDecimal `xml:"amount"`
}
docStr := `<account><amount>` + s + `</amount></account>`
err := xml.Unmarshal([]byte(docStr), &doc)
if err != nil {
t.Errorf("error unmarshaling %s: %v", docStr, err)
} else if doc.Amount.Decimal.String() != s {
t.Errorf("expected %s, got %s (%s, %d)",
s, doc.Amount.Decimal.String(),
doc.Amount.Decimal.value.String(), doc.Amount.Decimal.exp)
}

out, err := xml.Marshal(&doc)
if err != nil {
t.Errorf("error marshaling %+v: %v", doc, err)
} else if string(out) != docStr {
t.Errorf("expected %s, got %s", docStr, string(out))
}
}

var doc struct {
XMLName xml.Name `xml:"account"`
Amount NullDecimal `xml:"amount"`
}

// test for XML with empty body
docStr := `<account><amount></amount></account>`
err := xml.Unmarshal([]byte(docStr), &doc)
if err != nil {
t.Errorf("error unmarshaling: %s: %v", docStr, err)
} else if doc.Amount.Valid {
t.Errorf("expected null value to have Valid = false, got Valid = true and Decimal = %s (%s, %d)",
doc.Amount.Decimal.String(),
doc.Amount.Decimal.value.String(), doc.Amount.Decimal.exp)
}

expected := `<account><amount></amount></account>`
out, err := xml.Marshal(&doc)
if err != nil {
t.Errorf("error marshaling %+v: %v", doc, err)
} else if string(out) != expected {
t.Errorf("expected %s, got %s", expected, string(out))
}

// test for empty XML
docStr = `<account></account>`
err = xml.Unmarshal([]byte(docStr), &doc)
if err != nil {
t.Errorf("error unmarshaling: %s: %v", docStr, err)
} else if doc.Amount.Valid {
t.Errorf("expected null value to have Valid = false, got Valid = true and Decimal = %s (%s, %d)",
doc.Amount.Decimal.String(),
doc.Amount.Decimal.value.String(), doc.Amount.Decimal.exp)
}

expected = `<account><amount></amount></account>`
out, err = xml.Marshal(&doc)
if err != nil {
t.Errorf("error marshaling %+v: %v", doc, err)
} else if string(out) != expected {
t.Errorf("expected %s, got %s", expected, string(out))
}
}

func TestNullDecimalBadXML(t *testing.T) {
for _, testCase := range []string{
"o_o",
"<abc",
"<account><amount>7",
`<html><body></body></html>`,
`<account><amount>nope</amount></account>`,
`0.333`,
} {
var doc struct {
XMLName xml.Name `xml:"account"`
Amount NullDecimal `xml:"amount"`
}
err := xml.Unmarshal([]byte(testCase), &doc)
if err == nil {
t.Errorf("expected error, got %+v", doc)
}
}
}

func TestDecimal_rescale(t *testing.T) {
type Inp struct {
int int64
Expand Down