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

Tiny fixes #331

Merged
merged 5 commits into from
Oct 27, 2024
Merged
Changes from 1 commit
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
Next Next commit
do not skip fields in composite if keepzero is set
alovak committed Oct 25, 2024
commit 938552fc1e10e8d9094a03f544d4c57fb044527e
20 changes: 13 additions & 7 deletions field/composite.go
Original file line number Diff line number Diff line change
@@ -234,17 +234,23 @@ func (f *Composite) Marshal(v interface{}) error {
defer f.mu.Unlock()

rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New("data is not a pointer or nil")
if rv.Kind() != reflect.Ptr {
return errors.New("data is not a pointer")
}

// get the struct from the pointer
dataStruct := rv.Elem()
elemType := rv.Type().Elem()
if elemType.Kind() != reflect.Struct {
return errors.New("data must be a pointer to struct")
}

if dataStruct.Kind() != reflect.Struct {
return errors.New("data is not a struct")
// If nil, create a new instance of the struct
if rv.IsNil() {
rv = reflect.New(elemType)
}

// get the struct from the pointer
dataStruct := rv.Elem()

// iterate over struct fields
for i := 0; i < dataStruct.NumField(); i++ {
indexTag := NewIndexTag(dataStruct.Type().Field(i))
@@ -258,7 +264,7 @@ func (f *Composite) Marshal(v interface{}) error {
}

dataField := dataStruct.Field(i)
if dataField.IsZero() {
if dataField.IsZero() && !indexTag.KeepZero {
continue
}

15 changes: 14 additions & 1 deletion field/composite_test.go
Original file line number Diff line number Diff line change
@@ -351,10 +351,23 @@ type SubConstructedTLVTestData struct {
}

func TestCompositeField_Marshal(t *testing.T) {
t.Run("Marshal returns error on nil value", func(t *testing.T) {
composite := NewComposite(compositeTestSpec)
err := composite.Marshal(nil)
require.EqualError(t, err, "data is not a pointer")
})

t.Run("Marshal doesn't return an error when nil pointer is of struct type", func(t *testing.T) {
composite := NewComposite(compositeTestSpec)
var data *CompositeTestData
err := composite.Marshal(data)
require.NoError(t, err)
})

t.Run("Marshal returns an error on provision of primitive type data", func(t *testing.T) {
composite := NewComposite(compositeTestSpec)
err := composite.Marshal("primitive str")
require.EqualError(t, err, "data is not a pointer or nil")
require.EqualError(t, err, "data is not a pointer")
})

t.Run("Marshal skips fields without index tag", func(t *testing.T) {
86 changes: 86 additions & 0 deletions message_test.go
Original file line number Diff line number Diff line change
@@ -367,6 +367,73 @@ func TestMessage(t *testing.T) {
wantMsg := []byte("01007000000000000000164242424242424242123456000000000100")
require.Equal(t, wantMsg, rawMsg)
})

t.Run("Clone and reset fields", func(t *testing.T) {
type TestISOF3Data struct {
F1 *field.String
F2 *field.String
F3 *field.String
}

type ISO87Data struct {
F0 *field.String
F2 *field.String
F3 *TestISOF3Data
F4 *field.String
}

message := NewMessage(spec)
err := message.Marshal(&ISO87Data{
F0: field.NewStringValue("0100"),
F2: field.NewStringValue("4242424242424242"),
F3: &TestISOF3Data{
F1: field.NewStringValue("12"),
F2: field.NewStringValue("34"),
F3: field.NewStringValue("56"),
},
F4: field.NewStringValue("100"),
})
require.NoError(t, err)

// clone the message and reset some fields
clone, err := message.Clone()
require.NoError(t, err)

// reset the fields
// first, check that the fields are set
data := &ISO87Data{}
require.NoError(t, clone.Unmarshal(data))

require.Equal(t, "0100", data.F0.Value())
require.Equal(t, "4242424242424242", data.F2.Value())
require.Equal(t, "12", data.F3.F1.Value())
require.Equal(t, "34", data.F3.F2.Value())
require.Equal(t, "56", data.F3.F3.Value())
require.Equal(t, "100", data.F4.Value())

// reset the fields
err = clone.Marshal(&struct {
F2 *string `iso8583:"2,keepzero"`
F3 *struct {
F2 *string `iso8583:"2,keepzero"`
} `iso8583:"3,keepzero"`
}{})
require.NoError(t, err)

// check that the fields are reset
data = &ISO87Data{}
require.NoError(t, clone.Unmarshal(data))

require.Equal(t, "", data.F2.Value())
require.Equal(t, "", data.F3.F2.Value())

// check the reset fields in the message
require.Equal(t, "0100", data.F0.Value())
require.Equal(t, "12", data.F3.F1.Value())
require.Equal(t, "56", data.F3.F3.Value())
require.Equal(t, "100", data.F4.Value())
})

}

func TestPackUnpack(t *testing.T) {
@@ -1680,6 +1747,25 @@ func TestMessageClone(t *testing.T) {
require.Equal(t, message2Data.F55.F9A.Value(), message3Data.F55.F9A.Value())
require.Equal(t, message2Data.F55.F9F02.Value(), message3Data.F55.F9F02.Value())
require.Equal(t, message2Data.F120.Value(), message3Data.F120.Value())

// here is the way how to reset fields
response, err := message3.Clone()
// handle error

err = response.Marshal(&struct {
PAN *string `iso8583:"2,keepzero"`
F55 *struct {
F9A *string `iso8583:",keepzero"`
} `iso8583:",keepzero"`
}{})

responseData := &TestISOData{}
require.NoError(t, response.Unmarshal(responseData))

// check if the PAN is reset
require.Equal(t, "", responseData.F2.Value())
// check if the F55.F9A is reset
require.Equal(t, "210720", responseData.F55.F9A.Value())
}

func TestMessageMarshaling(t *testing.T) {