fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 8.5 kB View raw
1// Copyright 2016 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package query 16 17import ( 18 "log" 19 "reflect" 20 "regexp/syntax" 21 "testing" 22 23 "github.com/grafana/regexp" 24) 25 26func mustParseRE(s string) *syntax.Regexp { 27 r, err := syntax.Parse(s, regexpFlags) 28 if err != nil { 29 log.Panicf("parsing %q: %v", s, err) 30 } 31 return r 32} 33 34func TestParseQuery(t *testing.T) { 35 type testcase struct { 36 in string 37 want Q 38 } 39 40 for _, c := range []testcase{ 41 {`\bword\b`, &Regexp{Regexp: mustParseRE(`\bword\b`)}}, 42 {"fi\"le:bla\"", &Substring{Pattern: "file:bla"}}, 43 {"abc or def", NewOr(&Substring{Pattern: "abc"}, &Substring{Pattern: "def"})}, 44 {"(abc or def)", NewOr(&Substring{Pattern: "abc"}, &Substring{Pattern: "def"})}, 45 {"(ppp qqq or rrr sss)", NewOr( 46 NewAnd(&Substring{Pattern: "ppp"}, &Substring{Pattern: "qqq"}), 47 NewAnd(&Substring{Pattern: "rrr"}, &Substring{Pattern: "sss"}))}, 48 {"((x) ora b(z(d)))", NewAnd( 49 &Substring{Pattern: "x"}, 50 &Substring{Pattern: "ora"}, 51 &Substring{Pattern: "bzd"})}, 52 {"( )", &Const{Value: true}}, 53 {"(abc)(de)", &Substring{Pattern: "abcde"}}, 54 {"sub-pixel", &Substring{Pattern: "sub-pixel"}}, 55 {"abc", &Substring{Pattern: "abc"}}, 56 {"ABC", &Substring{Pattern: "ABC", CaseSensitive: true}}, 57 {"\"abc bcd\"", &Substring{Pattern: "abc bcd"}}, 58 {"abc bcd", NewAnd( 59 &Substring{Pattern: "abc"}, 60 &Substring{Pattern: "bcd"})}, 61 {"f:fs", &Substring{Pattern: "fs", FileName: true}}, 62 {"fs", &Substring{Pattern: "fs"}}, 63 {"-abc", &Not{&Substring{Pattern: "abc"}}}, 64 {"abccase:yes", &Substring{Pattern: "abccase:yes"}}, 65 {"file:abc", &Substring{Pattern: "abc", FileName: true}}, 66 {"branch:pqr", &Branch{Pattern: "pqr"}}, 67 {"((x|y) )", &Regexp{Regexp: mustParseRE("[xy]")}}, 68 {"archived:yes", RawConfig(RcOnlyArchived)}, 69 {"archived:no", RawConfig(RcNoArchived)}, 70 {"fork:yes", RawConfig(RcOnlyForks)}, 71 {"fork:no", RawConfig(RcNoForks)}, 72 {"public:yes", RawConfig(RcOnlyPublic)}, 73 {"public:no", RawConfig(RcOnlyPrivate)}, 74 {"file:helpers\\.go byte", NewAnd( 75 &Substring{Pattern: "helpers.go", FileName: true}, 76 &Substring{Pattern: "byte"})}, 77 {"(abc def)", NewAnd( 78 &Substring{Pattern: "abc"}, 79 &Substring{Pattern: "def"})}, 80 {"(abc def", nil}, 81 {"regex:abc[p-q]", &Regexp{Regexp: mustParseRE("abc[p-q]")}}, 82 {"aBc[p-q]", &Regexp{Regexp: mustParseRE("aBc[p-q]"), CaseSensitive: true}}, 83 {"aBc[p-q] case:auto", &Regexp{Regexp: mustParseRE("aBc[p-q]"), CaseSensitive: true}}, 84 {"repo:go", &Repo{regexp.MustCompile("go")}}, 85 {"repo:.*", &Repo{Regexp: regexp.MustCompile(".*")}}, 86 87 {"file:\"\"", &Const{true}}, 88 {"abc.*def", &Regexp{Regexp: mustParseRE("abc.*def")}}, 89 {"abc\\.\\*def", &Substring{Pattern: "abc.*def"}}, 90 {"(abc)", &Substring{Pattern: "abc"}}, 91 92 {"c:abc", &Substring{Pattern: "abc", Content: true}}, 93 {"content:abc", &Substring{Pattern: "abc", Content: true}}, 94 95 {"lang:c++", &Language{"C++"}}, 96 {"lang:cpp", &Language{"C++"}}, 97 {"sym:pqr", &Symbol{&Substring{Pattern: "pqr"}}}, 98 {"sym:Pqr", &Symbol{&Substring{Pattern: "Pqr", CaseSensitive: true}}}, 99 {"sym:.*", &Symbol{&Regexp{Regexp: mustParseRE(".*")}}}, 100 {"sym:a(b|d)e", &Symbol{&Regexp{Regexp: mustParseRE("a[bd]e")}}}, 101 102 // case 103 {"abc case:yes", &Substring{Pattern: "abc", CaseSensitive: true}}, 104 {"abc case:auto", &Substring{Pattern: "abc", CaseSensitive: false}}, 105 {"ABC case:auto", &Substring{Pattern: "ABC", CaseSensitive: true}}, 106 {"ABC case:\"auto\"", &Substring{Pattern: "ABC", CaseSensitive: true}}, 107 {"abc -f:def case:yes", NewAnd( 108 &Substring{Pattern: "abc", CaseSensitive: true}, 109 &Not{Child: &Substring{Pattern: "def", FileName: true, CaseSensitive: true}}, 110 )}, 111 {"(foo case:yes) bar", NewAnd( 112 &Substring{Pattern: "foo", CaseSensitive: true}, 113 &Substring{Pattern: "bar"}, 114 )}, 115 {"(case:yes foo) bar", NewAnd( 116 &Substring{Pattern: "foo", CaseSensitive: true}, 117 &Substring{Pattern: "bar"}, 118 )}, 119 {"(case:yes foo (bar))", NewAnd( 120 &Substring{Pattern: "foo", CaseSensitive: true}, 121 &Substring{Pattern: "bar", CaseSensitive: true}, 122 )}, 123 {"case:auto (foo case:yes) bar", NewAnd( 124 &Substring{Pattern: "foo", CaseSensitive: true}, 125 &Substring{Pattern: "bar"}, 126 )}, 127 {"case:yes (foo case:no) bar", NewAnd( 128 &Substring{Pattern: "foo"}, 129 &Substring{Pattern: "bar", CaseSensitive: true}, 130 )}, 131 132 // type 133 {"type:repo abc", &Type{Type: TypeRepo, Child: &Substring{Pattern: "abc"}}}, 134 {"type:file abc def", &Type{Type: TypeFileName, Child: NewAnd(&Substring{Pattern: "abc"}, &Substring{Pattern: "def"})}}, 135 {"type:repo foo or bar", &Type{Type: TypeRepo, Child: NewOr(&Substring{Pattern: "foo"}, &Substring{Pattern: "bar"})}}, 136 {"(type:repo abc) def", NewAnd(&Type{Type: TypeRepo, Child: &Substring{Pattern: "abc"}}, &Substring{Pattern: "def"})}, 137 138 // errors. 139 {"--", nil}, 140 {"\"abc", nil}, 141 {"\"a\\", nil}, 142 {"case:foo", nil}, 143 144 {"sym:", nil}, 145 {"abc or", nil}, 146 {"or abc", nil}, 147 {"def or or abc", nil}, 148 {"type:repo or", nil}, 149 {"or type:repo", nil}, 150 151 // unbalanced parentheses 152 {"(", nil}, 153 {"((", nil}, 154 {"(((", nil}, 155 {")", nil}, 156 {"))", nil}, 157 {")))", nil}, 158 {"foo)", nil}, 159 {"foo))", nil}, 160 {"foo)))", nil}, 161 {"(foo", nil}, 162 {"((foo", nil}, 163 {"(((foo", nil}, 164 {"(foo))", nil}, 165 {"(((foo))", nil}, 166 167 {"", &Const{Value: true}}, 168 169 // whitespace 170 {" ( ) ", &Const{Value: true}}, 171 {" ( foo ) ", &Substring{Pattern: "foo"}}, 172 } { 173 got, err := Parse(c.in) 174 if (c.want == nil) != (err != nil) { 175 t.Errorf("Parse(%q): error %v, want %v", c.in, err, c.want) 176 } else if got != nil { 177 if !reflect.DeepEqual(got, c.want) { 178 t.Errorf("Parse(%s): got %v want %v", c.in, got, c.want) 179 } 180 } 181 } 182} 183 184func TestTokenize(t *testing.T) { 185 type testcase struct { 186 in string 187 typ int 188 text string 189 } 190 191 cases := []testcase{ 192 {"file:bla", tokFile, "bla"}, 193 {"file:bla ", tokFile, "bla"}, 194 {"f:bla ", tokFile, "bla"}, 195 {"(abc def) ", tokParenOpen, "("}, 196 {"(abcdef)", tokText, "(abcdef)"}, 197 {"(abc)(de)", tokText, "(abc)(de)"}, 198 {"(ab(c)def) ", tokText, "(ab(c)def)"}, 199 {"(ab\\ def) ", tokText, "(ab\\ def)"}, 200 {") ", tokParenClose, ")"}, 201 {"a(bc))", tokText, "a(bc)"}, 202 {"abc) ", tokText, "abc"}, 203 {"file:\"bla\"", tokFile, "bla"}, 204 {"\"file:bla\"", tokText, "file:bla"}, 205 {"\\", tokError, ""}, 206 {"o\"r\" bla", tokText, "or"}, 207 {"or bla", tokOr, "or"}, 208 {"ar bla", tokText, "ar"}, 209 } 210 for _, c := range cases { 211 tok, err := nextToken([]byte(c.in)) 212 if err != nil { 213 tok = &token{Type: tokError} 214 } 215 if tok.Type != c.typ { 216 t.Errorf("%s: got type %d, want %d", c.in, tok.Type, c.typ) 217 continue 218 } 219 220 if string(tok.Text) != c.text { 221 t.Errorf("%s: got text %q, want %q", c.in, tok.Text, c.text) 222 } 223 } 224} 225 226func TestMetaQueryParsing(t *testing.T) { 227 cases := []struct { 228 input string 229 field string 230 pattern string 231 err bool 232 }{ 233 { 234 input: "meta.visibility_level:20", 235 field: "visibility_level", 236 pattern: "20", 237 err: false, 238 }, 239 { 240 input: "meta.needle:ha.*stack", 241 field: "needle", 242 pattern: "ha.*stack", 243 err: false, 244 }, 245 { 246 input: "meta.public:true", 247 field: "public", 248 pattern: "true", 249 err: false, 250 }, 251 { 252 input: "meta.language:go", 253 field: "language", 254 pattern: "go", 255 err: false, 256 }, 257 { 258 input: "meta.invalid_field:(", 259 field: "invalid_field", 260 pattern: "(", 261 err: true, 262 }, 263 } 264 265 for _, c := range cases { 266 t.Run(c.input, func(t *testing.T) { 267 q, err := Parse(c.input) 268 if c.err { 269 if err == nil { 270 t.Errorf("expected error, got nil") 271 } 272 return 273 } 274 275 if err != nil { 276 t.Errorf("unexpected error: %v", err) 277 } 278 279 meta, ok := q.(*Meta) 280 if !ok || meta == nil { 281 t.Errorf("expected *Meta, got %T", q) 282 return 283 } 284 285 if meta.Field != c.field { 286 t.Errorf("expected field %q, got %q", c.field, meta.Field) 287 } 288 if meta.Value == nil || meta.Value.String() != c.pattern { 289 t.Errorf("expected pattern %q, got %v", c.pattern, meta.Value) 290 } 291 }) 292 } 293}