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  }