Compare commits
2 Commits
b5/make-ap
...
v1.0.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae0cb176ae | ||
|
|
bc81dedafc |
2
go.mod
2
go.mod
@@ -3,13 +3,13 @@ module github.com/ucan-wg/go-ucan
|
|||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/ipfs/go-cid v0.0.7
|
github.com/ipfs/go-cid v0.0.7
|
||||||
github.com/libp2p/go-libp2p-core v0.7.0
|
github.com/libp2p/go-libp2p-core v0.7.0
|
||||||
github.com/multiformats/go-multibase v0.0.3
|
github.com/multiformats/go-multibase v0.0.3
|
||||||
github.com/multiformats/go-multihash v0.0.14
|
github.com/multiformats/go-multihash v0.0.14
|
||||||
github.com/multiformats/go-varint v0.0.6
|
github.com/multiformats/go-varint v0.0.6
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
13
go.sum
13
go.sum
@@ -71,13 +71,22 @@ github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS
|
|||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
|
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
|
||||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
|
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -124,9 +133,13 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
|
|||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
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=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
142
pkg/command/command.go
Normal file
142
pkg/command/command.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package command
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
separator = "/"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrNew indicates that the wrapped error was encountered while creating
|
||||||
|
// a new Command.
|
||||||
|
var ErrNew = errors.New("failed to create Command from elems")
|
||||||
|
|
||||||
|
// ErrParse indicates that the wrapped error was encountered while
|
||||||
|
// attempting to parse a string as a Command.
|
||||||
|
var ErrParse = errors.New("failed to parse Command")
|
||||||
|
|
||||||
|
// ErrorJoin indicates that the wrapped error was encountered while
|
||||||
|
// attempting to join a new segment to a Command.
|
||||||
|
var ErrJoin = errors.New("failed to join segments to Command")
|
||||||
|
|
||||||
|
// ErrRequiresLeadingSlash is returned when a parsing a string that
|
||||||
|
// doesn't start with a [leading slash character].
|
||||||
|
//
|
||||||
|
// [leading slash character]: https://github.com/ucan-wg/spec#segment-structure
|
||||||
|
var ErrRequiresLeadingSlash = parseError("a command requires a leading slash character")
|
||||||
|
|
||||||
|
// ErrDisallowsTrailingSlash is returned when parsing a string that [ends
|
||||||
|
// with a trailing slash character].
|
||||||
|
//
|
||||||
|
// [ends with a trailing slash character]: https://github.com/ucan-wg/spec#segment-structure
|
||||||
|
var ErrDisallowsTrailingSlash = parseError("a command must not include a trailing slash")
|
||||||
|
|
||||||
|
// ErrUCANNamespaceReserved is returned to indicate that a Command's
|
||||||
|
// first segment would contain the [reserved "ucan" namespace].
|
||||||
|
//
|
||||||
|
// [reserved "ucan" namespace]: https://github.com/ucan-wg/spec#ucan-namespace
|
||||||
|
var ErrUCANNamespaceReserved = errors.New("the UCAN namespace is reserved")
|
||||||
|
|
||||||
|
// ErrRequiresLowercase is returned if a Command contains, or would contain,
|
||||||
|
// [uppercase unicode characters].
|
||||||
|
//
|
||||||
|
// [uppercase unicode characters]: https://github.com/ucan-wg/spec#segment-structure
|
||||||
|
var ErrRequiresLowercase = parseError("UCAN path segments must must not contain upper-case characters")
|
||||||
|
|
||||||
|
func parseError(msg string) error {
|
||||||
|
return fmt.Errorf("%w: %s", ErrParse, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ fmt.Stringer = (*Command)(nil)
|
||||||
|
|
||||||
|
// Command is a concrete messages (a "verb") that MUST be unambiguously
|
||||||
|
// interpretable by the Subject of a UCAN.
|
||||||
|
//
|
||||||
|
// A [Command] is composed of a leading slash which is optionally followed
|
||||||
|
// by one or more slash-separated Segments of lowercase characters.
|
||||||
|
//
|
||||||
|
// [Command]: https://github.com/ucan-wg/spec#command
|
||||||
|
type Command struct {
|
||||||
|
segments []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a validated command from the provided list of segment
|
||||||
|
// strings. An error is returned if an invalid Command would be
|
||||||
|
// formed
|
||||||
|
func New(segments ...string) (*Command, error) {
|
||||||
|
return newCommand(ErrNew, segments...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommand(err error, segments ...string) (*Command, error) {
|
||||||
|
if len(segments) > 0 && segments[0] == "ucan" {
|
||||||
|
return nil, fmt.Errorf("%w: %w", err, ErrUCANNamespaceReserved)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := Command{segments}
|
||||||
|
|
||||||
|
return &cmd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse verifies that the provided string contains the required
|
||||||
|
// [segment structure] and, if valid, returns the resulting
|
||||||
|
// Command.
|
||||||
|
//
|
||||||
|
// [segment structure]: https://github.com/ucan-wg/spec#segment-structure
|
||||||
|
func Parse(s string) (*Command, error) {
|
||||||
|
if !strings.HasPrefix(s, "/") {
|
||||||
|
return nil, ErrRequiresLeadingSlash
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s) > 1 && strings.HasSuffix(s, "/") {
|
||||||
|
return nil, ErrDisallowsTrailingSlash
|
||||||
|
}
|
||||||
|
|
||||||
|
if s != strings.ToLower(s) {
|
||||||
|
return nil, ErrRequiresLowercase
|
||||||
|
}
|
||||||
|
|
||||||
|
// The leading slash will result in the first element from strings.Split
|
||||||
|
// being an empty string which is removed as strings.Join will ignore it.
|
||||||
|
return newCommand(ErrParse, strings.Split(s, "/")[1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Top] is the most powerful capability.
|
||||||
|
//
|
||||||
|
// This function returns a Command that is a wildcard and therefore represents the
|
||||||
|
// most powerful abilily. As such it should be handle with care and used
|
||||||
|
// sparingly.
|
||||||
|
//
|
||||||
|
// [Top]: https://github.com/ucan-wg/spec#-aka-top
|
||||||
|
func Top() *Command {
|
||||||
|
cmd, _ := New()
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid returns true if the provided string is a valid UCAN command.
|
||||||
|
func IsValid(s string) bool {
|
||||||
|
_, err := Parse(s)
|
||||||
|
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join appends segments to the end of this command using the required
|
||||||
|
// segment separator.
|
||||||
|
func (c *Command) Join(segments ...string) (*Command, error) {
|
||||||
|
return newCommand(ErrJoin, append(c.segments, segments...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segments returns the ordered segments that comprise the Command as a
|
||||||
|
// slice of strings.
|
||||||
|
func (c *Command) Segments() []string {
|
||||||
|
return c.segments
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the composed representation the command. This is also
|
||||||
|
// the required wire representation (before IPLD encoding occurs.)
|
||||||
|
func (c *Command) String() string {
|
||||||
|
return "/" + strings.Join([]string(c.segments), "/")
|
||||||
|
}
|
||||||
159
pkg/command/command_test.go
Normal file
159
pkg/command/command_test.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user