github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/pubsub/query/syntax/syntax_test.go (about)

     1  package syntax_test
     2  
     3  import (
     4  	"io"
     5  	"reflect"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/ari-anchor/sei-tendermint/internal/pubsub/query/syntax"
    10  )
    11  
    12  func TestScanner(t *testing.T) {
    13  	tests := []struct {
    14  		input string
    15  		want  []syntax.Token
    16  	}{
    17  		// Empty inputs
    18  		{"", nil},
    19  		{"  ", nil},
    20  		{"\t\n ", nil},
    21  
    22  		// Numbers
    23  		{`0 123`, []syntax.Token{syntax.TNumber, syntax.TNumber}},
    24  		{`0.32 3.14`, []syntax.Token{syntax.TNumber, syntax.TNumber}},
    25  
    26  		// Tags
    27  		{`foo foo.bar`, []syntax.Token{syntax.TTag, syntax.TTag}},
    28  
    29  		// Strings (values)
    30  		{` '' x 'x' 'x y'`, []syntax.Token{syntax.TString, syntax.TTag, syntax.TString, syntax.TString}},
    31  		{` 'you are not your job' `, []syntax.Token{syntax.TString}},
    32  
    33  		// Comparison operators
    34  		{`< <= = > >=`, []syntax.Token{
    35  			syntax.TLt, syntax.TLeq, syntax.TEq, syntax.TGt, syntax.TGeq,
    36  		}},
    37  
    38  		// Mixed values of various kinds.
    39  		{`x AND y`, []syntax.Token{syntax.TTag, syntax.TAnd, syntax.TTag}},
    40  		{`x.y CONTAINS 'z'`, []syntax.Token{syntax.TTag, syntax.TContains, syntax.TString}},
    41  		{`foo EXISTS`, []syntax.Token{syntax.TTag, syntax.TExists}},
    42  		{`and AND`, []syntax.Token{syntax.TTag, syntax.TAnd}},
    43  
    44  		// Timestamp
    45  		{`TIME 2021-11-23T15:16:17Z`, []syntax.Token{syntax.TTime}},
    46  
    47  		// Datestamp
    48  		{`DATE 2021-11-23`, []syntax.Token{syntax.TDate}},
    49  	}
    50  
    51  	for _, test := range tests {
    52  		s := syntax.NewScanner(strings.NewReader(test.input))
    53  		var got []syntax.Token
    54  		for s.Next() == nil {
    55  			got = append(got, s.Token())
    56  		}
    57  		if err := s.Err(); err != io.EOF {
    58  			t.Errorf("Next: unexpected error: %v", err)
    59  		}
    60  
    61  		if !reflect.DeepEqual(got, test.want) {
    62  			t.Logf("Scanner input: %q", test.input)
    63  			t.Errorf("Wrong tokens:\ngot:  %+v\nwant: %+v", got, test.want)
    64  		}
    65  	}
    66  }
    67  
    68  func TestScannerErrors(t *testing.T) {
    69  	tests := []struct {
    70  		input string
    71  	}{
    72  		{`'incomplete string`},
    73  		{`-23`},
    74  		{`&`},
    75  		{`DATE xyz-pdq`},
    76  		{`DATE xyzp-dq-zv`},
    77  		{`DATE 0000-00-00`},
    78  		{`DATE 0000-00-000`},
    79  		{`DATE 2021-01-99`},
    80  		{`TIME 2021-01-01T34:56:78Z`},
    81  		{`TIME 2021-01-99T14:56:08Z`},
    82  		{`TIME 2021-01-99T34:56:08`},
    83  		{`TIME 2021-01-99T34:56:11+3`},
    84  	}
    85  	for _, test := range tests {
    86  		s := syntax.NewScanner(strings.NewReader(test.input))
    87  		if err := s.Next(); err == nil {
    88  			t.Errorf("Next: got %v (%#q), want error", s.Token(), s.Text())
    89  		}
    90  	}
    91  }
    92  
    93  // These parser tests were copied from the original implementation of the query
    94  // parser, and are preserved here as a compatibility check.
    95  func TestParseValid(t *testing.T) {
    96  	tests := []struct {
    97  		input string
    98  		valid bool
    99  	}{
   100  		{"tm.events.type='NewBlock'", true},
   101  		{"tm.events.type = 'NewBlock'", true},
   102  		{"tm.events.name = ''", true},
   103  		{"tm.events.type='TIME'", true},
   104  		{"tm.events.type='DATE'", true},
   105  		{"tm.events.type='='", true},
   106  		{"tm.events.type='TIME", false},
   107  		{"tm.events.type=TIME'", false},
   108  		{"tm.events.type==", false},
   109  		{"tm.events.type=NewBlock", false},
   110  		{">==", false},
   111  		{"tm.events.type 'NewBlock' =", false},
   112  		{"tm.events.type>'NewBlock'", false},
   113  		{"", false},
   114  		{"=", false},
   115  		{"='NewBlock'", false},
   116  		{"tm.events.type=", false},
   117  
   118  		{"tm.events.typeNewBlock", false},
   119  		{"tm.events.type'NewBlock'", false},
   120  		{"'NewBlock'", false},
   121  		{"NewBlock", false},
   122  		{"", false},
   123  
   124  		{"tm.events.type='NewBlock' AND abci.account.name='Igor'", true},
   125  		{"tm.events.type='NewBlock' AND", false},
   126  		{"tm.events.type='NewBlock' AN", false},
   127  		{"tm.events.type='NewBlock' AN tm.events.type='NewBlockHeader'", false},
   128  		{"AND tm.events.type='NewBlock' ", false},
   129  
   130  		{"abci.account.name CONTAINS 'Igor'", true},
   131  
   132  		{"tx.date > DATE 2013-05-03", true},
   133  		{"tx.date < DATE 2013-05-03", true},
   134  		{"tx.date <= DATE 2013-05-03", true},
   135  		{"tx.date >= DATE 2013-05-03", true},
   136  		{"tx.date >= DAT 2013-05-03", false},
   137  		{"tx.date <= DATE2013-05-03", false},
   138  		{"tx.date <= DATE -05-03", false},
   139  		{"tx.date >= DATE 20130503", false},
   140  		{"tx.date >= DATE 2013+01-03", false},
   141  		// incorrect year, month, day
   142  		{"tx.date >= DATE 0013-01-03", false},
   143  		{"tx.date >= DATE 2013-31-03", false},
   144  		{"tx.date >= DATE 2013-01-83", false},
   145  
   146  		{"tx.date > TIME 2013-05-03T14:45:00+07:00", true},
   147  		{"tx.date < TIME 2013-05-03T14:45:00-02:00", true},
   148  		{"tx.date <= TIME 2013-05-03T14:45:00Z", true},
   149  		{"tx.date >= TIME 2013-05-03T14:45:00Z", true},
   150  		{"tx.date >= TIME2013-05-03T14:45:00Z", false},
   151  		{"tx.date = IME 2013-05-03T14:45:00Z", false},
   152  		{"tx.date = TIME 2013-05-:45:00Z", false},
   153  		{"tx.date >= TIME 2013-05-03T14:45:00", false},
   154  		{"tx.date >= TIME 0013-00-00T14:45:00Z", false},
   155  		{"tx.date >= TIME 2013+05=03T14:45:00Z", false},
   156  
   157  		{"account.balance=100", true},
   158  		{"account.balance >= 200", true},
   159  		{"account.balance >= -300", false},
   160  		{"account.balance >>= 400", false},
   161  		{"account.balance=33.22.1", false},
   162  
   163  		{"slashing.amount EXISTS", true},
   164  		{"slashing.amount EXISTS AND account.balance=100", true},
   165  		{"account.balance=100 AND slashing.amount EXISTS", true},
   166  		{"slashing EXISTS", true},
   167  
   168  		{"hash='136E18F7E4C348B780CF873A0BF43922E5BAFA63'", true},
   169  		{"hash=136E18F7E4C348B780CF873A0BF43922E5BAFA63", false},
   170  	}
   171  
   172  	for _, test := range tests {
   173  		q, err := syntax.Parse(test.input)
   174  		if test.valid != (err == nil) {
   175  			t.Errorf("Parse %#q: valid %v got err=%v", test.input, test.valid, err)
   176  		}
   177  
   178  		// For valid queries, check that the query round-trips.
   179  		if test.valid {
   180  			qstr := q.String()
   181  			r, err := syntax.Parse(qstr)
   182  			if err != nil {
   183  				t.Errorf("Reparse %#q failed: %v", qstr, err)
   184  			}
   185  			if rstr := r.String(); rstr != qstr {
   186  				t.Errorf("Reparse diff\nold: %#q\nnew: %#q", qstr, rstr)
   187  			}
   188  		}
   189  	}
   190  }