This is probably overkill but most of the code is needed to validate the command string. My thought was that this could then be used in the delegation and invocation structs to provide a stronger type. The Command struct itself is a bit more convenient with segments represented by []string but this might need to be changed to simply string to simplify IPLD encoding/decoding
160 lines
2.8 KiB
Go
160 lines
2.8 KiB
Go
package command_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/ucan-wg/go-ucan/pkg/command"
|
|
)
|
|
|
|
func TestCommand_String(t *testing.T) {
|
|
require.Equal(t, "/", command.Top().String())
|
|
}
|
|
|
|
func TestIsValidCommand(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("succeeds when", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, testcase := range validTestcases(t) {
|
|
testcase := testcase
|
|
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
require.True(t, command.IsValid(testcase.inp))
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("fails when", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, testcase := range invalidTestcases(t) {
|
|
testcase := testcase
|
|
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
require.False(t, command.IsValid(testcase.inp))
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestParseCommand(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("succeeds when", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, testcase := range validTestcases(t) {
|
|
testcase := testcase
|
|
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cmd, err := command.Parse("/elem0/elem1/elem2")
|
|
require.NoError(t, err)
|
|
require.NotNil(t, cmd)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("fails when", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, testcase := range invalidTestcases(t) {
|
|
testcase := testcase
|
|
|
|
t.Run(testcase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cmd, err := command.Parse(testcase.inp)
|
|
assert.ErrorIs(t, err, command.ErrParse)
|
|
assert.ErrorIs(t, err, testcase.err)
|
|
assert.Nil(t, cmd)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
type testcase struct {
|
|
name string
|
|
inp string
|
|
}
|
|
|
|
func validTestcases(t *testing.T) []testcase {
|
|
t.Helper()
|
|
|
|
cmds := []string{
|
|
"/",
|
|
"/crud",
|
|
"/crud/create",
|
|
"/stack/pop",
|
|
"/crypto/sign",
|
|
"/foo/bar/baz/qux/quux",
|
|
"/ほげ/ふが",
|
|
}
|
|
|
|
testcases := make([]testcase, len(cmds))
|
|
|
|
for i, inp := range cmds {
|
|
testcases[i] = testcase{
|
|
name: "Command is " + inp,
|
|
inp: inp,
|
|
}
|
|
}
|
|
|
|
return testcases
|
|
}
|
|
|
|
type errorTestcase struct {
|
|
testcase
|
|
err error
|
|
}
|
|
|
|
func invalidTestcases(t *testing.T) []errorTestcase {
|
|
t.Helper()
|
|
|
|
return []errorTestcase{
|
|
{
|
|
testcase: testcase{
|
|
name: "leading slash is missing",
|
|
inp: "elem0/elem1/elem2",
|
|
},
|
|
err: command.ErrRequiresLeadingSlash,
|
|
},
|
|
{
|
|
testcase: testcase{
|
|
name: "trailing slash is present",
|
|
inp: "/elem0/elem1/elem2/",
|
|
},
|
|
err: command.ErrDisallowsTrailingSlash,
|
|
},
|
|
{
|
|
testcase: testcase{
|
|
name: "only reserved ucan namespace",
|
|
inp: "/ucan",
|
|
},
|
|
err: command.ErrUCANNamespaceReserved,
|
|
},
|
|
{
|
|
testcase: testcase{
|
|
name: "reserved ucan namespace prefix",
|
|
inp: "/ucan/elem0/elem1/elem2",
|
|
},
|
|
err: command.ErrUCANNamespaceReserved,
|
|
},
|
|
{
|
|
testcase: testcase{
|
|
name: "uppercase character are present",
|
|
inp: "/elem0/Elem1/elem2",
|
|
},
|
|
err: command.ErrRequiresLowercase,
|
|
},
|
|
}
|
|
}
|