aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/lsp/glob/glob_test.go
blob: df602624d9cb6bca81e96c797cfc8b01f60e3bb7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package glob_test

import (
	"testing"

	"golang.org/x/tools/gopls/internal/lsp/glob"
)

func TestParseErrors(t *testing.T) {
	tests := []string{
		"***",
		"ab{c",
		"[]",
		"[a-]",
		"ab{c{d}",
	}

	for _, test := range tests {
		_, err := glob.Parse(test)
		if err == nil {
			t.Errorf("Parse(%q) succeeded unexpectedly", test)
		}
	}
}

func TestMatch(t *testing.T) {
	tests := []struct {
		pattern, input string
		want           bool
	}{
		// Basic cases.
		{"", "", true},
		{"", "a", false},
		{"", "/", false},
		{"abc", "abc", true},

		// ** behavior
		{"**", "abc", true},
		{"**/abc", "abc", true},
		{"**", "abc/def", true},
		{"{a/**/c,a/**/d}", "a/b/c", true},
		{"{a/**/c,a/**/d}", "a/b/c/d", true},
		{"{a/**/c,a/**/e}", "a/b/c/d", false},
		{"{a/**/c,a/**/e,a/**/d}", "a/b/c/d", true},
		{"{/a/**/c,a/**/e,a/**/d}", "a/b/c/d", true},
		{"{/a/**/c,a/**/e,a/**/d}", "/a/b/c/d", false},
		{"{/a/**/c,a/**/e,a/**/d}", "/a/b/c", true},
		{"{/a/**/e,a/**/e,a/**/d}", "/a/b/c", false},

		// * and ? behavior
		{"/*", "/a", true},
		{"*", "foo", true},
		{"*o", "foo", true},
		{"*o", "foox", false},
		{"f*o", "foo", true},
		{"f*o", "fo", true},
		{"fo?", "foo", true},
		{"fo?", "fox", true},
		{"fo?", "fooo", false},
		{"fo?", "fo", false},
		{"?", "a", true},
		{"?", "ab", false},
		{"?", "", false},
		{"*?", "", false},
		{"?b", "ab", true},
		{"?c", "ab", false},

		// {} behavior
		{"ab{c,d}e", "abce", true},
		{"ab{c,d}e", "abde", true},
		{"ab{c,d}e", "abxe", false},
		{"ab{c,d}e", "abe", false},
		{"{a,b}c", "ac", true},
		{"{a,b}c", "bc", true},
		{"{a,b}c", "ab", false},
		{"a{b,c}", "ab", true},
		{"a{b,c}", "ac", true},
		{"a{b,c}", "bc", false},
		{"ab{c{1,2},d}e", "abc1e", true},
		{"ab{c{1,2},d}e", "abde", true},
		{"ab{c{1,2},d}e", "abc1f", false},
		{"ab{c{1,2},d}e", "abce", false},
		{"ab{c[}-~]}d", "abc}d", true},
		{"ab{c[}-~]}d", "abc~d", true},
		{"ab{c[}-~],y}d", "abcxd", false},
		{"ab{c[}-~],y}d", "abyd", true},
		{"ab{c[}-~],y}d", "abd", false},
		{"{a/b/c,d/e/f}", "a/b/c", true},
		{"/ab{/c,d}e", "/ab/ce", true},
		{"/ab{/c,d}e", "/ab/cf", false},

		// [-] behavior
		{"[a-c]", "a", true},
		{"[a-c]", "b", true},
		{"[a-c]", "c", true},
		{"[a-c]", "d", false},
		{"[a-c]", " ", false},

		// Realistic examples.
		{"**/*.{ts,js}", "path/to/foo.ts", true},
		{"**/*.{ts,js}", "path/to/foo.js", true},
		{"**/*.{ts,js}", "path/to/foo.go", false},
	}

	for _, test := range tests {
		g, err := glob.Parse(test.pattern)
		if err != nil {
			t.Fatalf("New(%q) failed unexpectedly: %v", test.pattern, err)
		}
		if got := g.Match(test.input); got != test.want {
			t.Errorf("New(%q).Match(%q) = %t, want %t", test.pattern, test.input, got, test.want)
		}
	}
}