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

Updating unimarshaller #289

Merged
merged 14 commits into from
Oct 5, 2023
95 changes: 70 additions & 25 deletions field/binary.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package field

import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"reflect"

"github.com/moov-io/iso8583/encoding"
"github.com/moov-io/iso8583/utils"
Expand All @@ -16,7 +17,6 @@ var _ json.Unmarshaler = (*Binary)(nil)
type Binary struct {
value []byte
spec *Spec
data *Binary
}

func NewBinary(spec *Spec) *Binary {
Expand All @@ -41,9 +41,6 @@ func (f *Binary) SetSpec(spec *Spec) {

func (f *Binary) SetBytes(b []byte) error {
f.value = b
if f.data != nil {
*(f.data) = *f
}
return nil
}

Expand Down Expand Up @@ -120,34 +117,82 @@ func (f *Binary) SetData(data interface{}) error {
}

func (f *Binary) Unmarshal(v interface{}) error {
if v == nil {
return nil
switch val := v.(type) {
case reflect.Value:
switch val.Kind() { //nolint:exhaustive
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
case reflect.String:
if !val.CanSet() {
return fmt.Errorf("reflect.Value of the data can not be change")
}
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved

str := hex.EncodeToString(f.value)
val.SetString(str)
case reflect.Slice:
if !val.CanSet() {
return fmt.Errorf("reflect.Value of the data can not be change")
}

mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
val.SetBytes(f.value)
default:
return fmt.Errorf("data does not match required reflect.Value type")
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
}
case *string:
str := hex.EncodeToString(f.value)
*val = str
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
case *[]byte:
*val = f.value
case *Binary:
val.value = f.value
default:
return fmt.Errorf("data does not match required *Binary or (*string, *[]byte) type")
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
}

bin, ok := v.(*Binary)
if !ok {
return errors.New("data does not match required *Binary type")
}

bin.value = f.value

return nil
}

func (f *Binary) Marshal(v interface{}) error {
if v == nil {
return nil
}

bin, ok := v.(*Binary)
if !ok {
return errors.New("data does not match required *Binary type")
switch v := v.(type) {
case *Binary:
if v == nil {
return nil
}
f.value = v.value
case string:
if v == "" {
f.value = nil
return nil
}

buf, err := hex.DecodeString(v)
if err != nil {
return fmt.Errorf("failed to convert string to byte: %w", err)
}

f.value = buf
case *string:
if v == nil {
f.value = nil
return nil
}

buf, err := hex.DecodeString(*v)
if err != nil {
return fmt.Errorf("failed to convert string to byte: %w", err)
}

f.value = buf
case []byte:
f.SetBytes(v)
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
case *[]byte:
if v == nil {
f.value = nil
return nil
}
f.SetBytes(*v)
default:
return fmt.Errorf("data does not match required *Binary or (string, *string, []byte, *[]byte) type")
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
}

f.data = bin
if bin.value != nil {
f.value = bin.value
}
return nil
}

Expand Down
75 changes: 73 additions & 2 deletions field/binary_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package field

import (
"reflect"
"testing"

"github.com/moov-io/iso8583/encoding"
Expand Down Expand Up @@ -76,7 +77,7 @@ func TestBinaryField(t *testing.T) {
err := bin.SetBytes(in)
require.NoError(t, err)

require.Equal(t, in, data.value)
require.Equal(t, in, bin.value)
})

// SetValue sets data to the data field
Expand All @@ -96,7 +97,7 @@ func TestBinaryField(t *testing.T) {

require.NoError(t, err)
require.Equal(t, len(in), n)
require.Equal(t, in, data.value)
require.Equal(t, in, bin.value)
})

t.Run("UnmarshalJSON unquotes input before handling it", func(t *testing.T) {
Expand Down Expand Up @@ -140,3 +141,73 @@ func TestBinaryNil(t *testing.T) {
bs = str.Value()
require.Nil(t, bs)
}

func TestBinaryFieldUnmarshal(t *testing.T) {
testValue := []byte{0x12, 0x34, 0x56}
str := NewBinaryValue(testValue)

val1 := &Binary{}
err := str.Unmarshal(val1)
require.NoError(t, err)
require.Equal(t, testValue, val1.Value())

var val2 string
err = str.Unmarshal(&val2)
require.NoError(t, err)
require.Equal(t, "123456", val2)

var val3 []byte
err = str.Unmarshal(&val3)
require.NoError(t, err)
require.Equal(t, testValue, val3)

val4 := reflect.ValueOf(&val2).Elem()
err = str.Unmarshal(val4)
require.NoError(t, err)
require.Equal(t, "123456", val4.String())

val5 := reflect.ValueOf(&val3).Elem()
err = str.Unmarshal(val5)
require.NoError(t, err)
require.Equal(t, testValue, val5.Bytes())

val6 := reflect.ValueOf(val2)
err = str.Unmarshal(val6)
require.Error(t, err)
require.Equal(t, "reflect.Value of the data can not be change", err.Error())

val7 := reflect.ValueOf(&val2)
mfdeveloper508 marked this conversation as resolved.
Show resolved Hide resolved
err = str.Unmarshal(val7)
require.Error(t, err)
require.Equal(t, "data does not match required reflect.Value type", err.Error())

err = str.Unmarshal(nil)
require.Error(t, err)
require.Equal(t, "data does not match required *Binary or (*string, *[]byte) type", err.Error())
}

func TestBinaryFieldMarshal(t *testing.T) {
testValue := []byte{0x12, 0x34, 0x56}
str := NewBinaryValue(nil)

vstring := "123456"
err := str.Marshal(vstring)
require.NoError(t, err)
require.Equal(t, testValue, str.Value())

err = str.Marshal(&vstring)
require.NoError(t, err)
require.Equal(t, testValue, str.Value())

err = str.Marshal(testValue)
require.NoError(t, err)
require.Equal(t, testValue, str.Value())

err = str.Marshal(&testValue)
require.NoError(t, err)
require.Equal(t, testValue, str.Value())

err = str.Marshal(nil)
require.Error(t, err)
require.Equal(t, "data does not match required *Binary or (string, *string, []byte, *[]byte) type", err.Error())
}
4 changes: 2 additions & 2 deletions field/composite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ func TestCompositePacking(t *testing.T) {
})

require.Error(t, err)
require.EqualError(t, err, "failed to set data from field 1: data does not match required *String type")
require.EqualError(t, err, "failed to set data from field 1: data does not match required *String or (string, *string, int, *int) type")
})

t.Run("Pack returns error on failure of subfield packing", func(t *testing.T) {
Expand Down Expand Up @@ -747,7 +747,7 @@ func TestCompositePacking(t *testing.T) {
err = composite.Unmarshal(data)

require.Error(t, err)
require.EqualError(t, err, "failed to get data from field 1: data does not match required *String type")
require.EqualError(t, err, "failed to get data from field 1: data does not match required *String or *string type")
})

t.Run("Unpack returns an error on failure of subfield to unpack bytes", func(t *testing.T) {
Expand Down
85 changes: 60 additions & 25 deletions field/hex.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package field
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"

"github.com/moov-io/iso8583/utils"
Expand All @@ -22,7 +22,6 @@ var _ json.Unmarshaler = (*Hex)(nil)
type Hex struct {
value string
spec *Spec
data *Hex
}

func NewHex(spec *Spec) *Hex {
Expand Down Expand Up @@ -50,9 +49,6 @@ func (f *Hex) SetSpec(spec *Spec) {

func (f *Hex) SetBytes(b []byte) error {
f.value = strings.ToUpper(hex.EncodeToString(b))
if f.data != nil {
*(f.data) = *f
}
return nil
}

Expand Down Expand Up @@ -132,34 +128,73 @@ func (f *Hex) SetData(data interface{}) error {
}

func (f *Hex) Unmarshal(v interface{}) error {
if v == nil {
return nil
}

str, ok := v.(*Hex)
if !ok {
return errors.New("data does not match required *Hex type")
switch val := v.(type) {
case reflect.Value:
switch val.Kind() { //nolint:exhaustive
case reflect.String:
if !val.CanSet() {
return fmt.Errorf("reflect.Value of the data can not be change")
}

str, _ := f.String()
val.SetString(str)
case reflect.Slice:
if !val.CanSet() {
return fmt.Errorf("reflect.Value of the data can not be change")
}

buf, _ := f.Bytes()
val.SetBytes(buf)
default:
return fmt.Errorf("data does not match required reflect.Value type")
}
case *string:
*val, _ = f.String()
case *[]byte:
*val, _ = f.Bytes()
case *Hex:
val.value = f.value
default:
return fmt.Errorf("data does not match required *Hex or (*string, *[]byte) type")
}

str.value = f.value

return nil
}

func (f *Hex) Marshal(v interface{}) error {
if v == nil {
return nil
switch v := v.(type) {
case *Hex:
if v == nil {
return nil
}
f.value = v.value
case string:
if v == "" {
f.value = ""
return nil
}

f.value = v
hex.EncodeToString([]byte(v))
case *string:
if v == nil {
f.value = ""
return nil
}

f.value = *v
case []byte:
f.SetBytes(v)
case *[]byte:
if v == nil {
f.value = ""
return nil
}
f.SetBytes(*v)
default:
return fmt.Errorf("data does not match required *Hex or (string, *string, []byte, *[]byte) type")
}

str, ok := v.(*Hex)
if !ok {
return fmt.Errorf("data does not match required *Hex type")
}

f.data = str
if str.value != "" {
f.value = str.value
}
return nil
}

Expand Down
Loading
Loading