filter.cpp (8183B)
1 #include "helper.hpp" 2 3 #include <filter.hpp> 4 5 static const char *M = "[filter]"; 6 7 TEST_CASE("basic matching", M) { 8 Filter f; 9 REQUIRE(f.match({})); 10 REQUIRE(f.match({"world"})); 11 12 f.set("hello"); 13 REQUIRE(f.match({"hello"})); 14 REQUIRE(f.match({"HELLO"})); 15 REQUIRE_FALSE(f.match({"world"})); 16 } 17 18 TEST_CASE("word matching", M) { 19 Filter f; 20 f.set("hello world"); 21 22 REQUIRE_FALSE(f.match({"hello"})); 23 REQUIRE(f.match({"hello world"})); 24 REQUIRE(f.match({"helloworld"})); 25 REQUIRE(f.match({"hello test world"})); 26 } 27 28 TEST_CASE("quote phrase matching", M) { 29 Filter f; 30 31 SECTION("double quotes") 32 f.set("\"foo bar\" baz"); 33 SECTION("single quotes") 34 f.set("'foo bar' baz"); 35 36 REQUIRE(f.match({"baz foo bar"})); 37 REQUIRE(f.match({"BEFOREfoo barAFTER baz"})); 38 REQUIRE_FALSE(f.match({"foobarbaz"})); 39 REQUIRE_FALSE(f.match({"foo test bar baz"})); 40 } 41 42 TEST_CASE("full word matching", M) { 43 Filter f; 44 45 SECTION("double quotes") 46 f.set("\"hello\" world"); 47 SECTION("single quotes") 48 f.set("'hello' world"); 49 50 REQUIRE(f.match({"BEFORE hello AFTER world"})); 51 REQUIRE(f.match({"_hello_ world"})); 52 REQUIRE_FALSE(f.match({"BEFOREhello world"})); 53 REQUIRE_FALSE(f.match({"helloAFTER world"})); 54 REQUIRE_FALSE(f.match({"BEFOREhelloAFTER world"})); 55 } 56 57 TEST_CASE("late opening quote", M) { 58 Filter f; 59 f.set("foo'bar'"); 60 61 REQUIRE(f.match({"foo'bar'"})); 62 REQUIRE_FALSE(f.match({"foo bar"})); 63 } 64 65 TEST_CASE("early closing quote", M) { 66 Filter f; 67 f.set("'foo'bar"); 68 69 REQUIRE(f.match({"foo bar"})); 70 REQUIRE_FALSE(f.match({"foobar"})); 71 REQUIRE_FALSE(f.match({"foo ar"})); 72 } 73 74 TEST_CASE("mixing quotes", M) { 75 Filter f; 76 77 SECTION("double in single") { 78 f.set("'hello \"world\"'"); 79 80 REQUIRE(f.match({"hello \"world\""})); 81 REQUIRE_FALSE(f.match({"hello world"})); 82 } 83 84 SECTION("single in double") { 85 f.set("\"hello 'world'\""); 86 87 REQUIRE(f.match({"hello 'world'"})); 88 REQUIRE_FALSE(f.match({"hello world"})); 89 } 90 } 91 92 TEST_CASE("start of string", M) { 93 Filter f; 94 95 SECTION("normal") { 96 f.set("^hello"); 97 98 REQUIRE(f.match({"hello world"})); 99 REQUIRE_FALSE(f.match({"puts 'hello world'"})); 100 } 101 102 SECTION("middle") { 103 f.set("hel^lo"); 104 105 REQUIRE(f.match({"hel^lo world"})); 106 REQUIRE_FALSE(f.match({"hello world"})); 107 } 108 109 SECTION("single") { 110 f.set("^"); 111 REQUIRE(f.match({"hello world"})); 112 } 113 114 SECTION("literal ^") { 115 f.set("'^hello'"); 116 REQUIRE(f.match({"^hello world"})); 117 REQUIRE_FALSE(f.match({"world hello"})); 118 } 119 120 SECTION("full word") { 121 f.set("^'hello"); 122 REQUIRE(f.match({"hello world"})); 123 REQUIRE_FALSE(f.match({"world hello"})); 124 } 125 } 126 127 TEST_CASE("end of string", M) { 128 Filter f; 129 130 SECTION("normal") { 131 f.set("world$"); 132 133 REQUIRE(f.match({"hello world"})); 134 REQUIRE_FALSE(f.match({"'hello world'.upcase"})); 135 } 136 137 SECTION("middle") { 138 f.set("hel$lo"); 139 140 REQUIRE(f.match({"hel$lo world"})); 141 REQUIRE_FALSE(f.match({"hello world"})); 142 } 143 144 SECTION("single") { 145 f.set("$"); 146 REQUIRE(f.match({"hello world"})); 147 } 148 149 SECTION("full word") { 150 f.set("'hello'$"); 151 REQUIRE(f.match({"hello"})); 152 REQUIRE_FALSE(f.match({"hello world"})); 153 } 154 155 SECTION("literal $") { 156 f.set("'hello$'"); 157 REQUIRE(f.match({"hello$"})); 158 REQUIRE_FALSE(f.match({"hello world"})); 159 } 160 } 161 162 TEST_CASE("both anchors", M) { 163 Filter f; 164 f.set("^word$"); 165 166 REQUIRE(f.match({"word"})); 167 REQUIRE_FALSE(f.match({"word after"})); 168 REQUIRE_FALSE(f.match({"before word"})); 169 } 170 171 TEST_CASE("row matching", M) { 172 Filter f; 173 f.set("hello world"); 174 175 REQUIRE_FALSE(f.match({"hello"})); 176 REQUIRE(f.match({"hello", "world"})); 177 REQUIRE(f.match({"hello", "test", "world"})); 178 } 179 180 TEST_CASE("OR operator", M) { 181 Filter f; 182 183 SECTION("normal") { 184 f.set("hello OR bacon"); 185 186 REQUIRE(f.match({"hello world"})); 187 REQUIRE(f.match({"chunky bacon"})); 188 REQUIRE_FALSE(f.match({"not matching"})); 189 REQUIRE_FALSE(f.match({"OR"})); 190 } 191 192 SECTION("anchor") { 193 f.set("world OR ^bacon"); 194 195 REQUIRE(f.match({"hello world"})); 196 REQUIRE_FALSE(f.match({"chunky bacon"})); 197 REQUIRE(f.match({"bacon"})); 198 } 199 200 SECTION("reset") { 201 f.set("hello OR bacon world"); 202 203 REQUIRE_FALSE(f.match({"world"})); 204 REQUIRE(f.match({"hello world"})); 205 REQUIRE(f.match({"bacon world"})); 206 } 207 208 SECTION("single") { 209 f.set("OR"); 210 REQUIRE(f.match({"anything"})); 211 } 212 213 SECTION("literal OR") { 214 f.set("'OR'"); 215 REQUIRE(f.match({"OR"})); 216 REQUIRE_FALSE(f.match({"foo"})); 217 } 218 } 219 220 TEST_CASE("NOT operator", M) { 221 Filter f; 222 223 SECTION("normal") { 224 f.set("hello NOT bacon"); 225 226 REQUIRE(f.match({"hello world"})); 227 REQUIRE_FALSE(f.match({"chunky bacon"})); 228 REQUIRE_FALSE(f.match({"hello NOT bacon"})); 229 } 230 231 SECTION("row matching") { 232 f.set("NOT bacon"); 233 234 REQUIRE_FALSE(f.match({"hello", "bacon", "world"})); 235 REQUIRE(f.match({"hello", "world"})); 236 } 237 238 SECTION("preceded by OR") { 239 f.set("hello OR NOT bacon"); 240 REQUIRE(f.match({"hello bacon"})); 241 REQUIRE(f.match({"hello", "bacon"})); 242 } 243 244 SECTION("followed by OR") { 245 f.set("NOT bacon OR hello"); 246 REQUIRE(f.match({"hello bacon"})); 247 REQUIRE(f.match({"hello", "bacon"})); 248 } 249 250 SECTION("full word matching") { 251 f.set("NOT 'hello'"); 252 REQUIRE(f.match({"hellobacon"})); 253 } 254 255 SECTION("NOT NOT") { 256 f.set("NOT NOT hello"); 257 REQUIRE(f.match({"hello"})); 258 REQUIRE_FALSE(f.match({"world"})); 259 } 260 261 SECTION("literal NOT") { 262 f.set("'NOT'"); 263 REQUIRE(f.match({"NOT"})); 264 REQUIRE_FALSE(f.match({"foo"})); 265 } 266 } 267 268 TEST_CASE("AND grouping", M) { 269 Filter f; 270 271 SECTION("normal") { 272 f.set("( hello world ) OR ( NOT hello bacon )"); 273 274 REQUIRE(f.match({"hello world"})); 275 REQUIRE(f.match({"chunky bacon"})); 276 REQUIRE_FALSE(f.match({"hello chunky bacon"})); 277 } 278 279 SECTION("close without opening") { 280 f.set(") test"); 281 } 282 283 SECTION("NOT + AND grouping") { 284 f.set("NOT ( apple orange ) bacon"); 285 286 REQUIRE(f.match({"bacon"})); 287 REQUIRE(f.match({"apple bacon"})); 288 REQUIRE(f.match({"orange bacon"})); 289 REQUIRE_FALSE(f.match({"apple bacon orange"})); 290 } 291 292 SECTION("NOT + AND + OR grouping") { 293 f.set("NOT ( apple OR orange ) OR bacon"); 294 295 REQUIRE_FALSE(f.match({"apple"})); 296 REQUIRE_FALSE(f.match({"orange"})); 297 REQUIRE(f.match({"test"})); 298 REQUIRE(f.match({"apple bacon"})); 299 REQUIRE(f.match({"bacon"})); 300 } 301 302 SECTION("nested groups") { 303 f.set("NOT ( ( apple OR orange ) OR bacon )"); 304 305 REQUIRE_FALSE(f.match({"apple"})); 306 REQUIRE_FALSE(f.match({"orange"})); 307 REQUIRE(f.match({"test"})); 308 REQUIRE_FALSE(f.match({"apple bacon"})); 309 REQUIRE_FALSE(f.match({"bacon"})); 310 } 311 312 SECTION("literal parentheses") { 313 f.set("'('"); 314 REQUIRE(f.match({"("})); 315 REQUIRE_FALSE(f.match({"foo"})); 316 } 317 318 SECTION("closing a subgroup rewinds to the AND parent") { 319 f.set("a OR ( b ) c"); 320 321 REQUIRE_FALSE(f.match({"c"})); 322 REQUIRE(f.match({"a c"})); 323 REQUIRE(f.match({"b c"})); 324 } 325 326 SECTION("closing a subgroup doesn't rewind too far") { 327 f.set("NOT ( a OR ( b ) c ) OR d"); 328 329 REQUIRE_FALSE(f.match({"a c"})); 330 REQUIRE(f.match({"a z"})); 331 REQUIRE(f.match({"d"})); 332 } 333 } 334 335 TEST_CASE("synonymous words", M) { 336 Filter f; 337 338 SECTION("basic") { 339 f.set("open"); 340 REQUIRE(f.match({"open"})); 341 REQUIRE(f.match({"display"})); 342 REQUIRE_FALSE(f.match({"door"})); 343 } 344 345 SECTION("case-insensitive") { 346 f.set("OPEN"); 347 REQUIRE(f.match({"opening"})); 348 REQUIRE(f.match({"display"})); 349 } 350 351 SECTION("full-word synonyms") { 352 f.set("unselect"); 353 REQUIRE(f.match({"unselect"})); 354 REQUIRE(f.match({"unselected"})); 355 REQUIRE(f.match({"deselect"})); 356 REQUIRE_FALSE(f.match({"deselected"})); 357 } 358 359 SECTION("preserve anchor flags") { 360 f.set("^insert"); 361 REQUIRE(f.match({"add"})); 362 REQUIRE_FALSE(f.match({"don't add"})); 363 REQUIRE_FALSE(f.match({"not inserting things"})); 364 } 365 366 SECTION("NOT applies to all synonyms") { 367 f.set("NOT open"); 368 REQUIRE(f.match({"foo bar"})); 369 REQUIRE_FALSE(f.match({"open display"})); 370 } 371 372 SECTION("clear flags for the next token") { 373 f.set("^open bar"); 374 REQUIRE(f.match({"open bar"})); 375 } 376 }