diff --git a/modules/core/24-host/parse_test.go b/modules/core/24-host/parse_test.go index e7d039be2a4..3bb8ba10017 100644 --- a/modules/core/24-host/parse_test.go +++ b/modules/core/24-host/parse_test.go @@ -1,6 +1,7 @@ package host_test import ( + "errors" "fmt" "math" "testing" @@ -18,22 +19,22 @@ func TestParseIdentifier(t *testing.T) { identifier string prefix string expSeq uint64 - expPass bool + expErr error }{ - {"valid 0", "connection-0", "connection-", 0, true}, - {"valid 1", "connection-1", "connection-", 1, true}, - {"valid large sequence", connectiontypes.FormatConnectionIdentifier(math.MaxUint64), "connection-", math.MaxUint64, true}, + {"valid 0", "connection-0", "connection-", 0, nil}, + {"valid 1", "connection-1", "connection-", 1, nil}, + {"valid large sequence", connectiontypes.FormatConnectionIdentifier(math.MaxUint64), "connection-", math.MaxUint64, nil}, // one above uint64 max - {"invalid uint64", "connection-18446744073709551616", "connection-", 0, false}, + {"invalid uint64", "connection-18446744073709551616", "connection-", 0, errors.New("the value '18446744073709551616' cannot be parsed as a valid uint64")}, // uint64 == 20 characters - {"invalid large sequence", "connection-2345682193567182931243", "connection-", 0, false}, - {"capital prefix", "Connection-0", "connection-", 0, false}, - {"double prefix", "connection-connection-0", "connection-", 0, false}, - {"doesn't have prefix", "connection-0", "prefix", 0, false}, - {"missing dash", "connection0", "connection-", 0, false}, - {"blank id", " ", "connection-", 0, false}, - {"empty id", "", "connection-", 0, false}, - {"negative sequence", "connection--1", "connection-", 0, false}, + {"invalid large sequence", "connection-2345682193567182931243", "connection-", 0, errors.New("the sequence number '2345682193567182931243' exceeds the valid range for a uint64")}, + {"capital prefix", "Connection-0", "connection-", 0, errors.New("the prefix 'Connection' should be in lowercase")}, + {"double prefix", "connection-connection-0", "connection-", 0, errors.New("only a single 'connection-' prefix is allowed")}, + {"doesn't have prefix", "connection-0", "prefix", 0, errors.New("the connection ID is missing the required prefix 'connection-'")}, + {"missing dash", "connection0", "connection-", 0, errors.New("the connection ID is missing the dash ('-') between the prefix 'connection' and the sequence number")}, + {"blank id", " ", "connection-", 0, errors.New("invalid blank connection ID")}, + {"empty id", "", "connection-", 0, errors.New("invalid empty connection id")}, + {"negative sequence", "connection--1", "connection-", 0, errors.New("the sequence number '-1' is negative and invalid")}, } for _, tc := range testCases { @@ -42,7 +43,7 @@ func TestParseIdentifier(t *testing.T) { seq, err := host.ParseIdentifier(tc.identifier, tc.prefix) require.Equal(t, tc.expSeq, seq) - if tc.expPass { + if tc.expErr == nil { require.NoError(t, err, tc.name) } else { require.Error(t, err, tc.name) @@ -52,23 +53,23 @@ func TestParseIdentifier(t *testing.T) { func TestMustParseClientStatePath(t *testing.T) { testCases := []struct { - name string - path string - expPass bool + name string + path string + expErr error }{ - {"valid", string(host.FullClientStateKey(ibctesting.FirstClientID)), true}, - {"path too large", fmt.Sprintf("clients/clients/%s/clientState", ibctesting.FirstClientID), false}, - {"path too small", fmt.Sprintf("clients/%s", ibctesting.FirstClientID), false}, - {"path does not begin with client store", fmt.Sprintf("cli/%s/%s", ibctesting.FirstClientID, host.KeyClientState), false}, - {"path does not end with client state key", fmt.Sprintf("%s/%s/consensus", string(host.KeyClientStorePrefix), ibctesting.FirstClientID), false}, - {"client ID is empty", string(host.FullClientStateKey("")), false}, - {"client ID is only spaces", string(host.FullClientStateKey(" ")), false}, + {"valid", string(host.FullClientStateKey(ibctesting.FirstClientID)), nil}, + {"path too large", fmt.Sprintf("clients/clients/%s/clientState", ibctesting.FirstClientID), errors.New("path exceeds maximum allowed length for a client state path")}, + {"path too small", fmt.Sprintf("clients/%s", ibctesting.FirstClientID), errors.New("path is shorter than the minimum allowed length")}, + {"path does not begin with client store", fmt.Sprintf("cli/%s/%s", ibctesting.FirstClientID, host.KeyClientState), errors.New("the path must start with 'clients/' but starts with 'cli/'")}, + {"path does not end with client state key", fmt.Sprintf("%s/%s/consensus", string(host.KeyClientStorePrefix), ibctesting.FirstClientID), errors.New("the path must end with the client state key 'clientState'")}, + {"client ID is empty", string(host.FullClientStateKey("")), errors.New("the client ID is empty, which is invalid")}, + {"client ID is only spaces", string(host.FullClientStateKey(" ")), errors.New("Ensure the client ID is not empty and does not contain only spaces")}, } for _, tc := range testCases { tc := tc - if tc.expPass { + if tc.expErr == nil { require.NotPanics(t, func() { clientID := host.MustParseClientStatePath(tc.path) require.Equal(t, ibctesting.FirstClientID, clientID) @@ -86,15 +87,15 @@ func TestMustParseConnectionPath(t *testing.T) { name string path string expected string - expPass bool + expErr error }{ - {"valid", "a/connection", "connection", true}, - {"valid localhost", "/connection-localhost", "connection-localhost", true}, - {"invalid empty path", "", "", false}, + {"valid", "a/connection", "connection", nil}, + {"valid localhost", "/connection-localhost", "connection-localhost", nil}, + {"invalid empty path", "", "", errors.New("path cannot be empty")}, } for _, tc := range testCases { - if tc.expPass { + if tc.expErr == nil { require.NotPanics(t, func() { connID := host.MustParseConnectionPath(tc.path) require.Equal(t, connID, tc.expected) diff --git a/modules/core/24-host/validate_test.go b/modules/core/24-host/validate_test.go index c7e96275642..e94b8e69aa4 100644 --- a/modules/core/24-host/validate_test.go +++ b/modules/core/24-host/validate_test.go @@ -1,6 +1,7 @@ package host import ( + "errors" "fmt" "strings" "testing" @@ -12,25 +13,25 @@ import ( var longID = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis eros neque, ultricies vel ligula ac, convallis porttitor elit. Maecenas tincidunt turpis elit, vel faucibus nisl pellentesque sodales" type testCase struct { - msg string - id string - expPass bool + msg string + id string + expErr error } func TestDefaultIdentifierValidator(t *testing.T) { testCases := []testCase{ - {"valid lowercase", "lowercaseid", true}, - {"valid id special chars", "._+-#[]<>._+-#[]<>", true}, - {"valid id lower and special chars", "lower._+-#[]<>", true}, - {"numeric id", "1234567890", true}, - {"uppercase id", "NOTLOWERCASE", true}, - {"numeric id", "1234567890", true}, - {"blank id", " ", false}, - {"id length out of range", "1", false}, - {"id is too long", "this identifier is too long to be used as a valid identifier", false}, - {"path-like id", "lower/case/id", false}, - {"invalid id", "(clientid)", false}, - {"empty string", "", false}, + {"valid lowercase", "lowercaseid", nil}, + {"valid id special chars", "._+-#[]<>._+-#[]<>", nil}, + {"valid id lower and special chars", "lower._+-#[]<>", nil}, + {"numeric id", "1234567890", nil}, + {"uppercase id", "NOTLOWERCASE", nil}, + {"numeric id", "1234567890", nil}, + {"blank id", " ", errors.New("the ID is blank - contains only spaces")}, + {"id length out of range", "1", errors.New("the ID length is too short")}, + {"id is too long", "this identifier is too long to be used as a valid identifier", errors.New("the ID exceeds the maximum allowed length")}, + {"path-like id", "lower/case/id", errors.New("the ID contains path-like characters, which are invalid for an ID")}, + {"invalid id", "(clientid)", errors.New("the ID contains invalid characters")}, + {"empty string", "", errors.New("the ID cannot be empty")}, } for _, tc := range testCases { @@ -40,7 +41,7 @@ func TestDefaultIdentifierValidator(t *testing.T) { err1 := ConnectionIdentifierValidator(tc.id) err2 := ChannelIdentifierValidator(tc.id) err3 := PortIdentifierValidator(tc.id) - if tc.expPass { + if tc.expErr == nil { require.NoError(t, err, tc.msg) require.NoError(t, err1, tc.msg) require.NoError(t, err2, tc.msg) @@ -56,25 +57,25 @@ func TestDefaultIdentifierValidator(t *testing.T) { func TestPortIdentifierValidator(t *testing.T) { testCases := []testCase{ - {"valid lowercase", "transfer", true}, - {"valid id special chars", "._+-#[]<>._+-#[]<>", true}, - {"valid id lower and special chars", "lower._+-#[]<>", true}, - {"numeric id", "1234567890", true}, - {"uppercase id", "NOTLOWERCASE", true}, - {"numeric id", "1234567890", true}, - {"blank id", " ", false}, - {"id length out of range", "1", false}, - {"id is too long", longID, false}, - {"path-like id", "lower/case/id", false}, - {"invalid id", "(clientid)", false}, - {"empty string", "", false}, + {"valid lowercase", "transfer", nil}, + {"valid id special chars", "._+-#[]<>._+-#[]<>", nil}, + {"valid id lower and special chars", "lower._+-#[]<>", nil}, + {"numeric id", "1234567890", nil}, + {"uppercase id", "NOTLOWERCASE", nil}, + {"numeric id", "1234567890", nil}, + {"blank id", " ", errors.New("the ID is blank - contains only spaces")}, + {"id length out of range", "1", errors.New("the ID length is too short")}, + {"id is too long", longID, errors.New("the ID exceeds the maximum allowed length")}, + {"path-like id", "lower/case/id", errors.New("the ID contains path-like characters, which are invalid for an ID")}, + {"invalid id", "(clientid)", errors.New("the ID contains invalid characters")}, + {"empty string", "", errors.New("the ID cannot be empty")}, } for _, tc := range testCases { tc := tc err := PortIdentifierValidator(tc.id) - if tc.expPass { + if tc.expErr == nil { require.NoError(t, err, tc.msg) } else { require.Error(t, err, tc.msg) @@ -84,24 +85,24 @@ func TestPortIdentifierValidator(t *testing.T) { func TestPathValidator(t *testing.T) { testCases := []testCase{ - {"valid lowercase", "p/lowercaseid", true}, - {"numeric path", "p/239123", true}, - {"valid id special chars", "p/._+-#[]<>._+-#[]<>", true}, - {"valid id lower and special chars", "lower/._+-#[]<>", true}, - {"id length out of range", "p/l", true}, - {"uppercase id", "p/NOTLOWERCASE", true}, - {"invalid path", "lowercaseid", false}, - {"blank id", "p/ ", false}, - {"id length out of range", "p/12345678901234567890123456789012345678901234567890123456789012345", false}, - {"invalid id", "p/(clientid)", false}, - {"empty string", "", false}, - {"separators only", "////", false}, - {"just separator", "/", false}, - {"begins with separator", "/id", false}, - {"blank before separator", " /id", false}, - {"ends with separator", "id/", false}, - {"blank after separator", "id/ ", false}, - {"blanks with separator", " / ", false}, + {"valid lowercase", "p/lowercaseid", nil}, + {"numeric path", "p/239123", nil}, + {"valid id special chars", "p/._+-#[]<>._+-#[]<>", nil}, + {"valid id lower and special chars", "lower/._+-#[]<>", nil}, + {"id length out of range", "p/l", nil}, + {"uppercase id", "p/NOTLOWERCASE", nil}, + {"invalid path", "lowercaseid", errors.New("the path is invalid")}, + {"blank id", "p/ ", errors.New("the ID is blank or contains only whitespace after the separator")}, + {"id length out of range", "p/12345678901234567890123456789012345678901234567890123456789012345", errors.New("the ID exceeds the maximum allowed length")}, + {"invalid id", "p/(clientid)", errors.New("the ID contains invalid characters, such as parentheses")}, + {"empty string", "", errors.New("the ID cannot be empty")}, + {"separators only", "////", errors.New("the ID contains only separators, which is invalid")}, + {"just separator", "/", errors.New("the ID cannot be just a separator")}, + {"begins with separator", "/id", errors.New("the ID should not begin with a separator")}, + {"blank before separator", " /id", errors.New("the ID cannot have leading spaces before the separator")}, + {"ends with separator", "id/", errors.New("the ID cannot end with a separator")}, + {"blank after separator", "id/ ", errors.New("the ID cannot have trailing spaces after the separator")}, + {"blanks with separator", " / ", errors.New("the ID cannot have spaces before or after the separator")}, } for _, tc := range testCases { @@ -113,7 +114,7 @@ func TestPathValidator(t *testing.T) { err := f(tc.id) - if tc.expPass { + if tc.expErr == nil { seps := strings.Count(tc.id, "/") require.Equal(t, 1, seps) require.NoError(t, err, tc.msg) @@ -132,21 +133,21 @@ func TestCustomPathValidator(t *testing.T) { }) testCases := []testCase{ - {"valid custom path", "id_client/id_one", true}, - {"invalid path", "client", false}, - {"invalid custom path", "id_one/client", false}, - {"invalid identifier", "id_client/id_1234567890123456789012345678901234567890123457890123456789012345", false}, - {"separators only", "////", false}, - {"just separator", "/", false}, - {"ends with separator", "id_client/id_one/", false}, - {"beings with separator", "/id_client/id_one", false}, + {"valid custom path", "id_client/id_one", nil}, + {"invalid path", "client", errors.New("the path is invalid")}, + {"invalid custom path", "id_one/client", errors.New("the path contains an invalid structure")}, + {"invalid identifier", "id_client/id_1234567890123456789012345678901234567890123457890123456789012345", errors.New("the identifier exceeds the maximum allowed length for an ID")}, + {"separators only", "////", errors.New("the path contains only separators, which is invalid")}, + {"just separator", "/", errors.New("the path cannot be just a separator")}, + {"ends with separator", "id_client/id_one/", errors.New("the path cannot end with a separator")}, + {"beings with separator", "/id_client/id_one", errors.New("the path cannot begin with a separator")}, } for _, tc := range testCases { tc := tc err := validateFn(tc.id) - if tc.expPass { + if tc.expErr == nil { require.NoError(t, err, tc.msg) } else { require.Error(t, err, tc.msg)