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 }