From 74d8de8fc22c277215873f27868ebc63fa481ee7 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Fri, 29 Sep 2023 20:55:13 +0600 Subject: [PATCH] :technologist: Created ShiftPath urlutil --- internal/urlutil/shift_path.go | 22 +++++++++++++++++ internal/urlutil/shift_path_test.go | 37 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 internal/urlutil/shift_path.go create mode 100644 internal/urlutil/shift_path_test.go diff --git a/internal/urlutil/shift_path.go b/internal/urlutil/shift_path.go new file mode 100644 index 0000000..39dbf71 --- /dev/null +++ b/internal/urlutil/shift_path.go @@ -0,0 +1,22 @@ +package urlutil + +import ( + "path" + "strings" +) + +// ShiftPath splits off the first component of p, which will be cleaned of +// relative components before processing. head will never contain a slash and +// tail will always be a rooted path without trailing slash. +// +// See: https://blog.merovius.de/posts/2017-06-18-how-not-to-use-an-http-router/ +func ShiftPath(p string) (head, tail string) { + p = path.Clean("/" + p) + + i := strings.Index(p[1:], "/") + 1 + if i <= 0 { + return p[1:], "/" + } + + return p[1:i], p[i:] +} diff --git a/internal/urlutil/shift_path_test.go b/internal/urlutil/shift_path_test.go new file mode 100644 index 0000000..c0a32f2 --- /dev/null +++ b/internal/urlutil/shift_path_test.go @@ -0,0 +1,37 @@ +package urlutil_test + +import ( + "testing" + + "source.toby3d.me/toby3d/pub/internal/urlutil" +) + +func TestShiftPath(t *testing.T) { + t.Parallel() + + for name, tc := range map[string]struct { + input, expHead, expTail string + }{ + "root": {input: "/", expHead: "", expTail: "/"}, + "file": {input: "/foo", expHead: "foo", expTail: "/"}, + "dir": {input: "/foo/", expHead: "foo", expTail: "/"}, + "dirfile": {input: "/foo/bar", expHead: "foo", expTail: "/bar"}, + "subdir": {input: "/foo/bar/", expHead: "foo", expTail: "/bar"}, + } { + name, tc := name, tc + + t.Run(name, func(t *testing.T) { + t.Parallel() + + head, tail := urlutil.ShiftPath(tc.input) + + if head != tc.expHead { + t.Errorf("ShiftPath(%s) = '%s', want '%s'", tc.input, head, tc.expHead) + } + + if tail != tc.expTail { + t.Errorf("ShiftPath(%s) = '%s', want '%s'", tc.input, tail, tc.expTail) + } + }) + } +}