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

Configure Feed

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

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 112 // type 113 {"type:repo abc", &Type{Type: TypeRepo, Child: &Substring{Pattern: "abc"}}}, 114 {"type:file abc def", &Type{Type: TypeFileName, Child: NewAnd(&Substring{Pattern: "abc"}, &Substring{Pattern: "def"})}}, 115 {"(type:repo abc) def", NewAnd(&Type{Type: TypeRepo, Child: &Substring{Pattern: "abc"}}, &Substring{Pattern: "def"})}, 116 117 // errors. 118 {"--", nil}, 119 {"\"abc", nil}, 120 {"\"a\\", nil}, 121 {"case:foo", nil}, 122 123 {"sym:", nil}, 124 {"abc or", nil}, 125 {"or abc", nil}, 126 {"def or or abc", nil}, 127 128 {"", &Const{Value: true}}, 129 } { 130 got, err := Parse(c.in) 131 if (c.want == nil) != (err != nil) { 132 t.Errorf("Parse(%q): error %v, want %v", c.in, err, c.want) 133 } else if got != nil { 134 if !reflect.DeepEqual(got, c.want) { 135 t.Errorf("Parse(%s): got %v want %v", c.in, got, c.want) 136 } 137 } 138 } 139} 140 141func TestTokenize(t *testing.T) { 142 type testcase struct { 143 in string 144 typ int 145 text string 146 } 147 148 cases := []testcase{ 149 {"file:bla", tokFile, "bla"}, 150 {"file:bla ", tokFile, "bla"}, 151 {"f:bla ", tokFile, "bla"}, 152 {"(abc def) ", tokParenOpen, "("}, 153 {"(abcdef)", tokText, "(abcdef)"}, 154 {"(abc)(de)", tokText, "(abc)(de)"}, 155 {"(ab(c)def) ", tokText, "(ab(c)def)"}, 156 {"(ab\\ def) ", tokText, "(ab\\ def)"}, 157 {") ", tokParenClose, ")"}, 158 {"a(bc))", tokText, "a(bc)"}, 159 {"abc) ", tokText, "abc"}, 160 {"file:\"bla\"", tokFile, "bla"}, 161 {"\"file:bla\"", tokText, "file:bla"}, 162 {"\\", tokError, ""}, 163 {"o\"r\" bla", tokText, "or"}, 164 {"or bla", tokOr, "or"}, 165 {"ar bla", tokText, "ar"}, 166 } 167 for _, c := range cases { 168 tok, err := nextToken([]byte(c.in)) 169 if err != nil { 170 tok = &token{Type: tokError} 171 } 172 if tok.Type != c.typ { 173 t.Errorf("%s: got type %d, want %d", c.in, tok.Type, c.typ) 174 continue 175 } 176 177 if string(tok.Text) != c.text { 178 t.Errorf("%s: got text %q, want %q", c.in, tok.Text, c.text) 179 } 180 } 181} 182 183func TestMetaQueryParsing(t *testing.T) { 184 cases := []struct { 185 input string 186 field string 187 pattern string 188 err bool 189 }{ 190 { 191 input: "meta.visibility_level:20", 192 field: "visibility_level", 193 pattern: "20", 194 err: false, 195 }, 196 { 197 input: "meta.needle:ha.*stack", 198 field: "needle", 199 pattern: "ha.*stack", 200 err: false, 201 }, 202 { 203 input: "meta.public:true", 204 field: "public", 205 pattern: "true", 206 err: false, 207 }, 208 { 209 input: "meta.language:go", 210 field: "language", 211 pattern: "go", 212 err: false, 213 }, 214 { 215 input: "meta.invalid_field:(", 216 field: "invalid_field", 217 pattern: "(", 218 err: true, 219 }, 220 } 221 222 for _, c := range cases { 223 t.Run(c.input, func(t *testing.T) { 224 q, err := Parse(c.input) 225 if c.err { 226 if err == nil { 227 t.Errorf("expected error, got nil") 228 } 229 return 230 } 231 232 if err != nil { 233 t.Errorf("unexpected error: %v", err) 234 } 235 236 meta, ok := q.(*Meta) 237 if !ok || meta == nil { 238 t.Errorf("expected *Meta, got %T", q) 239 return 240 } 241 242 if meta.Field != c.field { 243 t.Errorf("expected field %q, got %q", c.field, meta.Field) 244 } 245 if meta.Value == nil || meta.Value.String() != c.pattern { 246 t.Errorf("expected pattern %q, got %v", c.pattern, meta.Value) 247 } 248 }) 249 } 250}