github.com/safing/portbase@v0.19.5/database/query/parser_test.go (about) 1 package query 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/davecgh/go-spew/spew" 8 ) 9 10 func TestExtractSnippets(t *testing.T) { 11 t.Parallel() 12 13 text1 := `query test: where ( "bananas" > 100 and monkeys.# <= "12")or(coconuts < 10 "and" area > 50) or name sameas Julian or name matches ^King\ ` 14 result1 := []*snippet{ 15 {text: "query", globalPosition: 1}, 16 {text: "test:", globalPosition: 7}, 17 {text: "where", globalPosition: 13}, 18 {text: "(", globalPosition: 19}, 19 {text: "bananas", globalPosition: 21}, 20 {text: ">", globalPosition: 31}, 21 {text: "100", globalPosition: 33}, 22 {text: "and", globalPosition: 37}, 23 {text: "monkeys.#", globalPosition: 41}, 24 {text: "<=", globalPosition: 51}, 25 {text: "12", globalPosition: 54}, 26 {text: ")", globalPosition: 58}, 27 {text: "or", globalPosition: 59}, 28 {text: "(", globalPosition: 61}, 29 {text: "coconuts", globalPosition: 62}, 30 {text: "<", globalPosition: 71}, 31 {text: "10", globalPosition: 73}, 32 {text: "and", globalPosition: 76}, 33 {text: "area", globalPosition: 82}, 34 {text: ">", globalPosition: 87}, 35 {text: "50", globalPosition: 89}, 36 {text: ")", globalPosition: 91}, 37 {text: "or", globalPosition: 93}, 38 {text: "name", globalPosition: 96}, 39 {text: "sameas", globalPosition: 101}, 40 {text: "Julian", globalPosition: 108}, 41 {text: "or", globalPosition: 115}, 42 {text: "name", globalPosition: 118}, 43 {text: "matches", globalPosition: 123}, 44 {text: "^King ", globalPosition: 131}, 45 } 46 47 snippets, err := extractSnippets(text1) 48 if err != nil { 49 t.Errorf("failed to extract snippets: %s", err) 50 } 51 52 if !reflect.DeepEqual(result1, snippets) { 53 t.Errorf("unexpected results:") 54 for _, el := range snippets { 55 t.Errorf("%+v", el) 56 } 57 } 58 59 // t.Error(spew.Sprintf("%v", treeElement)) 60 } 61 62 func testParsing(t *testing.T, queryText string, expectedResult *Query) { 63 t.Helper() 64 65 _, err := expectedResult.Check() 66 if err != nil { 67 t.Errorf("failed to create query: %s", err) 68 return 69 } 70 71 q, err := ParseQuery(queryText) 72 if err != nil { 73 t.Errorf("failed to parse query: %s", err) 74 return 75 } 76 77 if queryText != q.Print() { 78 t.Errorf("string match failed: %s", q.Print()) 79 return 80 } 81 if !reflect.DeepEqual(expectedResult, q) { 82 t.Error("deepqual match failed.") 83 t.Error("got:") 84 t.Error(spew.Sdump(q)) 85 t.Error("expected:") 86 t.Error(spew.Sdump(expectedResult)) 87 } 88 } 89 90 func TestParseQuery(t *testing.T) { 91 t.Parallel() 92 93 text1 := `query test: where (bananas > 100 and monkeys.# <= 12) or not (coconuts < 10 and area not > 50) or name sameas Julian or name matches "^King " orderby name limit 10 offset 20` 94 result1 := New("test:").Where(Or( 95 And( 96 Where("bananas", GreaterThan, 100), 97 Where("monkeys.#", LessThanOrEqual, 12), 98 ), 99 Not(And( 100 Where("coconuts", LessThan, 10), 101 Not(Where("area", GreaterThan, 50)), 102 )), 103 Where("name", SameAs, "Julian"), 104 Where("name", Matches, "^King "), 105 )).OrderBy("name").Limit(10).Offset(20) 106 testParsing(t, text1, result1) 107 108 testParsing(t, `query test: orderby name`, New("test:").OrderBy("name")) 109 testParsing(t, `query test: limit 10`, New("test:").Limit(10)) 110 testParsing(t, `query test: offset 10`, New("test:").Offset(10)) 111 testParsing(t, `query test: where banana matches ^ban`, New("test:").Where(Where("banana", Matches, "^ban"))) 112 testParsing(t, `query test: where banana exists`, New("test:").Where(Where("banana", Exists, nil))) 113 testParsing(t, `query test: where banana not exists`, New("test:").Where(Not(Where("banana", Exists, nil)))) 114 115 // test all operators 116 testParsing(t, `query test: where banana == 1`, New("test:").Where(Where("banana", Equals, 1))) 117 testParsing(t, `query test: where banana > 1`, New("test:").Where(Where("banana", GreaterThan, 1))) 118 testParsing(t, `query test: where banana >= 1`, New("test:").Where(Where("banana", GreaterThanOrEqual, 1))) 119 testParsing(t, `query test: where banana < 1`, New("test:").Where(Where("banana", LessThan, 1))) 120 testParsing(t, `query test: where banana <= 1`, New("test:").Where(Where("banana", LessThanOrEqual, 1))) 121 testParsing(t, `query test: where banana f== 1.1`, New("test:").Where(Where("banana", FloatEquals, 1.1))) 122 testParsing(t, `query test: where banana f> 1.1`, New("test:").Where(Where("banana", FloatGreaterThan, 1.1))) 123 testParsing(t, `query test: where banana f>= 1.1`, New("test:").Where(Where("banana", FloatGreaterThanOrEqual, 1.1))) 124 testParsing(t, `query test: where banana f< 1.1`, New("test:").Where(Where("banana", FloatLessThan, 1.1))) 125 testParsing(t, `query test: where banana f<= 1.1`, New("test:").Where(Where("banana", FloatLessThanOrEqual, 1.1))) 126 testParsing(t, `query test: where banana sameas banana`, New("test:").Where(Where("banana", SameAs, "banana"))) 127 testParsing(t, `query test: where banana contains banana`, New("test:").Where(Where("banana", Contains, "banana"))) 128 testParsing(t, `query test: where banana startswith banana`, New("test:").Where(Where("banana", StartsWith, "banana"))) 129 testParsing(t, `query test: where banana endswith banana`, New("test:").Where(Where("banana", EndsWith, "banana"))) 130 testParsing(t, `query test: where banana in banana,coconut`, New("test:").Where(Where("banana", In, []string{"banana", "coconut"}))) 131 testParsing(t, `query test: where banana matches banana`, New("test:").Where(Where("banana", Matches, "banana"))) 132 testParsing(t, `query test: where banana is true`, New("test:").Where(Where("banana", Is, true))) 133 testParsing(t, `query test: where banana exists`, New("test:").Where(Where("banana", Exists, nil))) 134 135 // special 136 testParsing(t, `query test: where banana not exists`, New("test:").Where(Not(Where("banana", Exists, nil)))) 137 } 138 139 func testParseError(t *testing.T, queryText string, expectedErrorString string) { 140 t.Helper() 141 142 _, err := ParseQuery(queryText) 143 if err == nil { 144 t.Errorf("should fail to parse: %s", queryText) 145 return 146 } 147 if err.Error() != expectedErrorString { 148 t.Errorf("unexpected error for query: %s\nwanted: %s\n got: %s", queryText, expectedErrorString, err) 149 } 150 } 151 152 func TestParseErrors(t *testing.T) { 153 t.Parallel() 154 155 // syntax 156 testParseError(t, `query`, `unexpected end at position 5`) 157 testParseError(t, `query test: where`, `unexpected end at position 17`) 158 testParseError(t, `query test: where (`, `unexpected end at position 19`) 159 testParseError(t, `query test: where )`, `unknown clause ")" at position 19`) 160 testParseError(t, `query test: where not`, `unexpected end at position 21`) 161 testParseError(t, `query test: where banana`, `unexpected end at position 24`) 162 testParseError(t, `query test: where banana >`, `unexpected end at position 26`) 163 testParseError(t, `query test: where banana nope`, `unknown operator at position 26`) 164 testParseError(t, `query test: where banana exists or`, `unexpected end at position 34`) 165 testParseError(t, `query test: where banana exists and`, `unexpected end at position 35`) 166 testParseError(t, `query test: where banana exists and (`, `unexpected end at position 37`) 167 testParseError(t, `query test: where banana exists and banana is true or`, `you may not mix "and" and "or" (position: 52)`) 168 testParseError(t, `query test: where banana exists or banana is true and`, `you may not mix "and" and "or" (position: 51)`) 169 // testParseError(t, `query test: where banana exists and (`, ``) 170 171 // value parsing error 172 testParseError(t, `query test: where banana == banana`, `could not parse banana to int64: strconv.ParseInt: parsing "banana": invalid syntax (hint: use "sameas" to compare strings)`) 173 testParseError(t, `query test: where banana f== banana`, `could not parse banana to float64: strconv.ParseFloat: parsing "banana": invalid syntax`) 174 testParseError(t, `query test: where banana in banana`, `could not parse "banana" to []string`) 175 testParseError(t, `query test: where banana matches [banana`, "could not compile regex \"[banana\": error parsing regexp: missing closing ]: `[banana`") 176 testParseError(t, `query test: where banana is great`, `could not parse "great" to bool: strconv.ParseBool: parsing "great": invalid syntax`) 177 }