go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/data/text/sequence/pattern_test.go (about) 1 // Copyright 2022 The LUCI Authors. 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 15 package sequence_test 16 17 import ( 18 "testing" 19 20 . "github.com/smartystreets/goconvey/convey" 21 "go.chromium.org/luci/common/data/text/sequence" 22 . "go.chromium.org/luci/common/testing/assertions" 23 ) 24 25 func TestAutoPattern(t *testing.T) { 26 t.Parallel() 27 28 Convey(`NewPattern`, t, func() { 29 Convey(`works`, func() { 30 Convey(`with empty input`, func() { 31 pat, err := sequence.NewPattern() 32 So(err, ShouldBeNil) 33 So(pat, ShouldBeNil) 34 }) 35 36 Convey(`with a literal`, func() { 37 pat, err := sequence.NewPattern("hello") 38 So(err, ShouldBeNil) 39 So(pat, ShouldResemble, sequence.Pattern{sequence.LiteralMatcher("hello")}) 40 }) 41 42 Convey(`with a reserved literal`, func() { 43 pat, err := sequence.NewPattern("=^", "==") 44 So(err, ShouldBeNil) 45 So(pat, ShouldResemble, sequence.Pattern{ 46 sequence.LiteralMatcher("^"), 47 sequence.LiteralMatcher("="), 48 }) 49 }) 50 51 Convey(`with string regexp`, func() { 52 pat, err := sequence.NewPattern("/hello/") 53 So(err, ShouldBeNil) 54 So(pat, ShouldHaveLength, 1) 55 So(pat[0], ShouldHaveSameTypeAs, sequence.RegexpMatcher{}) 56 rem := pat[0].(sequence.RegexpMatcher) 57 So(rem.R.String(), ShouldEqual, "hello") 58 }) 59 60 Convey(`with string ellipsis`, func() { 61 pat, err := sequence.NewPattern("...") 62 So(err, ShouldBeNil) 63 So(pat, ShouldResemble, sequence.Pattern{sequence.Ellipsis}) 64 }) 65 66 Convey(`with string edges`, func() { 67 pat, err := sequence.NewPattern("^", "$") 68 So(err, ShouldBeNil) 69 So(pat, ShouldResemble, sequence.Pattern{sequence.Edge, sequence.Edge}) 70 }) 71 }) 72 73 Convey(`fails`, func() { 74 Convey(`with a bad regexp`, func() { 75 _, err := sequence.NewPattern("/unclosed(/") 76 So(err, ShouldErrLike, "invalid regexp (i=0)") 77 }) 78 79 Convey(`with out of place edges`, func() { 80 _, err := sequence.NewPattern("$", "something") 81 So(err, ShouldErrLike, "cannot use `$` for Edge except at end") 82 83 _, err = sequence.NewPattern("something", "^") 84 So(err, ShouldErrLike, "cannot use `^` for Edge except at beginning") 85 }) 86 87 Convey(`with many ellipsis`, func() { 88 _, err := sequence.NewPattern("...", "...") 89 So(err, ShouldErrLike, "cannot have multiple Ellipsis in a row (i=1)") 90 }) 91 }) 92 }) 93 } 94 95 func TestPatternIn(t *testing.T) { 96 t.Parallel() 97 98 m := func(tokens ...string) sequence.Pattern { 99 ret, err := sequence.NewPattern(tokens...) 100 if err != nil { 101 panic(err) 102 } 103 return ret 104 } 105 106 Convey(`Pattern.In`, t, func() { 107 Convey(`works`, func() { 108 Convey(`no match`, func() { 109 So(m("narp").In("foo", "bar", "baz"), ShouldBeFalse) 110 }) 111 112 Convey(`finds single strings`, func() { 113 So(m("foo").In("foo", "bar", "baz"), ShouldBeTrue) 114 So(m("bar").In("foo", "bar", "baz"), ShouldBeTrue) 115 So(m("baz").In("foo", "bar", "baz"), ShouldBeTrue) 116 117 So(m("narp").In("foo", "bar", "baz"), ShouldBeFalse) 118 }) 119 120 Convey(`finds single regex`, func() { 121 So(m("/ba./").In("foo", "bar", "baz"), ShouldBeTrue) 122 So(m("/a/").In("foo", "bar", "baz"), ShouldBeTrue) 123 So(m("/z$/").In("foo", "bar", "baz"), ShouldBeTrue) 124 So(m("/^bar$/").In("foo", "bar", "baz"), ShouldBeTrue) 125 126 So(m("/^a$/").In("foo", "bar", "baz"), ShouldBeFalse) 127 }) 128 129 Convey(`finds string sequence`, func() { 130 So(m().In("foo", "bar", "baz"), ShouldBeTrue) 131 So(m("foo", "bar").In("foo", "bar", "baz"), ShouldBeTrue) 132 So(m("bar", "baz").In("foo", "bar", "baz"), ShouldBeTrue) 133 So(m("foo", "bar", "baz").In("foo", "bar", "baz"), ShouldBeTrue) 134 135 So(m("foo", "baz").In("foo", "bar", "baz"), ShouldBeFalse) 136 }) 137 138 Convey(`finds mixed sequence`, func() { 139 So(m("/.o./", "bar", "/z/").In("foo", "bar", "baz"), ShouldBeTrue) 140 141 So(m("/f/", "/z/", "/r/").In("foo", "bar", "baz"), ShouldBeFalse) 142 }) 143 144 Convey(`finds ellipsis sequence`, func() { 145 So(m("a", "foo", "...", "bar").In( 146 "a", "foo", "narp", "bar"), ShouldBeTrue) 147 148 So(m("foo", "...", "bar", "a").In( 149 "foo", "bar", "a"), ShouldBeTrue) 150 151 So(m("foo", "...", "bar", "...", "/^a/").In( 152 "foo", "narp", "bar", "tarp", "stuff", "aardvark"), ShouldBeTrue) 153 154 So(m("foo", "...", "bar").In( 155 "foo", "narp"), ShouldBeFalse) 156 }) 157 158 Convey(`respects Edges`, func() { 159 So(m("^", "foo", "...", "bar").In( 160 "foo", "narp", "bar"), ShouldBeTrue) 161 162 So(m("foo", "...", "bar", "$").In( 163 "a", "foo", "narp", "bar"), ShouldBeTrue) 164 165 So(m("a", "b", "$").In( 166 "extra", "a", "b"), ShouldBeTrue) 167 168 So(m("^", "foo", "...", "bar").In( 169 "a", "foo", "narp", "bar"), ShouldBeFalse) 170 171 So(m("foo", "...", "bar", "$").In( 172 "a", "foo", "narp", "bar", "stuff"), ShouldBeFalse) 173 174 }) 175 }) 176 177 Convey(`fails`, func() { 178 Convey(`bad Ellipsis`, func() { 179 So(func() { 180 sequence.Pattern{sequence.Ellipsis, sequence.Ellipsis}.In("something") 181 }, ShouldPanicLike, "cannot have multiple Ellipsis in a row") 182 }) 183 184 Convey(`bad Edge`, func() { 185 So(func() { 186 sequence.Pattern{ 187 sequence.Edge, 188 sequence.LiteralMatcher("stuff"), 189 sequence.Edge, 190 sequence.LiteralMatcher("more stuff"), 191 }.In("something") 192 }, ShouldPanicLike, "cannot have Edge in the middle of a Pattern") 193 }) 194 }) 195 }) 196 197 }