github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/internal/filter/filter_test.go (about) 1 package filter_test 2 3 import ( 4 "bufio" 5 "compress/bzip2" 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/restic/restic/internal/filter" 13 ) 14 15 var matchTests = []struct { 16 pattern string 17 path string 18 match bool 19 }{ 20 {"", "", true}, 21 {"", "foo", true}, 22 {"", "/x/y/z/foo", true}, 23 {"*.go", "/foo/bar/test.go", true}, 24 {"*.c", "/foo/bar/test.go", false}, 25 {"*", "/foo/bar/test.go", true}, 26 {"foo*", "/foo/bar/test.go", true}, 27 {"bar*", "/foo/bar/test.go", true}, 28 {"/bar*", "/foo/bar/test.go", false}, 29 {"bar/*", "/foo/bar/test.go", true}, 30 {"baz/*", "/foo/bar/test.go", false}, 31 {"bar/test.go", "/foo/bar/test.go", true}, 32 {"bar/*.go", "/foo/bar/test.go", true}, 33 {"ba*/*.go", "/foo/bar/test.go", true}, 34 {"bb*/*.go", "/foo/bar/test.go", false}, 35 {"test.*", "/foo/bar/test.go", true}, 36 {"tesT.*", "/foo/bar/test.go", false}, 37 {"bar/*", "/foo/bar/baz", true}, 38 {"bar", "/foo/bar", true}, 39 {"/foo/bar", "/foo/bar", true}, 40 {"/foo/bar/", "/foo/bar", true}, 41 {"/foo/bar", "/foo/baz", false}, 42 {"/foo/bar", "/foo/baz/", false}, 43 {"/foo///bar", "/foo/bar", true}, 44 {"/foo/../bar", "/foo/bar", false}, 45 {"/foo/../bar", "/bar", true}, 46 {"/foo", "/foo/baz", true}, 47 {"/foo/", "/foo/baz", true}, 48 {"/foo/*", "/foo", false}, 49 {"/foo/*", "/foo/baz", true}, 50 {"bar", "/foo/bar/baz", true}, 51 {"bar", "/foo/bar/test.go", true}, 52 {"/foo/*test.*", "/foo/bar/test.go", false}, 53 {"/foo/*/test.*", "/foo/bar/test.go", true}, 54 {"/foo/*/bar/test.*", "/foo/bar/test.go", false}, 55 {"/*/*/bar/test.*", "/foo/bar/test.go", false}, 56 {"/*/*/bar/test.*", "/foo/bar/baz/test.go", false}, 57 {"/*/*/baz/test.*", "/foo/bar/baz/test.go", true}, 58 {"/*/foo/bar/test.*", "/foo/bar/baz/test.go", false}, 59 {"/*/foo/bar/test.*", "/foo/bar/baz/test.go", false}, 60 {"/foo/bar/test.*", "bar/baz/test.go", false}, 61 {"/x/y/bar/baz/test.*", "bar/baz/test.go", false}, 62 {"/x/y/bar/baz/test.c", "bar/baz/test.go", false}, 63 {"baz/test.*", "bar/baz/test.go", true}, 64 {"baz/tesT.*", "bar/baz/test.go", false}, 65 {"test.go", "bar/baz/test.go", true}, 66 {"*.go", "bar/baz/test.go", true}, 67 {"*.c", "bar/baz/test.go", false}, 68 {"sdk", "/foo/bar/sdk", true}, 69 {"sdk", "/foo/bar/sdk/test/sdk_foo.go", true}, 70 { 71 "sdk/*/cpp/*/*vars*.html", 72 "/usr/share/doc/libreoffice/sdk/docs/cpp/ref/a00517.html", 73 false, 74 }, 75 {"foo/**/bar/*.go", "/home/user/foo/work/special/project/bar/test.go", true}, 76 {"foo/**/bar/*.go", "/home/user/foo/bar/test.go", true}, 77 {"foo/**/bar/*.go", "x/foo/bar/test.go", true}, 78 {"foo/**/bar/*.go", "foo/bar/test.go", true}, 79 {"foo/**/bar/*.go", "foo/bar/baz/bar/test.go", true}, 80 {"foo/**/bar/*.go", "/home/user/foo/test.c", false}, 81 {"foo/**/bar/*.go", "bar/foo/main.go", false}, 82 {"foo/**/bar/*.go", "/foo/bar/main.go", true}, 83 {"foo/**/bar/*.go", "bar/main.go", false}, 84 {"foo/**/bar", "/home/user/foo/x/y/bar", true}, 85 {"foo/**/bar", "/home/user/foo/x/y/bar/main.go", true}, 86 {"user/**/important*", "/home/user/work/x/y/hidden/x", false}, 87 {"user/**/hidden*/**/c", "/home/user/work/x/y/hidden/z/a/b/c", true}, 88 {"c:/foo/*test.*", "c:/foo/bar/test.go", false}, 89 {"c:/foo", "c:/foo/bar", true}, 90 {"c:/foo/", "c:/foo/bar", true}, 91 {"c:/foo/*/test.*", "c:/foo/bar/test.go", true}, 92 {"c:/foo/*/bar/test.*", "c:/foo/bar/test.go", false}, 93 } 94 95 func testpattern(t *testing.T, pattern, path string, shouldMatch bool) { 96 match, err := filter.Match(pattern, path) 97 if err != nil { 98 t.Errorf("test pattern %q failed: expected no error for path %q, but error returned: %v", 99 pattern, path, err) 100 } 101 102 if match != shouldMatch { 103 t.Errorf("test: filter.Match(%q, %q): expected %v, got %v", 104 pattern, path, shouldMatch, match) 105 } 106 } 107 108 func TestMatch(t *testing.T) { 109 for _, test := range matchTests { 110 testpattern(t, test.pattern, test.path, test.match) 111 112 // Test with native path separator 113 if filepath.Separator != '/' { 114 // Test with pattern as native 115 pattern := strings.Replace(test.pattern, "/", string(filepath.Separator), -1) 116 testpattern(t, pattern, test.path, test.match) 117 118 // Test with path as native 119 path := strings.Replace(test.path, "/", string(filepath.Separator), -1) 120 testpattern(t, test.pattern, path, test.match) 121 122 // Test with both pattern and path as native 123 testpattern(t, pattern, path, test.match) 124 } 125 } 126 } 127 128 var childMatchTests = []struct { 129 pattern string 130 path string 131 match bool 132 }{ 133 {"", "", true}, 134 {"", "/foo", true}, 135 {"", "/x/y/z/foo", true}, 136 {"foo/bar", "/foo", true}, 137 {"baz/bar", "/foo", true}, 138 {"foo", "/foo/bar", true}, 139 {"bar", "/foo", true}, 140 {"baz", "/foo/bar", true}, 141 {"*", "/foo", true}, 142 {"*", "/foo/bar", true}, 143 {"/foo/bar", "/foo", true}, 144 {"/foo/bar/baz", "/foo", true}, 145 {"/foo/bar/baz", "/foo/bar", true}, 146 {"/foo/bar/baz", "/foo/baz", false}, 147 {"/foo/**/baz", "/foo/bar/baz", true}, 148 {"/foo/**/baz", "/foo/bar/baz/blah", true}, 149 {"/foo/**/qux", "/foo/bar/baz/qux", true}, 150 {"/baz/bar", "/foo", false}, 151 {"/foo", "/foo/bar", true}, 152 {"/*", "/foo", true}, 153 {"/*", "/foo/bar", true}, 154 {"/foo", "/foo/bar", true}, 155 {"/**", "/foo", true}, 156 {"/*/**", "/foo", true}, 157 {"/*/**", "/foo/bar", true}, 158 {"/*/bar", "/foo", true}, 159 {"/bar/*", "/foo", false}, 160 {"/foo/*/baz", "/foo/bar", true}, 161 {"/foo/*/baz", "/foo/baz", true}, 162 {"/foo/*/baz", "/bar/baz", false}, 163 {"/**/*", "/foo", true}, 164 {"/**/bar", "/foo/bar", true}, 165 } 166 167 func testchildpattern(t *testing.T, pattern, path string, shouldMatch bool) { 168 match, err := filter.ChildMatch(pattern, path) 169 if err != nil { 170 t.Errorf("test child pattern %q failed: expected no error for path %q, but error returned: %v", 171 pattern, path, err) 172 } 173 174 if match != shouldMatch { 175 t.Errorf("test: filter.ChildMatch(%q, %q): expected %v, got %v", 176 pattern, path, shouldMatch, match) 177 } 178 } 179 180 func TestChildMatch(t *testing.T) { 181 for _, test := range childMatchTests { 182 testchildpattern(t, test.pattern, test.path, test.match) 183 184 // Test with native path separator 185 if filepath.Separator != '/' { 186 // Test with pattern as native 187 pattern := strings.Replace(test.pattern, "/", string(filepath.Separator), -1) 188 testchildpattern(t, pattern, test.path, test.match) 189 190 // Test with path as native 191 path := strings.Replace(test.path, "/", string(filepath.Separator), -1) 192 testchildpattern(t, test.pattern, path, test.match) 193 194 // Test with both pattern and path as native 195 testchildpattern(t, pattern, path, test.match) 196 } 197 } 198 } 199 200 func ExampleMatch() { 201 match, _ := filter.Match("*.go", "/home/user/file.go") 202 fmt.Printf("match: %v\n", match) 203 // Output: 204 // match: true 205 } 206 207 func ExampleMatch_wildcards() { 208 match, _ := filter.Match("/home/[uU]ser/?.go", "/home/user/F.go") 209 fmt.Printf("match: %v\n", match) 210 // Output: 211 // match: true 212 } 213 214 var filterListTests = []struct { 215 patterns []string 216 path string 217 match bool 218 }{ 219 {[]string{"*.go"}, "/foo/bar/test.go", true}, 220 {[]string{"*.c"}, "/foo/bar/test.go", false}, 221 {[]string{"*.go", "*.c"}, "/foo/bar/test.go", true}, 222 {[]string{"*"}, "/foo/bar/test.go", true}, 223 {[]string{"x"}, "/foo/bar/test.go", false}, 224 {[]string{"?"}, "/foo/bar/test.go", false}, 225 {[]string{"?", "x"}, "/foo/bar/x", true}, 226 {[]string{"/*/*/bar/test.*"}, "/foo/bar/test.go", false}, 227 {[]string{"/*/*/bar/test.*", "*.go"}, "/foo/bar/test.go", true}, 228 {[]string{"", "*.c"}, "/foo/bar/test.go", false}, 229 } 230 231 func TestList(t *testing.T) { 232 for i, test := range filterListTests { 233 match, _, err := filter.List(test.patterns, test.path) 234 if err != nil { 235 t.Errorf("test %d failed: expected no error for patterns %q, but error returned: %v", 236 i, test.patterns, err) 237 continue 238 } 239 240 if match != test.match { 241 t.Errorf("test %d: filter.MatchList(%q, %q): expected %v, got %v", 242 i, test.patterns, test.path, test.match, match) 243 } 244 } 245 } 246 247 func ExampleList() { 248 match, _, _ := filter.List([]string{"*.c", "*.go"}, "/home/user/file.go") 249 fmt.Printf("match: %v\n", match) 250 // Output: 251 // match: true 252 } 253 254 func extractTestLines(t testing.TB) (lines []string) { 255 f, err := os.Open("testdata/libreoffice.txt.bz2") 256 if err != nil { 257 t.Fatal(err) 258 } 259 260 defer func() { 261 if err := f.Close(); err != nil { 262 t.Fatal(err) 263 } 264 }() 265 266 sc := bufio.NewScanner(bzip2.NewReader(f)) 267 for sc.Scan() { 268 lines = append(lines, sc.Text()) 269 } 270 271 return lines 272 } 273 274 func TestFilterPatternsFile(t *testing.T) { 275 lines := extractTestLines(t) 276 277 var testPatterns = []struct { 278 pattern string 279 hits uint 280 }{ 281 {"*.html", 18249}, 282 {"sdk", 22186}, 283 {"sdk/*/cpp/*/*vars.html", 3}, 284 } 285 286 for _, test := range testPatterns { 287 var c uint 288 for _, line := range lines { 289 match, err := filter.Match(test.pattern, line) 290 if err != nil { 291 t.Error(err) 292 continue 293 } 294 295 if match { 296 c++ 297 // fmt.Printf("pattern %q, line %q\n", test.pattern, line) 298 } 299 } 300 301 if c != test.hits { 302 t.Errorf("wrong number of hits for pattern %q: want %d, got %d", 303 test.pattern, test.hits, c) 304 } 305 } 306 } 307 308 func BenchmarkFilterLines(b *testing.B) { 309 pattern := "sdk/*/cpp/*/*vars.html" 310 lines := extractTestLines(b) 311 var c uint 312 313 b.ResetTimer() 314 315 for i := 0; i < b.N; i++ { 316 c = 0 317 for _, line := range lines { 318 match, err := filter.Match(pattern, line) 319 if err != nil { 320 b.Fatal(err) 321 } 322 323 if match { 324 c++ 325 } 326 } 327 328 if c != 3 { 329 b.Fatalf("wrong number of matches: expected 3, got %d", c) 330 } 331 } 332 } 333 334 func BenchmarkFilterPatterns(b *testing.B) { 335 patterns := []string{ 336 "sdk/*", 337 "*.html", 338 } 339 lines := extractTestLines(b) 340 var c uint 341 342 b.ResetTimer() 343 344 for i := 0; i < b.N; i++ { 345 c = 0 346 for _, line := range lines { 347 match, _, err := filter.List(patterns, line) 348 if err != nil { 349 b.Fatal(err) 350 } 351 352 if match { 353 c++ 354 } 355 } 356 357 if c != 22185 { 358 b.Fatalf("wrong number of matches: expected 22185, got %d", c) 359 } 360 } 361 }