Skip to content

Commit

Permalink
code refactoring, fix error when using keepzero index
Browse files Browse the repository at this point in the history
  • Loading branch information
mfdeveloper508 committed Oct 6, 2023
1 parent ebbe759 commit 233b589
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 66 deletions.
205 changes: 151 additions & 54 deletions exp_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
package iso8583_test
package iso8583

import (
"reflect"
"testing"

"github.com/moov-io/iso8583"
"github.com/moov-io/iso8583/encoding"
"github.com/moov-io/iso8583/field"
"github.com/moov-io/iso8583/specs"
"github.com/moov-io/iso8583/padding"
"github.com/moov-io/iso8583/prefix"
"github.com/stretchr/testify/require"
)

func TestStructWithTypes(t *testing.T) {
func TestStructWithStringType(t *testing.T) {
spec := &MessageSpec{
Fields: map[int]field.Field{
0: field.NewString(&field.Spec{
Length: 4,
Description: "Message Type Indicator",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
}),
1: field.NewBitmap(&field.Spec{
Length: 16,
Description: "Bitmap",
Enc: encoding.BytesToASCIIHex,
Pref: prefix.Hex.Fixed,
}),
2: field.NewString(&field.Spec{
Length: 19,
Description: "Primary Account Number",
Enc: encoding.ASCII,
Pref: prefix.ASCII.LL,
}),
3: field.NewNumeric(&field.Spec{
Length: 6,
Description: "Processing Code",
Enc: encoding.ASCII,
Pref: prefix.ASCII.Fixed,
Pad: padding.Left('0'),
}),
},
}

t.Run("pack", func(t *testing.T) {
panInt := 4242424242424242
panStr := "4242424242424242"
Expand Down Expand Up @@ -82,7 +114,7 @@ func TestStructWithTypes(t *testing.T) {
}{
MTI: "0110",
},
expectedPackedString: "011000000000000000000000000000000000",
expectedPackedString: "01104000000000000000000000000000000000",
},

// Tests for int type
Expand Down Expand Up @@ -148,13 +180,13 @@ func TestStructWithTypes(t *testing.T) {
}{
MTI: "0110",
},
expectedPackedString: "011000000000000000000000000000000000",
expectedPackedString: "011040000000000000000000000000000000010",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
message := iso8583.NewMessage(specs.Spec87ASCII)
message := NewMessage(spec)
err := message.Marshal(tt.input)
require.NoError(t, err)

Expand All @@ -167,62 +199,127 @@ func TestStructWithTypes(t *testing.T) {
})

t.Run("unpack", func(t *testing.T) {
type authRequest struct {
MTI string `index:"0"`
PrimaryAccountNumber string `index:"2"`
}

packed := []byte("011040000000000000000000000000000000164242424242424242")
tests := []struct {
name string
input any
}{
// Tests for string type
{
name: "struct with string type and value set",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber string `index:"2"`
}{},
},
{
name: "struct with string type and no value",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber string `index:"2"`
}{},
},
{
name: "struct with string type, no value and keepzero tag - length prefix is set to 0 and no value is following",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber string `index:"2,keepzero"`
}{},
},

message := iso8583.NewMessage(specs.Spec87ASCII)
err := message.Unpack(packed)
require.NoError(t, err)
// Tests for *string type
{
name: "struct with *string type and value set",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *string `index:"2"`
}{},
},
{
name: "struct with *string type and no value",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *string `index:"2"`
}{},
},
{
name: "struct with *string type, no value and keepzero tag",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *string `index:"2,keepzero"`
}{},
},

data := authRequest{}
err = message.Unmarshal(&data)
require.NoError(t, err)
require.Equal(t, "0110", data.MTI)
require.Equal(t, "4242424242424242", data.PrimaryAccountNumber)
})
// Tests for int type
{
name: "struct with int type and value set",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber int `index:"2"`
}{},
},
{
name: "struct with int type and no value",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber int `index:"2"`
}{},
},
{
name: "struct with int type, no value and keepzero tag",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber int `index:"2,keepzero"`
}{},
},

t.Run("unpack2", func(t *testing.T) {
type authRequest struct {
MTI *string `index:"0"`
PrimaryAccountNumber *field.String `index:"2"`
// Tests for *int type
{
name: "struct with *int type and value set",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *int `index:"2"`
}{},
},
{
name: "struct with *int type and no value",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *int `index:"2"`
}{},
},
{
name: "struct with *int type, no value and keepzero tag",
input: &struct {
MTI string `index:"0"`
PrimaryAccountNumber *int `index:"2,keepzero"`
}{},
},
}

packed := []byte("011040000000000000000000000000000000164242424242424242")

message := iso8583.NewMessage(specs.Spec87ASCII)
err := message.Unpack(packed)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
message := NewMessage(spec)
err := message.Unpack(packed)

Check failure on line 303 in exp_test.go

View workflow job for this annotation

GitHub Actions / Go Build (ubuntu-latest, stable)

ineffectual assignment to err (ineffassign)

Check failure on line 303 in exp_test.go

View workflow job for this annotation

GitHub Actions / Go Build (ubuntu-latest, oldstable)

ineffectual assignment to err (ineffassign)

data := authRequest{}
err = message.Unmarshal(&data)
require.NoError(t, err)
require.Equal(t, "0110", *data.MTI)
require.Equal(t, "4242424242424242", data.PrimaryAccountNumber.Value())
})
err = message.Unmarshal(tt.input)
require.NoError(t, err)

t.Run("zero value using keepzero tag", func(t *testing.T) {
type DataWithoutKeepZero struct {
ProcessingCode int `index:"2"` // field.String in the spec
}
val := reflect.Indirect(reflect.ValueOf(tt.input))
require.Equal(t, "0110", val.Field(0).String())

type DataWithKeepZero struct {
ProcessingCode int `index:"2,keepzero"` // field.String in the spec
tStr := val.Field(1).Type().String()
switch tStr {
case "int":
require.Equal(t, int64(4242424242424242), val.Field(1).Int())
case "*int":
require.Equal(t, int64(4242424242424242), val.Field(1).Elem().Int())
case "string":
require.Equal(t, "4242424242424242", val.Field(1).String())
case "*string":
require.Equal(t, "4242424242424242", val.Field(1).Elem().String())
}
})
}

message := iso8583.NewMessage(specs.Spec87ASCII)

message.Marshal(&DataWithoutKeepZero{})
s, err := message.GetField(2).String()
require.NoError(t, err)
require.Equal(t, "", s)

message.Marshal(&DataWithKeepZero{})
s, err = message.GetField(2).String()
require.NoError(t, err)
require.Equal(t, "0", s)
})
}
2 changes: 1 addition & 1 deletion field/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func (f *Composite) Unmarshal(v interface{}) error {

dataField := dataStruct.Field(i)
switch dataField.Kind() { //nolint:exhaustive
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
case reflect.Pointer, reflect.Interface, reflect.Slice:
if dataField.IsNil() {
dataField.Set(reflect.New(dataField.Type().Elem()))
}
Expand Down
28 changes: 26 additions & 2 deletions field/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"strconv"
"strings"

"github.com/moov-io/iso8583/utils"
)
Expand Down Expand Up @@ -143,6 +144,12 @@ func (f *String) Unmarshal(v interface{}) error {
return fmt.Errorf("failed to convert string to int: %w", err)
}
*val = i
case *int64:
i, err := strconv.ParseInt(f.value, 10, 64)
if err != nil {
return fmt.Errorf("failed to convert string to int64: %w", err)
}
*val = i
case *String:
val.value = f.value
default:
Expand All @@ -153,9 +160,14 @@ func (f *String) Unmarshal(v interface{}) error {
}

func (f *String) Marshal(v interface{}) error {
if v == nil || (!reflect.ValueOf(v).CanInt() && reflect.ValueOf(v).IsZero()) {
if v == nil {
f.value = ""
return nil
} else if reflect.ValueOf(v).IsZero() {
if !strings.Contains(reflect.ValueOf(v).Type().String(), "int") {
f.value = ""
return nil
}
}

switch v := v.(type) {
Expand All @@ -167,8 +179,20 @@ func (f *String) Marshal(v interface{}) error {
f.value = *v
case int:
f.value = strconv.FormatInt(int64(v), 10)
case int64:
f.value = strconv.FormatInt(v, 10)
case *int:
f.value = strconv.FormatInt(int64(*v), 10)
if v == nil {
f.value = strconv.FormatInt(0, 10)
} else {
f.value = strconv.FormatInt(int64(*v), 10)
}
case *int64:
if v == nil {
f.value = strconv.FormatInt(0, 10)
} else {
f.value = strconv.FormatInt(*v, 10)
}
default:
return fmt.Errorf("data does not match required *String or (string, *string, int, *int) type")
}
Expand Down
11 changes: 2 additions & 9 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,13 +441,6 @@ func (m *Message) Marshal(v interface{}) error {
}

dataField := dataStruct.Field(i)
// for pointer fields we need to check if they are nil
// and if they are we need to skip them, to not set bitmap bit
// and not to set value to the field
if dataField.Kind() == reflect.Pointer && dataField.IsZero() {
continue
}

// for non pointer fields we need to check if they are zero
// and we want to skip them (as specified in the field tag)
if dataField.IsZero() && !indexTag.KeepZero {
Expand Down Expand Up @@ -503,8 +496,8 @@ func (m *Message) Unmarshal(v interface{}) error {

dataField := dataStruct.Field(i)
switch dataField.Kind() { //nolint:exhaustive
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice:
if dataField.IsNil() || dataField.IsZero() {
case reflect.Pointer, reflect.Interface, reflect.Slice:
if dataField.IsNil() {
dataField.Set(reflect.New(dataField.Type().Elem()))
}
err := messageField.Unmarshal(dataField.Interface())
Expand Down

0 comments on commit 233b589

Please sign in to comment.