go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/selector/parser_test.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package selector 9 10 import ( 11 "errors" 12 "strings" 13 "testing" 14 15 . "go.charczuk.com/sdk/assert" 16 ) 17 18 func Test_Parser_isWhitespace(t *testing.T) { 19 l := &Parser{} 20 ItsEqual(t, true, l.isWhitespace(' ')) 21 ItsEqual(t, true, l.isWhitespace('\n')) 22 ItsEqual(t, true, l.isWhitespace('\r')) 23 ItsEqual(t, true, l.isWhitespace('\t')) 24 25 ItsEqual(t, false, l.isWhitespace('a')) 26 ItsEqual(t, false, l.isWhitespace('z')) 27 ItsEqual(t, false, l.isWhitespace('A')) 28 ItsEqual(t, false, l.isWhitespace('Z')) 29 ItsEqual(t, false, l.isWhitespace('1')) 30 ItsEqual(t, false, l.isWhitespace('-')) 31 } 32 33 func Test_Parser_skipWhitespace(t *testing.T) { 34 l := &Parser{s: "foo != bar ", pos: 3} 35 ItsEqual(t, " ", string(l.current())) 36 l.skipWhiteSpace() 37 ItsEqual(t, 7, l.pos) 38 ItsEqual(t, "!", string(l.current())) 39 l.pos = 14 40 ItsEqual(t, " ", string(l.current())) 41 l.skipWhiteSpace() 42 ItsEqual(t, len(l.s), l.pos) 43 } 44 45 func Test_Parser_readWord(t *testing.T) { 46 l := &Parser{s: "foo != bar"} 47 word, err := l.readWord() 48 ItsNil(t, err) 49 ItsEqual(t, "foo", word) 50 ItsEqual(t, " ", string(l.current())) 51 52 l = &Parser{s: "foo,"} 53 word, err = l.readWord() 54 ItsNil(t, err) 55 ItsEqual(t, "foo", word) 56 ItsEqual(t, ",", string(l.current())) 57 58 l = &Parser{s: "foo"} 59 word, err = l.readWord() 60 ItsNil(t, err) 61 ItsEqual(t, "foo", word) 62 ItsEqual(t, true, l.done()) 63 64 l = &Parser{ 65 s: "foo ==", 66 pos: 6, 67 } 68 word, err = l.readWord() 69 ItsNotNil(t, err) 70 ItsEqual(t, true, errors.Is(err, ErrInvalidSelector)) 71 ItsEmpty(t, word) 72 ItsEqual(t, true, l.done()) 73 } 74 75 func Test_Parser_readOp(t *testing.T) { 76 l := &Parser{s: "!= bar"} 77 op, err := l.readOp() 78 ItsNil(t, err) 79 ItsEqual(t, "!=", op) 80 ItsEqual(t, " ", string(l.current())) 81 82 l = &Parser{s: "!=bar"} 83 op, err = l.readOp() 84 ItsNil(t, err) 85 ItsEqual(t, "!=", op) 86 ItsEqual(t, "b", string(l.current())) 87 88 l = &Parser{s: "!=bar"} 89 op, err = l.readOp() 90 ItsNil(t, err) 91 ItsEqual(t, "!=", op) 92 ItsEqual(t, "b", string(l.current())) 93 94 l = &Parser{s: "!="} 95 op, err = l.readOp() 96 ItsNil(t, err) 97 ItsEqual(t, "!=", op) 98 ItsEqual(t, true, l.done()) 99 100 l = &Parser{s: "= bar"} 101 op, err = l.readOp() 102 ItsNil(t, err) 103 ItsEqual(t, "=", op) 104 ItsEqual(t, " ", string(l.current())) 105 106 l = &Parser{s: "=bar"} 107 op, err = l.readOp() 108 ItsNil(t, err) 109 ItsEqual(t, "=", op) 110 ItsEqual(t, "b", string(l.current())) 111 112 l = &Parser{s: "== bar"} 113 op, err = l.readOp() 114 ItsNil(t, err) 115 ItsEqual(t, "==", op) 116 ItsEqual(t, " ", string(l.current())) 117 118 l = &Parser{s: "==bar"} 119 op, err = l.readOp() 120 ItsNil(t, err) 121 ItsEqual(t, "==", op) 122 ItsEqual(t, "b", string(l.current())) 123 124 l = &Parser{s: "in (foo)"} 125 op, err = l.readOp() 126 ItsNil(t, err) 127 ItsEqual(t, "in", op) 128 ItsEqual(t, " ", string(l.current())) 129 130 l = &Parser{s: "in(foo)"} 131 op, err = l.readOp() 132 ItsNil(t, err) 133 ItsEqual(t, "in", op) 134 ItsEqual(t, "(", string(l.current())) 135 136 l = &Parser{s: "notin (foo)"} 137 op, err = l.readOp() 138 ItsNil(t, err) 139 ItsEqual(t, "notin", op) 140 ItsEqual(t, " ", string(l.current())) 141 142 l = &Parser{s: "notin(foo)"} 143 op, err = l.readOp() 144 ItsNil(t, err) 145 ItsEqual(t, "notin", op) 146 ItsEqual(t, "(", string(l.current())) 147 } 148 149 func Test_Parser_readCSV(t *testing.T) { 150 l := &Parser{s: "(bar, baz, biz)"} 151 words, err := l.readCSV() 152 ItsNil(t, err) 153 ItsEqual(t, 3, len(words), strings.Join(words, ",")) 154 ItsEqual(t, "bar", words[0]) 155 ItsEqual(t, "baz", words[1]) 156 ItsEqual(t, "biz", words[2]) 157 ItsEqual(t, true, l.done()) 158 159 l = &Parser{s: "(bar,baz,biz)"} 160 words, err = l.readCSV() 161 ItsNil(t, err) 162 ItsEqual(t, 3, Len(words), strings.Join(words, ",")) 163 ItsEqual(t, "bar", words[0]) 164 ItsEqual(t, "baz", words[1]) 165 ItsEqual(t, "biz", words[2]) 166 ItsEqual(t, true, l.done()) 167 168 l = &Parser{s: "(bar, buzz, baz"} 169 words, err = l.readCSV() 170 ItsNotNil(t, err) 171 ItsEmpty(t, words) 172 173 l = &Parser{s: "()"} 174 words, err = l.readCSV() 175 ItsNil(t, err) 176 ItsEmpty(t, words) 177 ItsEqual(t, true, l.done()) 178 179 l = &Parser{s: "(), thing=after"} 180 words, err = l.readCSV() 181 ItsNil(t, err) 182 ItsEmpty(t, words) 183 ItsEqual(t, ",", string(l.current())) 184 185 l = &Parser{s: "(foo, bar), buzz=light"} 186 words, err = l.readCSV() 187 ItsNil(t, err) 188 ItsEqual(t, 2, Len(words)) 189 ItsEqual(t, "foo", words[0]) 190 ItsEqual(t, "bar", words[1]) 191 ItsEqual(t, ",", string(l.current())) 192 193 l = &Parser{s: "(test, space are bad)"} 194 words, err = l.readCSV() 195 ItsNotNil(t, err) 196 ItsEmpty(t, words) 197 } 198 199 func Test_Parser_hasKey(t *testing.T) { 200 l := &Parser{s: "foo"} 201 valid, err := l.Parse() 202 ItsNil(t, err) 203 ItsNotNil(t, valid) 204 typed, isTyped := valid.(HasKey) 205 ItsEqual(t, true, isTyped) 206 ItsEqual(t, "foo", string(typed)) 207 } 208 209 func Test_Parser_notHasKey(t *testing.T) { 210 l := &Parser{s: "!foo"} 211 valid, err := l.Parse() 212 ItsNil(t, err) 213 ItsNotNil(t, valid) 214 typed, isTyped := valid.(NotHasKey) 215 ItsEqual(t, true, isTyped) 216 ItsEqual(t, "foo", string(typed)) 217 } 218 219 func Test_Parser_equals(t *testing.T) { 220 l := &Parser{s: "foo = bar"} 221 valid, err := l.Parse() 222 ItsNil(t, err) 223 ItsNotNil(t, valid) 224 typed, isTyped := valid.(Equals) 225 ItsEqual(t, true, isTyped) 226 ItsEqual(t, "foo", typed.Key) 227 ItsEqual(t, "bar", typed.Value) 228 229 l = &Parser{s: "foo=bar"} 230 valid, err = l.Parse() 231 ItsNil(t, err) 232 ItsNotNil(t, valid) 233 typed, isTyped = valid.(Equals) 234 ItsEqual(t, true, isTyped) 235 ItsEqual(t, "foo", typed.Key) 236 ItsEqual(t, "bar", typed.Value) 237 } 238 239 func Test_Parser_doubleEquals(t *testing.T) { 240 l := &Parser{s: "foo == bar"} 241 valid, err := l.Parse() 242 ItsNil(t, err) 243 ItsNotNil(t, valid) 244 typed, isTyped := valid.(Equals) 245 ItsEqual(t, true, isTyped) 246 ItsEqual(t, "foo", typed.Key) 247 ItsEqual(t, "bar", typed.Value) 248 } 249 250 func Test_Parser_NotEquals(t *testing.T) { 251 l := &Parser{s: "foo != bar"} 252 valid, err := l.Parse() 253 ItsNil(t, err) 254 ItsNotNil(t, valid) 255 typed, isTyped := valid.(NotEquals) 256 ItsEqual(t, true, isTyped) 257 ItsEqual(t, "foo", typed.Key) 258 ItsEqual(t, "bar", typed.Value) 259 } 260 261 func Test_Parser_in(t *testing.T) { 262 l := &Parser{s: "foo in (bar, baz)"} 263 valid, err := l.Parse() 264 ItsNil(t, err) 265 ItsNotNil(t, valid) 266 typed, isTyped := valid.(In) 267 ItsEqual(t, true, isTyped) 268 ItsEqual(t, "foo", typed.Key) 269 ItsEqual(t, 2, Len(typed.Values)) 270 ItsEqual(t, "bar", typed.Values[0]) 271 ItsEqual(t, "baz", typed.Values[1]) 272 } 273 274 func Test_Parser_lexEmpty(t *testing.T) { 275 l := &Parser{s: ""} 276 _, err := l.Parse() 277 ItsNil(t, err) 278 } 279 280 func Test_Parser_errors(t *testing.T) { 281 sel, err := Parse("foo ==") 282 ItsNotNil(t, err) 283 ItsNil(t, sel) 284 285 typed, ok := err.(*ParseError) 286 ItsEqual(t, true, ok) 287 ItsEqual(t, ErrInvalidSelector, typed.Err) 288 ItsEqual(t, "foo ==", typed.Input) 289 ItsEqual(t, 6, typed.Position) 290 291 ItsEqual(t, "invalid selector", typed.Class().Error()) 292 ItsEqual(t, `"foo ==":0:6: invalid selector; expected non-empty key`, typed.Error()) 293 }