// Mgmt // Copyright (C) James Shubin and the project contributors // Written by James Shubin and the project contributors // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Additional permission under GNU GPL version 3 section 7 // // If you modify this program, or any covered work, by linking or combining it // with embedded mcl code and modules (and that the embedded mcl code and // modules which link with this program, contain a copy of their source code in // the authoritative form) containing parts covered by the terms of any other // license, the licensors of this program grant you additional permission to // convey the resulting work. Furthermore, the licensors of this program grant // the original author, James Shubin, additional permission to update this // additional permission if he deems it necessary to achieve the goals of this // additional permission. package safepath import ( "fmt" "testing" ) func ExampleJoinToAbsFile() { absDir := UnsafeParseIntoAbsDir("/foo/bar/") relFile := UnsafeParseIntoRelFile("baz") fmt.Println(JoinToAbsFile(absDir, relFile).String()) // Output: /foo/bar/baz } func ExampleJoinToAbsDir() { absDir := UnsafeParseIntoAbsDir("/foo/bar/") relDir := UnsafeParseIntoRelDir("baz/") fmt.Println(JoinToAbsDir(absDir, relDir).String()) // Output: /foo/bar/baz/ } func ExampleJoinToRelFile() { relDir := UnsafeParseIntoRelDir("foo/bar/") relFile := UnsafeParseIntoRelFile("baz") fmt.Println(JoinToRelFile(relDir, relFile).String()) // Output: foo/bar/baz } func ExampleJoinToRelDir() { relDir1 := UnsafeParseIntoRelDir("foo/") relDir2 := UnsafeParseIntoRelDir("bar/") relDir3 := UnsafeParseIntoRelDir("baz/") fmt.Println(JoinToRelDir(relDir1, relDir2, relDir3).String()) // Output: foo/bar/baz/ } func TestAbsFileParse(t *testing.T) { tests := []struct { AbsFile string Expect error }{ { AbsFile: "", Expect: fmt.Errorf("path is empty"), }, { AbsFile: "/", // root is an abs dir Expect: fmt.Errorf("path is not a file"), }, { AbsFile: "//", Expect: fmt.Errorf("path is not a file"), }, { AbsFile: "./", Expect: fmt.Errorf("file is not absolute"), }, { AbsFile: ".", Expect: fmt.Errorf("file is not absolute"), }, { AbsFile: "/../../", Expect: fmt.Errorf("path is not a file"), }, { AbsFile: "../../", Expect: fmt.Errorf("file is not absolute"), }, { AbsFile: "/foo/bar/baz", Expect: nil, }, { AbsFile: "foo/bar/baz", // this is rel Expect: fmt.Errorf("file is not absolute"), }, } for _, x := range tests { _, err := ParseIntoAbsFile(x.AbsFile) if err == nil && x.Expect == nil { continue } if (err == nil) != (x.Expect == nil) { t.Errorf("%s exp: %+v, got: %+v", x.AbsFile, x.Expect, err) continue } if s1, s2 := x.Expect.Error(), err.Error(); s1 != s2 { t.Errorf("%s exp: %+v, got: %+v", x.AbsFile, s1, s2) } } } func TestAbsDirParse(t *testing.T) { tests := []struct { AbsDir string Expect error }{ { AbsDir: "", Expect: fmt.Errorf("path is empty"), }, { AbsDir: "/", // root is an abs dir Expect: nil, }, { AbsDir: "//", Expect: nil, // TODO: should this pass? }, { AbsDir: "./", Expect: fmt.Errorf("dir is not absolute"), }, { AbsDir: ".", Expect: fmt.Errorf("dir is not absolute"), }, { AbsDir: "/../../", Expect: nil, // TODO: should this pass? }, { AbsDir: "../../", Expect: fmt.Errorf("dir is not absolute"), }, { AbsDir: "/foo/bar/baz/", Expect: nil, }, { AbsDir: "/foo/bar/baz", // omitting the trailing slash is ok Expect: nil, }, { AbsDir: "foo/bar/baz", // this is rel Expect: fmt.Errorf("dir is not absolute"), }, } for _, x := range tests { _, err := ParseIntoAbsDir(x.AbsDir) if err == nil && x.Expect == nil { continue } if (err == nil) != (x.Expect == nil) { t.Errorf("%s exp: %+v, got: %+v", x.AbsDir, x.Expect, err) continue } if s1, s2 := x.Expect.Error(), err.Error(); s1 != s2 { t.Errorf("%s exp: %+v, got: %+v", x.AbsDir, s1, s2) } } } func TestRelFileParse(t *testing.T) { tests := []struct { RelFile string Expect error }{ //{ // RelFile: "", // Expect: nil, // TODO: should this pass? //}, { RelFile: "/", // root is an abs dir Expect: fmt.Errorf("file is not relative"), }, { RelFile: "//", Expect: fmt.Errorf("file is not relative"), }, { // this is seen as a file named: . RelFile: ".", Expect: nil, }, { // this is seen as a file named: . // remember: the parser removes the trailing slash here RelFile: "./", Expect: nil, }, { RelFile: "/../../", Expect: fmt.Errorf("file is not relative"), }, { // this is seen as a file named: .. RelFile: "..", Expect: nil, }, { // this is seen as a file named: .. // remember: the parser removes the trailing slash here RelFile: "../../", Expect: nil, }, { // this is seen as a file named: ... RelFile: "...", Expect: nil, }, { RelFile: "/foo/bar/baz/", Expect: fmt.Errorf("file is not relative"), }, { RelFile: "foo/bar/baz", Expect: nil, }, } for _, x := range tests { _, err := ParseIntoRelFile(x.RelFile) if err == nil && x.Expect == nil { continue } if (err == nil) != (x.Expect == nil) { t.Errorf("%s exp: %+v, got: %+v", x.RelFile, x.Expect, err) continue } if s1, s2 := x.Expect.Error(), err.Error(); s1 != s2 { t.Errorf("%s exp: %+v, got: %+v", x.RelFile, s1, s2) } } } func TestRelDirParse(t *testing.T) { tests := []struct { RelDir string Expect error }{ { RelDir: "", Expect: fmt.Errorf("path is empty"), }, { RelDir: "/", // root is an abs dir Expect: fmt.Errorf("dir is not relative"), }, { RelDir: "//", Expect: fmt.Errorf("dir is not relative"), }, { RelDir: "./", Expect: nil, }, { RelDir: ".", // remember, the parser adds a slash here Expect: nil, }, { RelDir: "/../../", Expect: fmt.Errorf("dir is not relative"), }, { RelDir: "../../", Expect: nil, }, { RelDir: "foo/bar/baz/", Expect: nil, }, { RelDir: "foo/bar/baz", // omitting the trailing slash is ok Expect: nil, }, } for _, x := range tests { _, err := ParseIntoRelDir(x.RelDir) if err == nil && x.Expect == nil { continue } if (err == nil) != (x.Expect == nil) { t.Errorf("%s exp: %+v, got: %+v", x.RelDir, x.Expect, err) continue } if s1, s2 := x.Expect.Error(), err.Error(); s1 != s2 { t.Errorf("%s exp: %+v, got: %+v", x.RelDir, s1, s2) } } } func TestAbsFileHasDir(t *testing.T) { tests := []struct { AbsFile string Has string Expect bool }{ //{ // AbsFile: "/foo", // Has: "", // not currently permitted // Expect: false, //}, { AbsFile: "/foo/bar/baz", Has: "x/", Expect: false, }, { AbsFile: "/foo/bar/baz", Has: "bar/", Expect: true, }, { AbsFile: "/foo/bar/baz", Has: "bar/baz/", // baz is a file, not a dir! Expect: false, }, { AbsFile: "/foo/bar/baz", Has: "foo/bar/", // this one is sneaky for the brain Expect: true, }, { AbsFile: "/foo/bar/baz", Has: "foo/bar/b", Expect: false, }, } for _, x := range tests { absFile := UnsafeParseIntoAbsFile(x.AbsFile) has := UnsafeParseIntoRelDir(x.Has) if out := absFile.HasDir(has); x.Expect != out { t.Errorf("%s HasDir %s exp: %+v, got: %+v", x.AbsFile, x.Has, x.Expect, out) } } } func TestAbsDirHasDir(t *testing.T) { tests := []struct { AbsDir string Has string Expect bool }{ //{ // AbsDir: "/", // Has: "", // empty path is not supported, should it? // Expect: false, //}, //{ // AbsDir: "/whatever", // Has: "/", // not a rel dir! // Expect: false, //}, { AbsDir: "/abc/def/ghi", Has: "x/", Expect: false, }, { AbsDir: "/abc/def/ghi", Has: "def/", Expect: true, }, { AbsDir: "/abc/def/ghi", Has: "ghi/", Expect: true, }, { AbsDir: "/abc/def/ghi", Has: "def/ghi/", Expect: true, }, { AbsDir: "/abc/def/ghi", Has: "c/def/ghi/", // c is not a whole dir! Expect: false, }, { AbsDir: "/abc/def/ghi", Has: "bc/def/ghi/", // bc is not a whole dir! Expect: false, }, { AbsDir: "/abc/def/ghi", Has: "abc/def/ghi/", Expect: true, }, { AbsDir: "/abc/def/ghi", Has: "def/gh/", Expect: false, }, } for _, x := range tests { absDir := UnsafeParseIntoAbsDir(x.AbsDir) has := UnsafeParseIntoRelDir(x.Has) if out := absDir.HasDir(has); x.Expect != out { t.Errorf("%s HasDir %s exp: %+v, got: %+v", x.AbsDir, x.Has, x.Expect, out) } } } func TestRelFileHasDir(t *testing.T) { tests := []struct { RelFile string Has string Expect bool }{ //{ // RelFile: "/foo", // Has: "", // not currently permitted // Expect: false, //}, { RelFile: "foo", Has: "foo/", Expect: false, }, { RelFile: "foo/bar/baz", Has: "x/", Expect: false, }, { RelFile: "foo/bar/baz", Has: "bar/", Expect: true, }, { RelFile: "foo/bar/baz", Has: "baz/", Expect: false, // baz is a file, not a dir }, { RelFile: "foo/bar/baz", Has: "bar/baz/", Expect: false, // baz is a file, not a dir }, { RelFile: "foo/bar/baz", Has: "bar/b/", Expect: false, }, } for _, x := range tests { relFile := UnsafeParseIntoRelFile(x.RelFile) has := UnsafeParseIntoRelDir(x.Has) if out := relFile.HasDir(has); x.Expect != out { t.Errorf("%s HasDir %s exp: %+v, got: %+v", x.RelFile, x.Has, x.Expect, out) } } } func TestRelDirHasDir(t *testing.T) { tests := []struct { RelDir string Has string Expect bool }{ //{ // RelDir: "foo/", // Has: "", // not currently permitted // Expect: false, //}, { RelDir: "foo/bar/baz/", Has: "x/", Expect: false, }, { RelDir: "foo/bar/baz/", Has: "bar/", Expect: true, }, { RelDir: "foo/bar/baz", // omitting the trailing slash is ok Has: "bar/baz/", Expect: true, }, { RelDir: "foo/bar/baz/", Has: "bar/baz/", Expect: true, }, { RelDir: "foo/bar/baz/", Has: "bar/ba", // omitting the trailing slash is ok Expect: false, }, } for _, x := range tests { relDir := UnsafeParseIntoRelDir(x.RelDir) has := UnsafeParseIntoRelDir(x.Has) if out := relDir.HasDir(has); x.Expect != out { t.Errorf("%s HasDir %s exp: %+v, got: %+v", x.RelDir, x.Has, x.Expect, out) } } } func TestPathHasPrefix(t *testing.T) { tests := []struct { Path string // obey slash conventions Prefix string // Dir Expect bool }{ //{ // Path: "/foo/bar/baz", // Prefix: "", // not currently permitted // Expect: true, //}, { Path: "/foo/bar/baz/ff", // absfile Prefix: "/foo/", Expect: true, }, { Path: "/foo/bar/baz/ff", Prefix: "foo/", Expect: false, // an abs dir can't have a rel dir prefix }, { Path: "/foo/bar/baz/ff", Prefix: "foo/bar/", Expect: false, }, { Path: "/foo/bar/baz/ff", Prefix: "foo/bar/baz/", Expect: false, }, { Path: "/foo/bar/baz/ff", Prefix: "foo/barb", Expect: false, }, { Path: "/foo/bar/baz/ff", Prefix: "/foo/", Expect: true, }, { Path: "/foo/bar/baz/ff", Prefix: "/foo/bar/", Expect: true, }, { Path: "/foo/bar/baz/ff", Prefix: "/foo/bar/baz/", Expect: true, }, { Path: "/foo/bar/baz/", // absdir Prefix: "/foo/", Expect: true, }, { Path: "/foo/bar/baz/", Prefix: "foo/bar/", Expect: false, }, { Path: "foo/bar/baz/", Prefix: "foo/bar/baz/", Expect: true, }, { Path: "foo/bar/baz/", Prefix: "foo/barb", Expect: false, }, { Path: "foo/bar/baz/ff", // relfile Prefix: "/foo/", Expect: false, }, { Path: "foo/bar/baz/ff", Prefix: "foo/bar/", Expect: true, }, { Path: "foo/bar/baz/ff", Prefix: "foo/bar/baz/", Expect: true, }, { Path: "foo/bar/baz/ff", Prefix: "foo/barb", Expect: false, }, { Path: "foo/bar/baz/", // reldir Prefix: "foo/", Expect: true, }, { Path: "foo/bar/baz/", Prefix: "foo/bar/", Expect: true, }, { Path: "foo/bar/baz/", Prefix: "foo/bar/baz/", Expect: true, }, { Path: "foo/bar/baz/", Prefix: "foo/barb", Expect: false, }, } for _, x := range tests { path := UnsafeSmartParseIntoPath(x.Path) prefix := UnsafeParseIntoDir(x.Prefix) if out := HasPrefix(path, prefix); x.Expect != out { t.Errorf("%s HasPrefix %s exp: %+v, got: %+v", x.Path, x.Prefix, x.Expect, out) } } } func TestAbsFile(t *testing.T) { tests := []struct { AbsFile string Base string // relfile Dir string // absdir }{ // not possible afaict //{ // AbsFile: "/", // Base: "", // Dir: "/", //}, //{ // AbsFile: "", // Base: "", // Dir: "", //}, { AbsFile: "/abc/def/ghi", Base: "ghi", Dir: "/abc/def/", }, { AbsFile: "/x", Base: "x", Dir: "/", }, { AbsFile: "/abc", Base: "abc", Dir: "/", }, { AbsFile: "/abc/def", Base: "def", Dir: "/abc/", }, } for _, x := range tests { absFile := UnsafeParseIntoAbsFile(x.AbsFile) base := UnsafeParseIntoRelFile(x.Base) dir := UnsafeParseIntoAbsDir(x.Dir) if out := absFile.Base(); base.Path() != out.Path() { t.Errorf("%s exp base: %+v, got: %+v", x.AbsFile, base.Path(), out.Path()) } if out := absFile.Dir(); dir.Path() != out.Path() { t.Errorf("%s exp dir: %+v, got: %+v", x.AbsFile, dir.Path(), out.Path()) } } }