PageRenderTime 113ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/KinoSearch-0.315/core/KinoSearch/Test/TestQueryParserLogic.c

#
C | 724 lines | 641 code | 71 blank | 12 comment | 24 complexity | bbf31398d1506304f20206040ffa5a91 MD5 | raw file
  1. #define C_KINO_TESTQUERYPARSERLOGIC
  2. #define C_KINO_TESTQUERYPARSER
  3. #include "KinoSearch/Util/ToolSet.h"
  4. #include <stdarg.h>
  5. #include <string.h>
  6. #include "KinoSearch/Test.h"
  7. #include "KinoSearch/Test/TestQueryParserLogic.h"
  8. #include "KinoSearch/Test/TestQueryParser.h"
  9. #include "KinoSearch/Test/TestSchema.h"
  10. #include "KinoSearch/Test/TestUtils.h"
  11. #include "KinoSearch/Analysis/Analyzer.h"
  12. #include "KinoSearch/Analysis/Tokenizer.h"
  13. #include "KinoSearch/Document/Doc.h"
  14. #include "KinoSearch/Index/Indexer.h"
  15. #include "KinoSearch/Search/Hits.h"
  16. #include "KinoSearch/Search/IndexSearcher.h"
  17. #include "KinoSearch/Search/QueryParser.h"
  18. #include "KinoSearch/Search/TermQuery.h"
  19. #include "KinoSearch/Search/PhraseQuery.h"
  20. #include "KinoSearch/Search/LeafQuery.h"
  21. #include "KinoSearch/Search/ANDQuery.h"
  22. #include "KinoSearch/Search/MatchAllQuery.h"
  23. #include "KinoSearch/Search/NOTQuery.h"
  24. #include "KinoSearch/Search/NoMatchQuery.h"
  25. #include "KinoSearch/Search/ORQuery.h"
  26. #include "KinoSearch/Search/RequiredOptionalQuery.h"
  27. #include "KinoSearch/Store/RAMFolder.h"
  28. #define make_leaf_query (Query*)kino_TestUtils_make_leaf_query
  29. #define make_not_query (Query*)kino_TestUtils_make_not_query
  30. #define make_poly_query (Query*)kino_TestUtils_make_poly_query
  31. static TestQueryParser*
  32. logical_test_empty_phrase(uint32_t boolop)
  33. {
  34. Query *tree = make_leaf_query(NULL, "\"\"");
  35. UNUSED_VAR(boolop);
  36. return TestQP_new("\"\"", tree, NULL, 0);
  37. }
  38. static TestQueryParser*
  39. logical_test_empty_parens(uint32_t boolop)
  40. {
  41. Query *tree = make_poly_query(boolop, NULL);
  42. return TestQP_new("()", tree, NULL, 0);
  43. }
  44. static TestQueryParser*
  45. logical_test_nested_empty_parens(uint32_t boolop)
  46. {
  47. Query *inner = make_poly_query(boolop, NULL);
  48. Query *tree = make_poly_query(boolop, inner, NULL);
  49. return TestQP_new("(())", tree, NULL, 0);
  50. }
  51. static TestQueryParser*
  52. logical_test_nested_empty_phrase(uint32_t boolop)
  53. {
  54. Query *leaf = make_leaf_query(NULL, "\"\"");
  55. Query *tree = make_poly_query(boolop, leaf, NULL);
  56. return TestQP_new("(\"\")", tree, NULL, 0);
  57. }
  58. static TestQueryParser*
  59. logical_test_simple_term(uint32_t boolop)
  60. {
  61. Query *tree = make_leaf_query(NULL, "b");
  62. UNUSED_VAR(boolop);
  63. return TestQP_new("b", tree, NULL, 3);
  64. }
  65. static TestQueryParser*
  66. logical_test_one_nested_term(uint32_t boolop)
  67. {
  68. Query *leaf = make_leaf_query(NULL, "a");
  69. Query *tree = make_poly_query(boolop, leaf, NULL);
  70. return TestQP_new("(a)", tree, NULL, 4);
  71. }
  72. static TestQueryParser*
  73. logical_test_one_term_phrase(uint32_t boolop)
  74. {
  75. Query *tree = make_leaf_query(NULL, "\"a\"");
  76. UNUSED_VAR(boolop);
  77. return TestQP_new("\"a\"", tree, NULL, 4);
  78. }
  79. static TestQueryParser*
  80. logical_test_two_terms(uint32_t boolop)
  81. {
  82. Query *a_leaf = make_leaf_query(NULL, "a");
  83. Query *b_leaf = make_leaf_query(NULL, "b");
  84. Query *tree = make_poly_query(boolop, a_leaf, b_leaf, NULL);
  85. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 3;
  86. return TestQP_new("a b", tree, NULL, num_hits);
  87. }
  88. static TestQueryParser*
  89. logical_test_two_terms_nested(uint32_t boolop)
  90. {
  91. Query *a_leaf = make_leaf_query(NULL, "a");
  92. Query *b_leaf = make_leaf_query(NULL, "b");
  93. Query *tree = make_poly_query(boolop, a_leaf, b_leaf, NULL);
  94. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 3;
  95. return TestQP_new("(a b)", tree, NULL, num_hits);
  96. }
  97. static TestQueryParser*
  98. logical_test_one_term_one_single_term_phrase(uint32_t boolop)
  99. {
  100. Query *a_leaf = make_leaf_query(NULL, "a");
  101. Query *b_leaf = make_leaf_query(NULL, "\"b\"");
  102. Query *tree = make_poly_query(boolop, a_leaf, b_leaf, NULL);
  103. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 3;
  104. return TestQP_new("a \"b\"", tree, NULL, num_hits);
  105. }
  106. static TestQueryParser*
  107. logical_test_two_terms_one_nested(uint32_t boolop)
  108. {
  109. Query *a_leaf = make_leaf_query(NULL, "a");
  110. Query *b_leaf = make_leaf_query(NULL, "b");
  111. Query *b_tree = make_poly_query(boolop, b_leaf, NULL);
  112. Query *tree = make_poly_query(boolop, a_leaf, b_tree, NULL);
  113. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 3;
  114. return TestQP_new("a (b)", tree, NULL, num_hits);
  115. }
  116. static TestQueryParser*
  117. logical_test_one_term_one_nested_single_term_phrase(uint32_t boolop)
  118. {
  119. Query *a_leaf = make_leaf_query(NULL, "a");
  120. Query *b_leaf = make_leaf_query(NULL, "\"b\"");
  121. Query *b_tree = make_poly_query(boolop, b_leaf, NULL);
  122. Query *tree = make_poly_query(boolop, a_leaf, b_tree, NULL);
  123. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 3;
  124. return TestQP_new("a (\"b\")", tree, NULL, num_hits);
  125. }
  126. static TestQueryParser*
  127. logical_test_phrase(uint32_t boolop)
  128. {
  129. Query *tree = make_leaf_query(NULL, "\"a b\"");
  130. UNUSED_VAR(boolop);
  131. return TestQP_new("\"a b\"", tree, NULL, 3);
  132. }
  133. static TestQueryParser*
  134. logical_test_nested_phrase(uint32_t boolop)
  135. {
  136. Query *leaf = make_leaf_query(NULL, "\"a b\"");
  137. Query *tree = make_poly_query(boolop, leaf, NULL);
  138. return TestQP_new("(\"a b\")", tree, NULL, 3);
  139. }
  140. static TestQueryParser*
  141. logical_test_three_terms(uint32_t boolop)
  142. {
  143. Query *a_leaf = make_leaf_query(NULL, "a");
  144. Query *b_leaf = make_leaf_query(NULL, "b");
  145. Query *c_leaf = make_leaf_query(NULL, "c");
  146. Query *tree = make_poly_query(boolop, a_leaf, b_leaf,
  147. c_leaf, NULL);
  148. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 2;
  149. return TestQP_new("a b c", tree, NULL, num_hits);
  150. }
  151. static TestQueryParser*
  152. logical_test_three_terms_two_nested(uint32_t boolop)
  153. {
  154. Query *a_leaf = make_leaf_query(NULL, "a");
  155. Query *b_leaf = make_leaf_query(NULL, "b");
  156. Query *c_leaf = make_leaf_query(NULL, "c");
  157. Query *inner_tree = make_poly_query(boolop, b_leaf, c_leaf, NULL);
  158. Query *tree = make_poly_query(boolop, a_leaf, inner_tree, NULL);
  159. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 2;
  160. return TestQP_new("a (b c)", tree, NULL, num_hits);
  161. }
  162. static TestQueryParser*
  163. logical_test_one_term_one_phrase(uint32_t boolop)
  164. {
  165. Query *a_leaf = make_leaf_query(NULL, "a");
  166. Query *bc_leaf = make_leaf_query(NULL, "\"b c\"");
  167. Query *tree = make_poly_query(boolop, a_leaf, bc_leaf, NULL);
  168. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 2;
  169. return TestQP_new("a \"b c\"", tree, NULL, num_hits);
  170. }
  171. static TestQueryParser*
  172. logical_test_one_term_one_nested_phrase(uint32_t boolop)
  173. {
  174. Query *a_leaf = make_leaf_query(NULL, "a");
  175. Query *bc_leaf = make_leaf_query(NULL, "\"b c\"");
  176. Query *inner_tree = make_poly_query(boolop, bc_leaf, NULL);
  177. Query *tree = make_poly_query(boolop, a_leaf, inner_tree, NULL);
  178. uint32_t num_hits = boolop == BOOLOP_OR ? 4 : 2;
  179. return TestQP_new("a (\"b c\")", tree, NULL, num_hits);
  180. }
  181. static TestQueryParser*
  182. logical_test_long_phrase(uint32_t boolop)
  183. {
  184. Query *tree = make_leaf_query(NULL, "\"a b c\"");
  185. UNUSED_VAR(boolop);
  186. return TestQP_new("\"a b c\"", tree, NULL, 2);
  187. }
  188. static TestQueryParser*
  189. logical_test_pure_negation(uint32_t boolop)
  190. {
  191. Query *leaf = make_leaf_query(NULL, "x");
  192. Query *tree = make_not_query(leaf);
  193. UNUSED_VAR(boolop);
  194. return TestQP_new("-x", tree, NULL, 0);
  195. }
  196. static TestQueryParser*
  197. logical_test_double_negative(uint32_t boolop)
  198. {
  199. Query *tree = make_leaf_query(NULL, "a");
  200. UNUSED_VAR(boolop);
  201. return TestQP_new("--a", tree, NULL, 4);
  202. }
  203. static TestQueryParser*
  204. logical_test_triple_negative(uint32_t boolop)
  205. {
  206. Query *leaf = make_leaf_query(NULL, "a");
  207. Query *tree = make_not_query(leaf);
  208. UNUSED_VAR(boolop);
  209. return TestQP_new("---a", tree, NULL, 0);
  210. }
  211. // Technically, this should produce an acceptably small result set, but it's
  212. // too difficult to prune -- so QParser_Prune just lops it because it's a
  213. // top-level NOTQuery.
  214. static TestQueryParser*
  215. logical_test_nested_negations(uint32_t boolop)
  216. {
  217. Query *query = make_leaf_query(NULL, "a");
  218. query = make_poly_query(boolop, query, NULL);
  219. query = make_not_query(query);
  220. query = make_poly_query(BOOLOP_AND, query, NULL);
  221. query = make_not_query(query);
  222. return TestQP_new("-(-(a))", query, NULL, 0);
  223. }
  224. static TestQueryParser*
  225. logical_test_two_terms_one_required(uint32_t boolop)
  226. {
  227. Query *a_query = make_leaf_query(NULL, "a");
  228. Query *b_query = make_leaf_query(NULL, "b");
  229. Query *tree;
  230. if (boolop == BOOLOP_AND) {
  231. tree = make_poly_query(boolop, a_query, b_query, NULL);
  232. }
  233. else {
  234. tree = (Query*)ReqOptQuery_new(b_query, a_query);
  235. DECREF(b_query);
  236. DECREF(a_query);
  237. }
  238. return TestQP_new("a +b", tree, NULL, 3);
  239. }
  240. static TestQueryParser*
  241. logical_test_intersection(uint32_t boolop)
  242. {
  243. Query *a_query = make_leaf_query(NULL, "a");
  244. Query *b_query = make_leaf_query(NULL, "b");
  245. Query *tree = make_poly_query(BOOLOP_AND, a_query, b_query, NULL);
  246. UNUSED_VAR(boolop);
  247. return TestQP_new("a AND b", tree, NULL, 3);
  248. }
  249. static TestQueryParser*
  250. logical_test_three_way_intersection(uint32_t boolop)
  251. {
  252. Query *a_query = make_leaf_query(NULL, "a");
  253. Query *b_query = make_leaf_query(NULL, "b");
  254. Query *c_query = make_leaf_query(NULL, "c");
  255. Query *tree = make_poly_query(BOOLOP_AND, a_query, b_query,
  256. c_query, NULL);
  257. UNUSED_VAR(boolop);
  258. return TestQP_new("a AND b AND c", tree, NULL, 2);
  259. }
  260. static TestQueryParser*
  261. logical_test_union(uint32_t boolop)
  262. {
  263. Query *a_query = make_leaf_query(NULL, "a");
  264. Query *b_query = make_leaf_query(NULL, "b");
  265. Query *tree = make_poly_query(BOOLOP_OR, a_query, b_query, NULL);
  266. UNUSED_VAR(boolop);
  267. return TestQP_new("a OR b", tree, NULL, 4);
  268. }
  269. static TestQueryParser*
  270. logical_test_three_way_union(uint32_t boolop)
  271. {
  272. Query *a_query = make_leaf_query(NULL, "a");
  273. Query *b_query = make_leaf_query(NULL, "b");
  274. Query *c_query = make_leaf_query(NULL, "c");
  275. Query *tree = make_poly_query(BOOLOP_OR, a_query, b_query, c_query, NULL);
  276. UNUSED_VAR(boolop);
  277. return TestQP_new("a OR b OR c", tree, NULL, 4);
  278. }
  279. static TestQueryParser*
  280. logical_test_a_or_plus_b(uint32_t boolop)
  281. {
  282. Query *a_query = make_leaf_query(NULL, "a");
  283. Query *b_query = make_leaf_query(NULL, "b");
  284. Query *tree = make_poly_query(BOOLOP_OR, a_query, b_query, NULL);
  285. UNUSED_VAR(boolop);
  286. return TestQP_new("a OR +b", tree, NULL, 4);
  287. }
  288. static TestQueryParser*
  289. logical_test_and_not(uint32_t boolop)
  290. {
  291. Query *a_query = make_leaf_query(NULL, "a");
  292. Query *b_query = make_leaf_query(NULL, "b");
  293. Query *not_b = make_not_query(b_query);
  294. Query *tree = make_poly_query(BOOLOP_AND, a_query, not_b, NULL);
  295. UNUSED_VAR(boolop);
  296. return TestQP_new("a AND NOT b", tree, NULL, 1);
  297. }
  298. static TestQueryParser*
  299. logical_test_nested_or(uint32_t boolop)
  300. {
  301. Query *a_query = make_leaf_query(NULL, "a");
  302. Query *b_query = make_leaf_query(NULL, "b");
  303. Query *c_query = make_leaf_query(NULL, "c");
  304. Query *nested = make_poly_query(BOOLOP_OR, b_query, c_query, NULL);
  305. Query *tree = make_poly_query(boolop, a_query, nested, NULL);
  306. return TestQP_new("a (b OR c)", tree, NULL, boolop == BOOLOP_OR ? 4 : 3);
  307. }
  308. static TestQueryParser*
  309. logical_test_and_nested_or(uint32_t boolop)
  310. {
  311. Query *a_query = make_leaf_query(NULL, "a");
  312. Query *b_query = make_leaf_query(NULL, "b");
  313. Query *c_query = make_leaf_query(NULL, "c");
  314. Query *nested = make_poly_query(BOOLOP_OR, b_query, c_query, NULL);
  315. Query *tree = make_poly_query(BOOLOP_AND, a_query, nested, NULL);
  316. UNUSED_VAR(boolop);
  317. return TestQP_new("a AND (b OR c)", tree, NULL, 3);
  318. }
  319. static TestQueryParser*
  320. logical_test_or_nested_or(uint32_t boolop)
  321. {
  322. Query *a_query = make_leaf_query(NULL, "a");
  323. Query *b_query = make_leaf_query(NULL, "b");
  324. Query *c_query = make_leaf_query(NULL, "c");
  325. Query *nested = make_poly_query(BOOLOP_OR, b_query, c_query, NULL);
  326. Query *tree = make_poly_query(BOOLOP_OR, a_query, nested, NULL);
  327. UNUSED_VAR(boolop);
  328. return TestQP_new("a OR (b OR c)", tree, NULL, 4);
  329. }
  330. static TestQueryParser*
  331. logical_test_and_not_nested_or(uint32_t boolop)
  332. {
  333. Query *a_query = make_leaf_query(NULL, "a");
  334. Query *b_query = make_leaf_query(NULL, "b");
  335. Query *c_query = make_leaf_query(NULL, "c");
  336. Query *nested = make_poly_query(BOOLOP_OR, b_query, c_query, NULL);
  337. Query *not_nested = make_not_query(nested);
  338. Query *tree = make_poly_query(BOOLOP_AND, a_query,
  339. not_nested, NULL);
  340. UNUSED_VAR(boolop);
  341. return TestQP_new("a AND NOT (b OR c)", tree, NULL, 1);
  342. }
  343. static TestQueryParser*
  344. logical_test_required_phrase_negated_term(uint32_t boolop)
  345. {
  346. Query *bc_query = make_leaf_query(NULL, "\"b c\"");
  347. Query *d_query = make_leaf_query(NULL, "d");
  348. Query *not_d = make_not_query(d_query);
  349. Query *tree = make_poly_query(BOOLOP_AND, bc_query, not_d, NULL);
  350. UNUSED_VAR(boolop);
  351. return TestQP_new("+\"b c\" -d", tree, NULL, 1);
  352. }
  353. static TestQueryParser*
  354. logical_test_required_term_optional_phrase(uint32_t boolop)
  355. {
  356. Query *ab_query = make_leaf_query(NULL, "\"a b\"");
  357. Query *d_query = make_leaf_query(NULL, "d");
  358. Query *tree;
  359. if (boolop == BOOLOP_AND) {
  360. tree = make_poly_query(BOOLOP_AND, ab_query, d_query, NULL);
  361. }
  362. else {
  363. tree = (Query*)ReqOptQuery_new(d_query, ab_query);
  364. DECREF(d_query);
  365. DECREF(ab_query);
  366. }
  367. UNUSED_VAR(boolop);
  368. return TestQP_new("\"a b\" +d", tree, NULL, 1);
  369. }
  370. static TestQueryParser*
  371. logical_test_nested_nest(uint32_t boolop)
  372. {
  373. Query *a_query = make_leaf_query(NULL, "a");
  374. Query *b_query = make_leaf_query(NULL, "b");
  375. Query *c_query = make_leaf_query(NULL, "c");
  376. Query *d_query = make_leaf_query(NULL, "d");
  377. Query *innermost = make_poly_query(BOOLOP_AND, c_query, d_query, NULL);
  378. Query *inner = make_poly_query(BOOLOP_OR, b_query, innermost, NULL);
  379. Query *not_inner = make_not_query(inner);
  380. Query *tree = make_poly_query(BOOLOP_AND, a_query, not_inner, NULL);
  381. UNUSED_VAR(boolop);
  382. return TestQP_new("a AND NOT (b OR (c AND d))", tree, NULL, 1);
  383. }
  384. static TestQueryParser*
  385. logical_test_field_bool_group(uint32_t boolop)
  386. {
  387. Query *b_query = make_leaf_query("content", "b");
  388. Query *c_query = make_leaf_query("content", "c");
  389. Query *tree = make_poly_query(boolop, b_query, c_query, NULL);
  390. return TestQP_new("content:(b c)", tree, NULL,
  391. boolop == BOOLOP_OR ? 3 : 2);
  392. }
  393. static TestQueryParser*
  394. logical_test_field_multi_OR(uint32_t boolop)
  395. {
  396. Query *a_query = make_leaf_query("content", "a");
  397. Query *b_query = make_leaf_query("content", "b");
  398. Query *c_query = make_leaf_query("content", "c");
  399. Query *tree = make_poly_query(BOOLOP_OR, a_query, b_query, c_query, NULL);
  400. UNUSED_VAR(boolop);
  401. return TestQP_new("content:(a OR b OR c)", tree, NULL, 4);
  402. }
  403. static TestQueryParser*
  404. logical_test_field_multi_AND(uint32_t boolop)
  405. {
  406. Query *a_query = make_leaf_query("content", "a");
  407. Query *b_query = make_leaf_query("content", "b");
  408. Query *c_query = make_leaf_query("content", "c");
  409. Query *tree = make_poly_query(BOOLOP_AND, a_query, b_query,
  410. c_query, NULL);
  411. UNUSED_VAR(boolop);
  412. return TestQP_new("content:(a AND b AND c)", tree, NULL, 2);
  413. }
  414. static TestQueryParser*
  415. logical_test_field_phrase(uint32_t boolop)
  416. {
  417. Query *tree = make_leaf_query("content", "\"b c\"");
  418. UNUSED_VAR(boolop);
  419. return TestQP_new("content:\"b c\"", tree, NULL, 2);
  420. }
  421. static TestQueryParser*
  422. prune_test_null_querystring()
  423. {
  424. Query *pruned = (Query*)NoMatchQuery_new();
  425. return TestQP_new(NULL, NULL, pruned, 0);
  426. }
  427. static TestQueryParser*
  428. prune_test_matchall()
  429. {
  430. Query *tree = (Query*)MatchAllQuery_new();
  431. Query *pruned = (Query*)NoMatchQuery_new();
  432. return TestQP_new(NULL, tree, pruned, 0);
  433. }
  434. static TestQueryParser*
  435. prune_test_nomatch()
  436. {
  437. Query *tree = (Query*)NoMatchQuery_new();
  438. Query *pruned = (Query*)NoMatchQuery_new();
  439. return TestQP_new(NULL, tree, pruned, 0);
  440. }
  441. static TestQueryParser*
  442. prune_test_optional_not()
  443. {
  444. Query *a_leaf = make_leaf_query(NULL, "a");
  445. Query *b_leaf = make_leaf_query(NULL, "b");
  446. Query *not_b = make_not_query(b_leaf);
  447. Query *tree = make_poly_query(BOOLOP_OR, (Query*)INCREF(a_leaf),
  448. not_b, NULL);
  449. Query *nomatch = (Query*)NoMatchQuery_new();
  450. Query *pruned = make_poly_query(BOOLOP_OR, a_leaf, nomatch, NULL);
  451. return TestQP_new(NULL, tree, pruned, 4);
  452. }
  453. static TestQueryParser*
  454. prune_test_reqopt_optional_not()
  455. {
  456. Query *a_leaf = make_leaf_query(NULL, "a");
  457. Query *b_leaf = make_leaf_query(NULL, "b");
  458. Query *not_b = make_not_query(b_leaf);
  459. Query *tree = (Query*)ReqOptQuery_new(a_leaf, not_b);
  460. Query *nomatch = (Query*)NoMatchQuery_new();
  461. Query *pruned = (Query*)ReqOptQuery_new(a_leaf, nomatch);
  462. DECREF(nomatch);
  463. DECREF(not_b);
  464. DECREF(a_leaf);
  465. return TestQP_new(NULL, tree, pruned, 4);
  466. }
  467. static TestQueryParser*
  468. prune_test_reqopt_required_not()
  469. {
  470. Query *a_leaf = make_leaf_query(NULL, "a");
  471. Query *b_leaf = make_leaf_query(NULL, "b");
  472. Query *not_a = make_not_query(a_leaf);
  473. Query *tree = (Query*)ReqOptQuery_new(not_a, b_leaf);
  474. Query *nomatch = (Query*)NoMatchQuery_new();
  475. Query *pruned = (Query*)ReqOptQuery_new(nomatch, b_leaf);
  476. DECREF(nomatch);
  477. DECREF(not_a);
  478. DECREF(b_leaf);
  479. return TestQP_new(NULL, tree, pruned, 0);
  480. }
  481. static TestQueryParser*
  482. prune_test_not_and_not()
  483. {
  484. Query *a_leaf = make_leaf_query(NULL, "a");
  485. Query *b_leaf = make_leaf_query(NULL, "b");
  486. Query *not_a = make_not_query(a_leaf);
  487. Query *not_b = make_not_query(b_leaf);
  488. Query *tree = make_poly_query(BOOLOP_AND, not_a, not_b, NULL);
  489. Query *pruned = make_poly_query(BOOLOP_AND, NULL);
  490. return TestQP_new(NULL, tree, pruned, 0);
  491. }
  492. /***************************************************************************/
  493. typedef TestQueryParser*
  494. (*kino_TestQPLogic_logical_test_t)(uint32_t boolop_sym);
  495. static kino_TestQPLogic_logical_test_t logical_test_funcs[] = {
  496. logical_test_empty_phrase,
  497. logical_test_empty_parens,
  498. logical_test_nested_empty_parens,
  499. logical_test_nested_empty_phrase,
  500. logical_test_simple_term,
  501. logical_test_one_nested_term,
  502. logical_test_one_term_phrase,
  503. logical_test_two_terms,
  504. logical_test_two_terms_nested,
  505. logical_test_one_term_one_single_term_phrase,
  506. logical_test_two_terms_one_nested,
  507. logical_test_one_term_one_nested_phrase,
  508. logical_test_phrase,
  509. logical_test_nested_phrase,
  510. logical_test_three_terms,
  511. logical_test_three_terms_two_nested,
  512. logical_test_one_term_one_phrase,
  513. logical_test_one_term_one_nested_single_term_phrase,
  514. logical_test_long_phrase,
  515. logical_test_pure_negation,
  516. logical_test_double_negative,
  517. logical_test_triple_negative,
  518. logical_test_nested_negations,
  519. logical_test_two_terms_one_required,
  520. logical_test_intersection,
  521. logical_test_three_way_intersection,
  522. logical_test_union,
  523. logical_test_three_way_union,
  524. logical_test_a_or_plus_b,
  525. logical_test_and_not,
  526. logical_test_nested_or,
  527. logical_test_and_nested_or,
  528. logical_test_or_nested_or,
  529. logical_test_and_not_nested_or,
  530. logical_test_required_phrase_negated_term,
  531. logical_test_required_term_optional_phrase,
  532. logical_test_nested_nest,
  533. logical_test_field_phrase,
  534. logical_test_field_bool_group,
  535. logical_test_field_multi_OR,
  536. logical_test_field_multi_AND,
  537. NULL
  538. };
  539. typedef TestQueryParser*
  540. (*kino_TestQPLogic_prune_test_t)();
  541. static kino_TestQPLogic_prune_test_t prune_test_funcs[] = {
  542. prune_test_null_querystring,
  543. prune_test_matchall,
  544. prune_test_nomatch,
  545. prune_test_optional_not,
  546. prune_test_reqopt_optional_not,
  547. prune_test_reqopt_required_not,
  548. prune_test_not_and_not,
  549. NULL
  550. };
  551. static Folder*
  552. S_create_index()
  553. {
  554. Schema *schema = (Schema*)TestSchema_new();
  555. RAMFolder *folder = RAMFolder_new(NULL);
  556. VArray *doc_set = TestUtils_doc_set();
  557. Indexer *indexer = Indexer_new(schema, (Obj*)folder, NULL, 0);
  558. uint32_t i, max;
  559. CharBuf *field = (CharBuf*)ZCB_WRAP_STR("content", 7);
  560. for (i = 0, max = VA_Get_Size(doc_set); i < max; i++) {
  561. Doc *doc = Doc_new(NULL, 0);
  562. Doc_Store(doc, field, VA_Fetch(doc_set, i));
  563. Indexer_Add_Doc(indexer, doc, 1.0f);
  564. DECREF(doc);
  565. }
  566. Indexer_Commit(indexer);
  567. DECREF(doc_set);
  568. DECREF(indexer);
  569. DECREF(schema);
  570. return (Folder*)folder;
  571. }
  572. void
  573. TestQPLogic_run_tests()
  574. {
  575. uint32_t i;
  576. TestBatch *batch = TestBatch_new(178);
  577. Folder *folder = S_create_index();
  578. IndexSearcher *searcher = IxSearcher_new((Obj*)folder);
  579. QueryParser *or_parser = QParser_new(IxSearcher_Get_Schema(searcher),
  580. NULL, NULL, NULL);
  581. ZombieCharBuf *AND = ZCB_WRAP_STR("AND", 3);
  582. QueryParser *and_parser = QParser_new(IxSearcher_Get_Schema(searcher),
  583. NULL, (CharBuf*)AND, NULL);
  584. QParser_Set_Heed_Colons(or_parser, true);
  585. QParser_Set_Heed_Colons(and_parser, true);
  586. TestBatch_Plan(batch);
  587. // Run logical tests with default boolop of OR.
  588. for (i = 0; logical_test_funcs[i] != NULL; i++) {
  589. kino_TestQPLogic_logical_test_t test_func = logical_test_funcs[i];
  590. TestQueryParser *test_case = test_func(BOOLOP_OR);
  591. Query *tree = QParser_Tree(or_parser, test_case->query_string);
  592. Query *parsed = QParser_Parse(or_parser, test_case->query_string);
  593. Hits *hits = IxSearcher_Hits(searcher, (Obj*)parsed, 0, 10, NULL);
  594. TEST_TRUE(batch, Query_Equals(tree, (Obj*)test_case->tree),
  595. "tree() OR %s", (char*)CB_Get_Ptr8(test_case->query_string));
  596. TEST_INT_EQ(batch, Hits_Total_Hits(hits), test_case->num_hits,
  597. "hits: OR %s", (char*)CB_Get_Ptr8(test_case->query_string));
  598. DECREF(hits);
  599. DECREF(parsed);
  600. DECREF(tree);
  601. DECREF(test_case);
  602. }
  603. // Run logical tests with default boolop of AND.
  604. for (i = 0; logical_test_funcs[i] != NULL; i++) {
  605. kino_TestQPLogic_logical_test_t test_func = logical_test_funcs[i];
  606. TestQueryParser *test_case = test_func(BOOLOP_AND);
  607. Query *tree = QParser_Tree(and_parser, test_case->query_string);
  608. Query *parsed = QParser_Parse(and_parser, test_case->query_string);
  609. Hits *hits = IxSearcher_Hits(searcher, (Obj*)parsed, 0, 10, NULL);
  610. TEST_TRUE(batch, Query_Equals(tree, (Obj*)test_case->tree),
  611. "tree() AND %s", (char*)CB_Get_Ptr8(test_case->query_string));
  612. TEST_INT_EQ(batch, Hits_Total_Hits(hits), test_case->num_hits,
  613. "hits: AND %s", (char*)CB_Get_Ptr8(test_case->query_string));
  614. DECREF(hits);
  615. DECREF(parsed);
  616. DECREF(tree);
  617. DECREF(test_case);
  618. }
  619. // Run tests for QParser_Prune().
  620. for (i = 0; prune_test_funcs[i] != NULL; i++) {
  621. kino_TestQPLogic_prune_test_t test_func = prune_test_funcs[i];
  622. TestQueryParser *test_case = test_func();
  623. CharBuf *qstring = test_case->tree
  624. ? Query_To_String(test_case->tree)
  625. : CB_new_from_trusted_utf8("(NULL)", 6);
  626. Query *tree = test_case->tree;
  627. Query *wanted = test_case->expanded;
  628. Query *pruned = QParser_Prune(or_parser, tree);
  629. Query *expanded;
  630. Hits *hits;
  631. TEST_TRUE(batch, Query_Equals(pruned, (Obj*)wanted),
  632. "prune() %s", (char*)CB_Get_Ptr8(qstring));
  633. expanded = QParser_Expand(or_parser, pruned);
  634. hits = IxSearcher_Hits(searcher, (Obj*)expanded, 0, 10, NULL);
  635. TEST_INT_EQ(batch, Hits_Total_Hits(hits), test_case->num_hits,
  636. "hits: %s", (char*)CB_Get_Ptr8(qstring));
  637. DECREF(hits);
  638. DECREF(expanded);
  639. DECREF(pruned);
  640. DECREF(qstring);
  641. DECREF(test_case);
  642. }
  643. DECREF(and_parser);
  644. DECREF(or_parser);
  645. DECREF(searcher);
  646. DECREF(folder);
  647. DECREF(batch);
  648. }
  649. /* Copyright 2005-2011 Marvin Humphrey
  650. *
  651. * This program is free software; you can redistribute it and/or modify
  652. * under the same terms as Perl itself.
  653. */