Compare commits

..

No commits in common. "4e99dd5057b159276c29fab7cf7af199f7345844" and "5d60552f123821fa17565c698bc93dae58df1042" have entirely different histories.

11 changed files with 36 additions and 633 deletions

View File

@ -67,8 +67,6 @@ func CompileTo(target *Pattern, uncompiledPattern string) error {
target.init(defaultFieldTagName) target.init(defaultFieldTagName)
target.template = uncompiledPattern
s := uncompiledPattern s := uncompiledPattern
for { for {
index := strings.IndexRune(s, '{') index := strings.IndexRune(s, '{')

44
doc.go
View File

@ -1,43 +1,12 @@
/* /*
Package pathmatch provides pattern matching for path templates. Package pathmatch provides pattern matching for paths.
A path template might look something like the following: For example, a path could be a file system path, or a path could be a path from a URL (such as an HTTP or HTTPS based URL).
/v1/users/{user_id} The matches can be loaded into variables (when using pathmatch.Find());
or can be loaded into a struct (when using pathmatch.Pattern.FindAndLoad()).
Or: Example Usage:
/account={account_name}/user={user_name}/message={message_hash}
Or:
/backup/{folder_name}/
Or:
/v2/select/{fields}/from/{table_name}/where/{filters}
This path template could be a file system path, or a path could be a path from a URL (such as an HTTP or HTTPS based URL).
To compile one of these pattern templates, you would do something such as:
var template string = "/v1/users/{user_id}/messages/{message_id}"
var pattern pathmatch.Pattern
err := pathmatch.CompileTo(&pattern, template)
if nil != err {
fmt.Fprintf(os.Stdout, "ERROR: %s\n", err)
return
}
(In addition to the pathmatch.CompileTo() func, there is also the pathmatch.Compile(), and
pathmatch.MustCompile(). But pathmatch.CompileTo() is recommended over the other 2 options
for most cases.)
One you have the compiled pattern, you would either use pathmatch.Match(), pathmatch.Find(),
or pathmatch.FindAndLoad() depending on what you were trying to accomplish.
Example Usage
var pattern pathmatch.Pattern var pattern pathmatch.Pattern
@ -66,7 +35,7 @@ Example Usage
fmt.Printf("user_id = %q \n", userId) // user_id = "bMM_kJFMEV" fmt.Printf("user_id = %q \n", userId) // user_id = "bMM_kJFMEV"
fmt.Printf("vehicle_id = %q \n", vehicleId) // vehicle_id = "o_bcU.RZGK" fmt.Printf("vehicle_id = %q \n", vehicleId) // vehicle_id = "o_bcU.RZGK"
Alternate Example Usage Alternate Example Usage:
var pattern pathmatch.Pattern var pattern pathmatch.Pattern
@ -95,5 +64,6 @@ Alternate Example Usage
fmt.Printf("user_id = %q \n", data.UserId) // user_id = "bMM_kJFMEV" fmt.Printf("user_id = %q \n", data.UserId) // user_id = "bMM_kJFMEV"
fmt.Printf("vehicle_id = %q \n", data.VehicleId) // vehicle_id = "o_bcU.RZGK" fmt.Printf("vehicle_id = %q \n", data.VehicleId) // vehicle_id = "o_bcU.RZGK"
*/ */
package pathmatch package pathmatch

View File

@ -1,26 +0,0 @@
package pathmatch_test
import (
"github.com/reiver/go-pathmatch"
"fmt"
"os"
)
func ExamplePattern_String() {
var template = "/v1/users/{user_id}"
var pattern pathmatch.Pattern
err := pathmatch.CompileTo(&pattern, template)
if nil != err {
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
return
}
fmt.Printf("pattern: %s", pattern)
// Output:
// pattern: /v1/users/{user_id}
}

View File

@ -32,7 +32,6 @@ import (
// } // }
type Pattern struct { type Pattern struct {
mutex sync.RWMutex mutex sync.RWMutex
template string
bits []string bits []string
names []string names []string
namesSet map[string]struct{} namesSet map[string]struct{}

View File

@ -12,11 +12,6 @@ var (
errThisShouldNeverHappen = newInternalError("This should never happen.") errThisShouldNeverHappen = newInternalError("This should never happen.")
) )
// Find compares path against its (compiled) pattern template; if it matches it loads the
// matches into args, and then returns true.
//
// Find may set some, or all of the items in args even if it returns false, and even if it
// returns an error.
func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) { func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) {
if nil == pattern { if nil == pattern {
return false, errNilReceiver return false, errNilReceiver
@ -38,33 +33,24 @@ func (pattern *Pattern) Find(path string, args ...interface{}) (bool, error) {
s = s[len(bit):] s = s[len(bit):]
case wildcardBit: case wildcardBit:
if "" == s {
return false, nil
}
index := strings.IndexRune(s, '/') index := strings.IndexRune(s, '/')
if -1 == index {
var value string if err := set(s, argsIndex, args...); nil != err {
switch { return doesNotMatter, err
default: }
argsIndex++
} else if 0 <= index {
value := s[:index]
if err := set(value, argsIndex, args...); nil != err {
return doesNotMatter, err
}
argsIndex++
s = s[index:]
} else {
return doesNotMatter, errThisShouldNeverHappen return doesNotMatter, errThisShouldNeverHappen
case -1 == index:
value = s
case 0 <= index:
value = s[:index]
} }
if err := set(value, argsIndex, args...); nil != err {
return doesNotMatter, err
}
argsIndex++
s = s[len(value):]
} }
} }
if "" != s {
return false, nil
}
return true, nil return true, nil
} }

View File

@ -1,9 +1,7 @@
package pathmatch_test package pathmatch
import ( import (
"github.com/reiver/go-pathmatch"
"testing" "testing"
) )
@ -11,13 +9,13 @@ import (
func TestFind(t *testing.T) { func TestFind(t *testing.T) {
tests := []struct{ tests := []struct{
Pattern *pathmatch.Pattern Pattern *Pattern
Args []interface{} Args []interface{}
Path string Path string
ExpectedArgs []string ExpectedArgs []string
}{ }{
{ {
Pattern: pathmatch.MustCompile("/{this}/{that}/{these}/{those}"), Pattern: MustCompile("/{this}/{that}/{these}/{those}"),
Args: []interface{}{new(string), new(string), new(string), new(string), }, Args: []interface{}{new(string), new(string), new(string), new(string), },
Path: "/apple/banana/cherry/grape", Path: "/apple/banana/cherry/grape",
ExpectedArgs: []string{"apple","banana","cherry","grape"}, ExpectedArgs: []string{"apple","banana","cherry","grape"},
@ -26,65 +24,65 @@ func TestFind(t *testing.T) {
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}"), Pattern: MustCompile("/user/{sessionKey}"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/"), Pattern: MustCompile("/user/{sessionKey}/"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle"), Pattern: MustCompile("/user/{sessionKey}/vehicle"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/"), Pattern: MustCompile("/user/{sessionKey}/vehicle/"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/DEFAULT"), Pattern: MustCompile("/user/{sessionKey}/vehicle/DEFAULT"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/DEFAULT/"), Pattern: MustCompile("/user/{sessionKey}/vehicle/DEFAULT/"),
Args: []interface{}{new(string), }, Args: []interface{}{new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"), Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
Args: []interface{}{new(string), new(string), }, Args: []interface{}{new(string), new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"), Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
Args: []interface{}{new(string), new(string), }, Args: []interface{}{new(string), new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "DEFAULT"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"), Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}"),
Args: []interface{}{new(string), new(string), }, Args: []interface{}{new(string), new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},
}, },
{ {
Pattern: pathmatch.MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"), Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
Args: []interface{}{new(string), new(string), }, Args: []interface{}{new(string), new(string), },
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7/", Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/N9Z_tiv7/",
ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"}, ExpectedArgs: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij", "N9Z_tiv7"},

View File

@ -14,13 +14,7 @@ var (
) )
// FindAndLoad compares path against its (compiled) pattern template; if it matches func (pattern *Pattern) FindAndLoad(path string, strct interface{}) (bool, error) {
// it loads the matches into dest, and then returns true.
//
// dest can be a pointer struct, or a pointer to a []string.
//
// Find may set some, or all of the items or fields in dest even if it returns false, and even if it returns an error.
func (pattern *Pattern) FindAndLoad(path string, dest interface{}) (bool, error) {
if nil == pattern { if nil == pattern {
return false, errNilReceiver return false, errNilReceiver
} }
@ -45,59 +39,12 @@ func (pattern *Pattern) FindAndLoad(path string, dest interface{}) (bool, error)
return false, nil return false, nil
} }
reflectedValue := reflect.ValueOf(dest) reflectedValue := reflect.ValueOf(strct)
if reflect.Ptr != reflectedValue.Kind() { if reflect.Ptr != reflectedValue.Kind() {
//@TODO: change error
return doesNotMatter, errExpectedAPointerToAStruct return doesNotMatter, errExpectedAPointerToAStruct
} }
reflectedValueElem := reflectedValue.Elem() reflectedValueElem := reflectedValue.Elem()
switch reflectedValueElem.Kind() {
case reflect.Slice:
var a []string = make([]string, len(args))
for i, arg := range args {
a[i] = *(arg.(*string))
}
return loadSlice(dest, a...)
case reflect.Struct:
return pattern.loadStruct(reflectedValueElem, args)
default:
//@TODO: change error
return doesNotMatter, errExpectedAPointerToAStruct
}
}
func loadSlice(dest interface{}, matches ...string) (bool, error) {
if nil == dest {
return false, errNilTarget
}
target, casted := dest.(*[]string)
if !casted {
//@TODO: CHANGE ERROR! ============================
return false, errExpectedAPointerToAStruct
}
if nil == target {
return false, errNilTarget
}
*target = (*target)[:0]
for _, match := range matches {
*target = append(*target, match)
}
return true, nil
}
func (pattern *Pattern) loadStruct(reflectedValueElem reflect.Value, args []interface{}) (bool, error) {
if nil == pattern {
return false, errNilReceiver
}
if reflect.Struct != reflectedValueElem.Kind() {
return doesNotMatter, errExpectedAPointerToAStruct
}
reflectedValueElemType := reflectedValueElem.Type() reflectedValueElemType := reflectedValueElem.Type()

View File

@ -4,13 +4,11 @@ package pathmatch
import ( import (
"github.com/fatih/structs" "github.com/fatih/structs"
"reflect"
"testing" "testing"
) )
func TestFindAndLoadStrucs(t *testing.T) { func TestFindAndLoad(t *testing.T) {
tests := []struct{ tests := []struct{
Pattern *Pattern Pattern *Pattern
@ -168,73 +166,3 @@ func TestFindAndLoadStrucs(t *testing.T) {
} }
} }
} }
func TestFindAndLoadStrings(t *testing.T) {
tests := []struct{
Pattern *Pattern
Path string
Expected []string
}{
{
Pattern: MustCompile("/user/{sessionKey}"),
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
Expected: []string{"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij"},
},
{
Pattern: MustCompile("/user/{sessionKey}/vehicle/{vehicleIdcode}/"),
Path: "/user/76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij/vehicle/DEFAULT/",
Expected: []string{
"76M6.mXQfgiGSC_YJ5uXSnWUmELbe8OgOm5n.iZ98Ij",
"DEFAULT",
},
},
{
Pattern: MustCompile("/{this}/{that}/{these}/{those}"),
Path: "/apple/banana/cherry/grape",
Expected: []string{
"apple",
"banana",
"cherry",
"grape",
},
},
}
for testNumber, test := range tests {
var actual []string
matched, err := test.Pattern.FindAndLoad(test.Path, &actual)
if nil != err {
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
t.Logf("\tPATTERN: %q", test.Pattern)
t.Logf("\tPATH: %q", test.Path)
continue
}
if !matched {
t.Errorf("For test #%d, expected a match, but it didn't.", testNumber)
t.Logf("\tPATTERN: %q", test.Pattern)
t.Logf("\tPATH: %q", test.Path)
t.Log("\t--")
t.Logf("\tMATCHED: %t", matched)
continue
}
if expected := test.Expected; !reflect.DeepEqual(expected, actual) {
t.Errorf("For test #%d, did not get what was expected.", testNumber)
t.Logf("\tPATTERN: %q", test.Pattern)
t.Logf("\tPATH: %q", test.Path)
t.Log("\t--")
t.Logf("\tEXPECTED: %#v", expected)
t.Logf("\tACTUAL: %#v", actual)
continue
}
}
}

View File

@ -1,23 +0,0 @@
package pathmatch
// Match returns true if path matches the compiled pattern, else returns false if it doesn't match.
func (receiver *Pattern) Match(path string) (bool, error) {
if nil == receiver {
return false, errNilReceiver
}
//@TODO: Is it a good idea to be dynamically creating this?
//@TODO: Also, can the struct fields be put in here directly instead?
args := []interface{}{}
numNames := len(receiver.MatchNames())
for i:=0; i<numNames; i++ {
args = append(args, new(string))
}
found, err := receiver.Find(path, args...)
if nil != err {
return false, err
}
return found, nil
}

View File

@ -1,366 +0,0 @@
package pathmatch_test
import (
"github.com/reiver/go-pathmatch"
"testing"
)
func TestPatternMatch(t *testing.T) {
tests := []struct{
Pattern string
Path string
Expected bool
}{
{
Pattern: "/v1/help",
Path: "/v1/help",
Expected: true,
},
{
Pattern: "/v1/help",
Path: "/v1/help/",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/help/me",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/help/me/",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/helping",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/helping/",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v2/help",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v2/HELP",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/apple",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/banana",
Expected: false,
},
{
Pattern: "/v1/help",
Path: "/v1/cherry",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/help/",
Expected: true,
},
{
Pattern: "/v1/help/",
Path: "/v1/help",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/help/me",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/help/me/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/helping",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/helping/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v2/help/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v2/HELP/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/apple/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/banana/",
Expected: false,
},
{
Pattern: "/v1/help/",
Path: "/v1/cherry/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1/user/123",
Expected: true,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1/user/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1/user/123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "//v1/user/123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1//user/123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1/user//123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "//v1//user/123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "/v1//user//123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "//v1//user//123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}",
Path: "//v1//user//123//",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1/user/123/",
Expected: true,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1/user/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1/user/123",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "//v1/user/123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1//user/123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1/user//123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "//v1//user/123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "/v1//user//123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "//v1//user//123/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/",
Path: "//v1//user//123//",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
Path: "/v1/user/123/contact/e-mail",
Expected: true,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
Path: "/v1/user/123/contact/e-mail/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
Path: "/v2/user/123/contact/e-mail",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}",
Path: "/v2/user/123/contact/e-mail",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
Path: "/v1/user/123/contact/e-mail/",
Expected: true,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
Path: "/v1/user/123/contact/e-mail",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
Path: "/v2/user/123/contact/e-mail/",
Expected: false,
},
{
Pattern: "/v1/user/{user_id}/contact/{contact_type}/",
Path: "/v2/user/123/contact/e-mail/",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}",
Path: "/v1/company/acme",
Expected: true,
},
{
Pattern: "/v1/company/{company_name}",
Path: "/v1/company/acme/",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}",
Path: "/v2/company/acme",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}",
Path: "/v1/user/acme",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}",
Path: "/v1/COMPANY/acme",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}/",
Path: "/v1/company/acme/",
Expected: true,
},
{
Pattern: "/v1/company/{company_name}/",
Path: "/v1/company/acme",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}/",
Path: "/v2/company/acme/",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}/",
Path: "/v1/user/acme/",
Expected: false,
},
{
Pattern: "/v1/company/{company_name}/",
Path: "/v1/COMPANY/acme/",
Expected: false,
},
}
for testNumber, test := range tests {
var pattern pathmatch.Pattern
if err := pathmatch.CompileTo(&pattern, test.Pattern); nil != err {
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
t.Errorf("\t: PATTERN: %q", test.Pattern)
t.Errorf("\t: PATH: %q", test.Path)
t.Errorf("\t: EXPECTED: %t", test.Expected)
continue
}
matched, err := pattern.Match(test.Path)
if nil != err {
t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %q", testNumber, err, err)
t.Errorf("\t: PATTERN: %q", test.Pattern)
t.Errorf("\t: PATH: %q", test.Path)
t.Errorf("\t: EXPECTED: %t", test.Expected)
continue
}
if expected, actual := test.Expected, matched; expected != actual {
t.Errorf("For test #%d, expected %t, but actually got %t.", testNumber, expected, actual)
t.Errorf("\t: PATTERN: %q", test.Pattern)
t.Errorf("\t: PATH: %q", test.Path)
t.Errorf("\t: EXPECTED: %t", test.Expected)
continue
}
}
}

View File

@ -1,8 +0,0 @@
package pathmatch
// String makes pathmatch.Pattern fit the fmt.Stringer interface.
//
// String returns the (pre-compiled) pattern template.
func (receiver Pattern) String() string {
return receiver.template
}