github.com/hattya/go.sh@v0.0.0-20240328132134-f53276d95cc6/pattern/pattern_test.go (about) 1 // 2 // go.sh/pattern :: pattern_test.go 3 // 4 // Copyright (c) 2021-2022 Akinori Hattori <hattya@gmail.com> 5 // 6 // SPDX-License-Identifier: MIT 7 // 8 9 package pattern_test 10 11 import ( 12 "os" 13 "path/filepath" 14 "reflect" 15 "strings" 16 "testing" 17 18 "github.com/hattya/go.sh/pattern" 19 ) 20 21 var matchTests = []struct { 22 patterns []string 23 mode pattern.Mode 24 s string 25 e string 26 }{ 27 {[]string{""}, 0, "", ""}, 28 {[]string{"", ""}, 0, "", ""}, 29 {[]string{"*.go"}, 0, "go.mod", ""}, 30 {[]string{"*.go"}, 0, "pattern.go", "pattern.go"}, 31 {[]string{"*.sw?"}, 0, ".pattern.go.swp", ".pattern.go.swp"}, 32 {[]string{"\\w"}, 0, "w", "w"}, 33 {[]string{"\\["}, 0, "[", "["}, 34 {[]string{"abc[lmn]xyz"}, 0, "abcmxyz", "abcmxyz"}, 35 {[]string{"abc[!lmn]xyz"}, 0, "abc-xyz", "abc-xyz"}, 36 {[]string{"[]\\-]"}, 0, "-", "-"}, 37 {[]string{"[[\\+]"}, 0, "+", "+"}, 38 {[]string{"[[:digit:]]"}, 0, "1", "1"}, 39 {[]string{"[[:digit]"}, 0, ":", ":"}, 40 41 {[]string{"/*"}, pattern.Smallest | pattern.Suffix, "foo", ""}, 42 {[]string{"/*"}, pattern.Smallest | pattern.Suffix, "foo/bar/baz", "/baz"}, 43 {[]string{"/*"}, pattern.Largest | pattern.Suffix, "foo", ""}, 44 {[]string{"/*"}, pattern.Largest | pattern.Suffix, "foo/bar/baz", "/bar/baz"}, 45 46 {[]string{"*/"}, pattern.Smallest | pattern.Prefix, "foo", ""}, 47 {[]string{"*/"}, pattern.Smallest | pattern.Prefix, "foo/bar/baz", "foo/"}, 48 {[]string{"*/"}, pattern.Largest | pattern.Prefix, "foo", ""}, 49 {[]string{"*/"}, pattern.Largest | pattern.Prefix, "foo/bar/baz", "foo/bar/"}, 50 51 {[]string{"*"}, pattern.Smallest | pattern.Suffix, "", ""}, 52 {[]string{"*"}, pattern.Smallest | pattern.Prefix, "", ""}, 53 {[]string{"*"}, pattern.Suffix | pattern.Prefix, "foo", ""}, 54 {[]string{"?"}, pattern.Smallest | pattern.Suffix, "\xf0\xff", "\xff"}, 55 {[]string{"?"}, pattern.Smallest | pattern.Prefix, "\xf0\xff", "\xf0"}, 56 } 57 58 func TestMatch(t *testing.T) { 59 for _, tt := range matchTests { 60 switch g, err := pattern.Match(tt.patterns, tt.mode, tt.s); { 61 case err != nil && err != pattern.NoMatch: 62 t.Error("unexpected error:", err) 63 case g != tt.e: 64 t.Errorf("expected %q, got %q", tt.e, g) 65 } 66 } 67 } 68 69 var matchErrorTests = [][]string{ 70 {"\xff"}, 71 {"\\"}, 72 {"\\\xff"}, 73 {"["}, 74 {"[\xff"}, 75 {"[\\"}, 76 {"[\\\xff"}, 77 {"[["}, 78 {"[[\xff"}, 79 {"[[\\"}, 80 } 81 82 func TestMatchError(t *testing.T) { 83 for _, patterns := range matchErrorTests { 84 if _, err := pattern.Match(patterns, 0, ""); err == nil { 85 t.Error("expected error") 86 } 87 } 88 } 89 90 var globTests = []struct { 91 pattern string 92 paths []string 93 }{ 94 {"*.go", []string{"a.go"}}, 95 {"[.a]*", []string{"a.go"}}, 96 {".*", []string{".", "..", ".git", ".gitignore"}}, 97 {"*", []string{"a.go", "bar", "baz", "foo"}}, 98 {"*/*", []string{"bar/a.go", "baz/a.go", "foo/a.go"}}, 99 {"foo/*", []string{"foo/a.go"}}, 100 {"foo//*", []string{"foo//a.go"}}, 101 {`foo\/*`, []string{"foo/a.go"}}, 102 {`foo/\*`, nil}, 103 {"_.go", nil}, 104 {"_/*", nil}, 105 {"_/_", nil}, 106 {".", []string{"."}}, 107 {"..", []string{".."}}, 108 {"", nil}, 109 110 {"${PATDIR}/*.go", []string{"${LITDIR}/a.go"}}, 111 {"${PATDIR}/.*", []string{"${LITDIR}/.", "${LITDIR}/..", "${LITDIR}/.git", "${LITDIR}/.gitignore"}}, 112 {"${PATDIR}/foo/*", []string{"${LITDIR}/foo/a.go"}}, 113 {"${PATDIR}/foo//*", []string{"${LITDIR}/foo//a.go"}}, 114 {`${PATDIR}/foo\/*`, []string{"${LITDIR}/foo/a.go"}}, 115 {`${PATDIR}/fo/\*`, nil}, 116 {"${PATDIR}/_.go", nil}, 117 {"${PATDIR}/_/*", nil}, 118 {"${PATDIR}/_/_", nil}, 119 {"${PATDIR}/", []string{"${LITDIR}/"}}, 120 {"${PATDIR}/.", []string{"${LITDIR}/."}}, 121 {"${PATDIR}/..", []string{"${LITDIR}/.."}}, 122 } 123 124 func TestGlob(t *testing.T) { 125 dir := t.TempDir() 126 popd, err := pushd(dir) 127 if err != nil { 128 t.Fatal(err) 129 } 130 defer popd() 131 132 for _, p := range []string{ 133 filepath.Join(".git", "config"), 134 ".gitignore", 135 "a.go", 136 filepath.Join("foo", "a.go"), 137 filepath.Join("bar", "a.go"), 138 filepath.Join("baz", "a.go"), 139 } { 140 if dir := filepath.Dir(p); dir != "" { 141 if err := mkdir(dir); err != nil { 142 t.Fatal(err) 143 } 144 } 145 if err := touch(p); err != nil { 146 t.Fatal(err) 147 } 148 } 149 150 mapper := func(k string) string { 151 switch k { 152 case "PATDIR": 153 return strings.ReplaceAll(dir, `\`, `\\`) 154 case "LITDIR": 155 return dir 156 } 157 return "" 158 } 159 for _, tt := range globTests { 160 g, err := pattern.Glob(os.Expand(tt.pattern, mapper)) 161 if err != nil { 162 t.Error("unexpected error:", err) 163 } 164 var e []string 165 for _, p := range tt.paths { 166 e = append(e, os.Expand(p, mapper)) 167 } 168 if !reflect.DeepEqual(g, e) { 169 t.Errorf("expected %#v, got %#v", e, g) 170 } 171 } 172 } 173 174 var globErrorTests = []string{ 175 "*\xff", 176 "_\xff", 177 } 178 179 func TestGlobError(t *testing.T) { 180 for _, pat := range globErrorTests { 181 if _, err := pattern.Glob(pat); err == nil { 182 t.Error("expected error") 183 } 184 } 185 } 186 187 func mkdir(s ...string) error { 188 return os.MkdirAll(filepath.Join(s...), 0o777) 189 } 190 191 func pushd(path string) (func() error, error) { 192 wd, err := os.Getwd() 193 popd := func() error { 194 if err != nil { 195 return err 196 } 197 return os.Chdir(wd) 198 } 199 return popd, os.Chdir(path) 200 } 201 202 func touch(s ...string) error { 203 return os.WriteFile(filepath.Join(s...), nil, 0o666) 204 }