internal/control/querylang_test.go
112 lines · 4034 bytes
3 symbols in this file
1package control
2
3import (
4 "errors"
5 "reflect"
6 "testing"
7
8 "gitbay.org/gitbay/internal/store"
9)
10
11func TestParseItemQuery(t *testing.T) {
12 for _, tc := range []struct {
13 in []string
14 want ItemQuery
15 text string // canonical form
16 }{
17 {[]string{"repo:krz/gitbay"}, ItemQuery{Scopes: []store.RepoScope{{Owner: "krz", Name: "gitbay"}}}, "repo:krz/gitbay"},
18 {[]string{"repo:krz/git* owner:cmc"}, ItemQuery{Scopes: []store.RepoScope{{Owner: "krz", Name: "git*"}, {Owner: "cmc"}}}, "repo:krz/git* owner:cmc"},
19 {[]string{"repo:*", "is:open"}, ItemQuery{AnyRepo: true, State: "open"}, "repo:* is:open"},
20 {[]string{"is:merged"}, ItemQuery{State: "merged"}, "is:merged"},
21 {[]string{"is:open is:issue"}, ItemQuery{Kind: "issue", State: "open"}, "is:issue is:open"},
22 {[]string{"label:bug", "label:ui", "label:bug"}, ItemQuery{Labels: []string{"bug", "ui"}}, "label:bug label:ui"},
23 {[]string{`label:"needs review"`}, ItemQuery{Labels: []string{"needs review"}}, `label:"needs review"`},
24 {[]string{"label:needs review"}, ItemQuery{Labels: []string{"needs"}, Text: []string{"review"}}, "label:needs review"},
25 {[]string{"no:label no:milestone"}, ItemQuery{NoLabel: true, NoMilestone: true}, "no:label no:milestone"},
26 {[]string{"milestone:v2"}, ItemQuery{Milestone: "v2"}, "milestone:v2"},
27 {[]string{"assignee:@me author:cmc"}, ItemQuery{Assignee: "@me", Author: "cmc"}, "assignee:@me author:cmc"},
28 {[]string{"crash", `"on start"`, "is:open"}, ItemQuery{State: "open", Text: []string{"crash", "on start"}}, `is:open crash "on start"`},
29 {[]string{`"a:b"`}, ItemQuery{Text: []string{"a:b"}}, `"a:b"`},
30 } {
31 got, err := ParseItemQuery(tc.in...)
32 if err != nil {
33 t.Errorf("%q: %v", tc.in, err)
34 continue
35 }
36 if !reflect.DeepEqual(got, tc.want) {
37 t.Errorf("%q = %+v, want %+v", tc.in, got, tc.want)
38 }
39 if s := got.String(); s != tc.text {
40 t.Errorf("%q canonical = %q, want %q", tc.in, s, tc.text)
41 }
42 again, err := ParseItemQuery(got.String())
43 if err != nil || !reflect.DeepEqual(again, got) {
44 t.Errorf("%q does not survive its canonical form: %+v, %v", tc.in, again, err)
45 }
46 }
47}
48
49func TestParseItemQueryRefuses(t *testing.T) {
50 for _, tc := range []struct {
51 in, token string
52 }{
53 {"", ""},
54 {"foo:bar", "foo:bar"},
55 {"is:open is:bogus", "is:bogus"},
56 {"is:open is:closed", "is:closed"},
57 {"is:issue is:mr", "is:mr"},
58 {"is:issue is:merged", "is:merged"},
59 {"is:mr assignee:cmc", "assignee:cmc"},
60 {"assignee:cmc is:mr", "is:mr"},
61 {"assignee:cmc assignee:bob", "assignee:bob"},
62 {"is:merged assignee:cmc", "assignee:cmc"},
63 {"assignee:@me is:merged", "is:merged"},
64 {"author:Not_A_User", "author:Not_A_User"},
65 {"repo:krz", "repo:krz"},
66 {"repo:*/gitbay", "repo:*/gitbay"},
67 {"repo:krz/[ab]", "repo:krz/[ab]"},
68 {"owner:krz/x", "owner:krz/x"},
69 {"label:bug no:label", "no:label"},
70 {"no:milestone milestone:v1", "milestone:v1"},
71 {"no:author", "no:author"},
72 {"label:", "label:"},
73 {`label:"open`, `label:"open`},
74 {"x", "x"}, // text too short
75 } {
76 _, err := ParseItemQuery(tc.in)
77 var qe *QueryError
78 if !errors.As(err, &qe) {
79 t.Errorf("%q: err %v, want a QueryError", tc.in, err)
80 continue
81 }
82 if qe.Token != tc.token {
83 t.Errorf("%q: token %q, want %q (%v)", tc.in, qe.Token, tc.token, err)
84 }
85 }
86}
87
88func TestItemQuerySelects(t *testing.T) {
89 for _, tc := range []struct {
90 in string
91 issues, mrs bool
92 }{
93 {"is:open", true, true},
94 {"is:issue", true, false},
95 {"is:mr", false, true},
96 {"is:merged", false, true},
97 {"assignee:cmc", true, false},
98 } {
99 q, err := ParseItemQuery(tc.in)
100 if err != nil {
101 t.Fatal(err)
102 }
103 if i, m := q.Selects(); i != tc.issues || m != tc.mrs {
104 t.Errorf("%q selects issues=%v mrs=%v, want %v %v", tc.in, i, m, tc.issues, tc.mrs)
105 }
106 }
107 q, _ := ParseItemQuery("repo:* repo:krz/x assignee:@me author:@me")
108 f := q.Filter("alice", true, true)
109 if f.Scopes != nil || f.Assignee != "alice" || f.Author != "alice" {
110 t.Errorf("Filter = %+v: repo:* widens to every repository, @me is the caller", f)
111 }
112}