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

feat: add cip20 model tests #24

Merged
merged 1 commit into from
Dec 17, 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
23 changes: 21 additions & 2 deletions cip20.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,29 @@

package models

import "github.com/go-playground/validator/v10"

type Cip20Metadata struct {
Num674 Num674 `cbor:"674,keyasint" json:"674"`
Num674 Num674 `cbor:"674,keyasint" json:"674" validate:"required"`
}

type Num674 struct {
Msg []string `cbor:"msg" json:"msg"`
Msg []string `cbor:"msg" json:"msg" validate:"required,gt=0,dive,max=64"`
}

func NewCip20Metadata(messages []string) (*Cip20Metadata, error) {
validate := validator.New()

metadata := &Cip20Metadata{Num674: Num674{Msg: messages}}

if err := validate.Struct(metadata); err != nil {
return nil, err
}

return metadata, nil
}

func (c *Cip20Metadata) Validate() error {
validate := validator.New()
return validate.Struct(c)
}
257 changes: 257 additions & 0 deletions cip20_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package models

import (
"encoding/hex"
"encoding/json"
"reflect"
"strings"
"testing"

"github.com/fxamacker/cbor/v2"
)

func TestValidCip20Metadata(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
cborHex string
expectedObj Cip20Metadata
jsonData string
expectCBORUnmarshalError bool
expectJSONUnmarshalError bool
expectValidationError bool
expectCBORDeepEqualError bool
expectJSONDeepEqualError bool
}{
{
name: "Valid - Single Message",
expectedObj: Cip20Metadata{
Num674: Num674{
Msg: []string{"This is a comment for the transaction xyz, thank you very much!"},
},
},
cborHex: "A163363734A1636D736781783F54686973206973206120636F6D6D656E7420666F7220746865207472616E73616374696F6E2078797A2C207468616E6B20796F752076657279206D75636821",
jsonData: `{
"674":
{
"msg":
[
"This is a comment for the transaction xyz, thank you very much!"
]
}
}`,
expectCBORUnmarshalError: false,
expectJSONUnmarshalError: false,
expectValidationError: false,
expectCBORDeepEqualError: false,
expectJSONDeepEqualError: false,
},
{
name: "Valid - Multiple Messages",
expectedObj: Cip20Metadata{
Num674: Num674{
Msg: []string{
"Invoice-No: 1234567890",
"Customer-No: 555-1234",
"P.S.: i will shop again at your store :-)",
},
},
},
jsonData: `{
"674":
{
"msg":
[
"Invoice-No: 1234567890",
"Customer-No: 555-1234",
"P.S.: i will shop again at your store :-)"
]
}
}`,
cborHex: "A163363734A1636D73678376496E766F6963652D4E6F3A203132333435363738393075437573746F6D65722D4E6F3A203535352D313233347829502E532E3A20692077696C6C2073686F7020616761696E20617420796F75722073746F7265203A2D29",
expectCBORUnmarshalError: false,
expectJSONUnmarshalError: false,
expectValidationError: false,
expectCBORDeepEqualError: false,
expectJSONDeepEqualError: false,
},
{
name: "Invalid - Message Exceeds 64 Bytes",
expectedObj: Cip20Metadata{
Num674: Num674{
Msg: []string{strings.Repeat("a", 65)}, // 65 'a's to exceed the limit
},
},
jsonData: `{
"674": {
"msg": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
}
}`,
cborHex: "A163363734A1636D73678178416161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
expectCBORUnmarshalError: false,
expectJSONUnmarshalError: false,
expectValidationError: true,
expectCBORDeepEqualError: false,
expectJSONDeepEqualError: false,
},
{
name: "Invalid - Message Deep error",
expectedObj: Cip20Metadata{
Num674: Num674{
Msg: []string{strings.Repeat("b", 65)},
},
},
jsonData: `{
"674": {
"msg": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
}
}`,
cborHex: "A163363734A1636D73678178416161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
expectCBORUnmarshalError: false,
expectJSONUnmarshalError: false,
expectValidationError: true,
expectCBORDeepEqualError: true,
expectJSONDeepEqualError: true,
},
{
name: "Invalid - Message Deep error 675",
expectedObj: Cip20Metadata{
Num674: Num674{
Msg: []string{strings.Repeat("b", 65)},
},
},
jsonData: `{
"675": {
"msg": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
}
}`,
cborHex: "A163363734A1636D73678178416161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161",
expectCBORUnmarshalError: false,
expectJSONUnmarshalError: false,
expectValidationError: true,
expectCBORDeepEqualError: true,
expectJSONDeepEqualError: true,
},
}

for _, tc := range testCases {
tc := tc // capture range variable for goroutines
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

// Decode the CBOR hex string
cborData, err := hex.DecodeString(tc.cborHex)
if err != nil {
t.Errorf("failed to decode CBOR hex string for %s, error: %v", tc.name, err)
}

// CBOR Unmarshal
var decodedMetadata Cip20Metadata
err = cbor.Unmarshal(cborData, &decodedMetadata)
if tc.expectCBORUnmarshalError {
if err == nil {
t.Errorf("expected CBOR unmarshal error but got none for test: %s", tc.name)
}
} else {
if err != nil {
t.Errorf("did not expect CBOR unmarshal error but got one for test: %s, error: %v", tc.name, err)
}
}

// CBOR Validate
err = decodedMetadata.Validate()
if tc.expectValidationError {
if err == nil {
t.Errorf("expected validation error but got none for test: %s", tc.name)
}
} else {
if err != nil {
t.Errorf("did not expect validation error but got one for test: %s, error: %v", tc.name, err)
}
}

// Deep Equality Check for CBOR
deepEqual := reflect.DeepEqual(decodedMetadata, tc.expectedObj)
if tc.expectCBORDeepEqualError && deepEqual {
t.Errorf("Cbor expected deep equal error but objects are identical for test: %s", tc.name)
}
if !tc.expectCBORDeepEqualError && !deepEqual {
t.Errorf("Cbor expected objects to be identical but they are not for test: %s, expected: %v, got: %v", tc.name, tc.expectedObj, decodedMetadata)
}

// Reset the object for JSON testing
decodedMetadata = Cip20Metadata{}
// Decode the JSON string
err = json.Unmarshal([]byte(tc.jsonData), &decodedMetadata)
if err != nil {
t.Errorf("unexpected result unmarshaling JSON to Cip20Metadata for test %s, error: %v", tc.name, err)
}
if tc.expectJSONUnmarshalError {
if err == nil {
t.Errorf("expected JSON unmarshal error but got none for test: %s", tc.name)
}
} else {
if err != nil {
t.Errorf("did not expect JSON unmarshal error but got one for test: %s, error: %v", tc.name, err)
}
}

// JSON Validate
err = decodedMetadata.Validate()
if tc.expectValidationError {
if err == nil {
t.Errorf("expected validation error but got none for test: %s", tc.name)
}
} else {
if err != nil {
t.Errorf("did not expect validation error but got one for test: %s, error: %v", tc.name, err)
}
}

// Deep Equality Check for JSON
deepEqual = reflect.DeepEqual(decodedMetadata, tc.expectedObj)
if tc.expectJSONDeepEqualError && deepEqual {
t.Errorf("Json expected deep equal error but objects are identical for test: %s", tc.name)
}
if !tc.expectJSONDeepEqualError && !deepEqual {
t.Errorf("Json expected objects to be identical but they are not for test: %s, expected: %v, got: %v", tc.name, tc.expectedObj, decodedMetadata)
}
})
}
}

func TestNewCip20Metadata(t *testing.T) {
t.Parallel()
// Test case: Non-empty messages
messages := []string{"message1", "message2"}
expectedJSON := `{"674":{"msg":["message1","message2"]}}`

metadata, err := NewCip20Metadata(messages)
if err != nil {
t.Errorf("Expected no error, but got: %v", err)
}

actualJSON, err := json.Marshal(metadata)
if err != nil {
t.Errorf("Failed to marshal metadata to JSON: %v", err)
}

if string(actualJSON) != expectedJSON {
t.Errorf("Expected JSON: %s, but got: %s", expectedJSON, string(actualJSON))
}

// Test case: Invalid metadata
messages = []string{}
expectedErr := "Key: 'Cip20Metadata.Num674.Msg' Error:Field validation for 'Msg' failed on the 'gt' tag"

_, err = NewCip20Metadata(messages)
if err == nil {
t.Errorf("Expected validation error, but got no error")
} else {
actualErr := err.Error()
if actualErr != expectedErr {
t.Errorf("Expected error: %s, but got: %s", expectedErr, actualErr)
}
}
}
15 changes: 13 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ module github.com/blinklabs-io/cardano-models

go 1.20

require github.com/blinklabs-io/gouroboros v0.67.1
require (
github.com/blinklabs-io/gouroboros v0.67.1
github.com/fxamacker/cbor/v2 v2.5.0
github.com/go-playground/validator/v10 v10.16.0
)

require (
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/jinzhu/copier v0.4.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.16.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
35 changes: 35 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,43 @@
github.com/blinklabs-io/gouroboros v0.67.1 h1:SyzxCIEa2rph3KQr1D+PgqsPNFORN/OdwNtrL0h42g8=
github.com/blinklabs-io/gouroboros v0.67.1/go.mod h1:Q154NJPs7gB93Tggt8ts9RGIlW2kkknr6M90Q3jh0s4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=