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

Andrei cloud composite spec builder #285

Merged
merged 4 commits into from
Oct 6, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 50 additions & 22 deletions specs/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,31 +114,33 @@ type MessageSpecBuilder interface {
type messageSpecBuilder struct{}

type specDummy struct {
Name string `json:"name,omitempty" xml:"name,omitempty"`
Name string `json:"name,omitempty" xml:"name,omitempty"`
Fields orderedFieldMap `json:"fields,omitempty" xml:"fields,omitempty"`
}

type fieldDummy struct {
Type string `json:"type,omitempty" xml:"type,omitempty"`
Length int `json:"length,omitempty" xml:"length,omitempty"`
Description string `json:"description,omitempty" xml:"description,omitempty"`
Enc string `json:"enc,omitempty" xml:"enc,omitempty"`
Prefix string `json:"prefix,omitempty" xml:"prefix,omitempty"`
Padding *paddingDummy `json:"padding,omitempty" xml:"padding,omitempty"`
Tag *tagDummy `json:"tag,omitempty" xml:"tag,omitempty"`
Subfields map[string]*fieldDummy `json:"subfields,omitempty" xml:"subfields:omitempty"`
Type string `json:"type,omitempty" xml:"type,omitempty"`
Length int `json:"length,omitempty" xml:"length,omitempty"`
Description string `json:"description,omitempty" xml:"description,omitempty"`
Enc string `json:"enc,omitempty" xml:"enc,omitempty"`
Prefix string `json:"prefix,omitempty" xml:"prefix,omitempty"`
Padding *paddingDummy `json:"padding,omitempty" xml:"padding,omitempty"`
Tag *tagDummy `json:"tag,omitempty" xml:"tag,omitempty"`
Subfields map[string]*fieldDummy `json:"subfields,omitempty" xml:"subfields:omitempty"`
Bitmap *fieldDummy `json:"bitmap,omitempty" xml:"bitmap,omitempty"`
DisableAutoExpand bool `json:"disableAutoExpand,omitempty" xml:"disableAutoExpand,omitempty"`
}

type paddingDummy struct {
Type string `json:"type" xml:"type"`
Pad string `json:"pad" xml:"pad"`
Pad string `json:"pad" xml:"pad"`
}

type tagDummy struct {
Length int `json:"length,omitempty" xml:"length,omitempty"`
Enc string `json:"enc,omitempty" xml:"enc,omitempty"`
Length int `json:"length,omitempty" xml:"length,omitempty"`
Enc string `json:"enc,omitempty" xml:"enc,omitempty"`
Padding *paddingDummy `json:"padding,omitempty" xml:"padding,omitempty"`
Sort string `json:"sort,omitempty" xml:"sort,omitempty"`
Sort string `json:"sort,omitempty" xml:"sort,omitempty"`
}

func importField(dummyField *fieldDummy, index string) (*field.Spec, error) {
Expand Down Expand Up @@ -177,17 +179,30 @@ func importField(dummyField *fieldDummy, index string) (*field.Spec, error) {
fieldSpec.Subfields[key] = constructor(subfieldSpec)
}

fieldSpec.Tag = &field.TagSpec{
Length: dummyField.Tag.Length,
if dummyField.Tag != nil {
fieldSpec.Tag = &field.TagSpec{
Length: dummyField.Tag.Length,
}
fieldSpec.Tag.Enc = EncodingsExtToInt[dummyField.Tag.Enc]
if dummyField.Tag.Padding != nil {
if padderConstructor := PaddersExtToInt[dummyField.Tag.Padding.Type]; padderConstructor != nil {
fieldSpec.Tag.Pad = padderConstructor(dummyField.Tag.Padding.Pad)
}
}
fieldSpec.Tag.Sort = SortExtToInt[dummyField.Tag.Sort]
}
fieldSpec.Tag.Enc = EncodingsExtToInt[dummyField.Tag.Enc]
if dummyField.Tag.Padding != nil {
if padderConstructor := PaddersExtToInt[dummyField.Tag.Padding.Type]; padderConstructor != nil {
fieldSpec.Tag.Pad = padderConstructor(dummyField.Tag.Padding.Pad)

if dummyField.Bitmap != nil {
bitmapSpec, err := importField(dummyField.Bitmap, "field bitmap")
if err != nil {
return nil, err
}

fieldSpec.Bitmap = field.NewBitmap(bitmapSpec)
}
fieldSpec.Tag.Sort = SortExtToInt[dummyField.Tag.Sort]

}
fieldSpec.DisableAutoExpand = dummyField.DisableAutoExpand
return fieldSpec, nil
}

Expand Down Expand Up @@ -218,7 +233,11 @@ func (builder *messageSpecBuilder) ImportJSON(raw []byte) (*iso8583.MessageSpec,
}
constructor := FieldConstructor[dummyField.Type]
if constructor == nil {
return nil, fmt.Errorf("no constructor for filed type: %s for field: %d", dummyField.Type, index)
return nil, fmt.Errorf(
"no constructor for filed type: %s for field: %d",
dummyField.Type,
index,
)
}
spec.Fields[index] = constructor(fieldSpec)
}
Expand Down Expand Up @@ -278,7 +297,16 @@ func exportField(internalField field.Field) (*fieldDummy, error) {
}
dummyField.Tag = tag
}

if spec.Bitmap != nil {
bitmap, err := exportField(spec.Bitmap)
if err != nil {
return nil, err
}
dummyField.Bitmap = bitmap
}
}
dummyField.DisableAutoExpand = spec.DisableAutoExpand

return dummyField, nil
}
Expand All @@ -304,7 +332,6 @@ func exportTag(tag *field.TagSpec) (*tagDummy, error) {
dummy.Sort = getFunctionName(tag.Sort)
}
return dummy, nil

}

func exportPad(pad padding.Padder) (*paddingDummy, error) {
Expand All @@ -317,6 +344,7 @@ func exportPad(pad padding.Padder) (*paddingDummy, error) {
}
return nil, fmt.Errorf("unknown padding type: %s", paddingType)
}

func exportEnc(enc encoding.Encoder) (string, error) {
// set encoding
encType := reflect.TypeOf(enc).Elem().Name()
Expand Down
140 changes: 137 additions & 3 deletions specs/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
)

func TestBuilder(t *testing.T) {

asciiJson, err := Builder.ExportJSON(Spec87ASCII)
require.NoError(t, err)

Expand All @@ -31,7 +30,6 @@ func TestBuilder(t *testing.T) {
require.NoError(t, err)

require.Exactly(t, Spec87Hex.Name, hexSpec.Name)

}

func TestExampleJSONSpec(t *testing.T) {
Expand Down Expand Up @@ -87,7 +85,8 @@ func TestSpecWithCompositeFields(t *testing.T) {
Pref: prefix.EBCDIC.Fixed,
Pad: padding.Left('0'),
}),
}}),
},
}),
30: field.NewNumeric(&field.Spec{
Length: 5,
Description: "field key that is not next number",
Expand All @@ -114,3 +113,138 @@ func TestSpecWithCompositeFields(t *testing.T) {

require.Exactly(t, testSpec, importedSpec)
}

func TestSpecWithCompositeBitmapedFields(t *testing.T) {
specJSON := []byte(`
{
"name": "TEST Spec",
"fields": {
"1": {
"type": "Composite",
"length": 255,
"description": "Private use field",
"prefix": "ASCII.LL",
"bitmap": {
"type": "Bitmap",
"length": 8,
"description": "Bitmap",
"enc": "HexToASCII",
"prefix": "Hex.Fixed",
"disableAutoExpand": true
},
"subfields": {
"1": {
"type": "String",
"length": 2,
"description": "Cardholder certificate Serial Number",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"2": {
"type": "String",
"length": 2,
"description": "Merchant certificate Serial Number",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"3": {
"type": "String",
"length": 2,
"description": "Transaction ID",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"4": {
"type": "String",
"length": 20,
"description": "CAVV",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"5": {
"type": "String",
"length": 20,
"description": "CAVV",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"6": {
"type": "String",
"length": 2,
"description": "Cardholder certificate Serial Number",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"7": {
"type": "String",
"length": 2,
"description": "Merchant certificate Serial Number",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"8": {
"type": "String",
"length": 2,
"description": "Transaction ID",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"9": {
"type": "String",
"length": 20,
"description": "CAVV",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
},
"10": {
"type": "String",
"length": 6,
"description": "CVV2",
"enc": "ASCII",
"prefix": "ASCII.Fixed"
}
}
}
}
}`)

spec, err := Builder.ImportJSON(specJSON)
require.NoError(t, err)

data := struct {
F1 *field.String
F2 *field.String
F3 *field.String
F4 *field.String
F5 *field.String
F6 *field.String
F7 *field.String
F8 *field.String
F9 *field.String
F10 *field.String
}{
F10: field.NewStringValue("11 456"),
}

compositeRestored := field.NewComposite(spec.Fields[1].Spec())
err = compositeRestored.Marshal(&data)
require.NoError(t, err)

packed, err := compositeRestored.Pack()
require.NoError(t, err)
require.Equal(t, "22004000000000000011 456", string(packed))

exportedJSON, err := Builder.ExportJSON(spec)
require.NoError(t, err)

spec, err = Builder.ImportJSON(exportedJSON)
require.NoError(t, err)

compositeRestored = field.NewComposite(spec.Fields[1].Spec())
err = compositeRestored.Marshal(&data)
require.NoError(t, err)

packed, err = compositeRestored.Pack()
require.NoError(t, err)
require.Equal(t, "22004000000000000011 456", string(packed))
}
Loading