fts3expr2.test 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. # 2009 January 1
  2. #
  3. # The author disclaims copyright to this source code. In place of
  4. # a legal notice, here is a blessing:
  5. #
  6. # May you do good and not evil.
  7. # May you find forgiveness for yourself and forgive others.
  8. # May you share freely, never taking more than you give.
  9. #
  10. #*************************************************************************
  11. # This file implements regression tests for SQLite library. The
  12. # focus of this script is testing the FTS3 module syntax parser.
  13. #
  14. # $Id: fts3expr2.test,v 1.2 2009/06/05 17:09:12 drh Exp $
  15. #
  16. set testdir [file dirname $argv0]
  17. source $testdir/tester.tcl
  18. # If SQLITE_ENABLE_FTS3 is defined, omit this file.
  19. ifcapable !fts3 {
  20. finish_test
  21. return
  22. }
  23. # Test overview:
  24. #
  25. # The tests in this file are pseudo-randomly generated. They test
  26. # the fts3 match expression parser via the test interface
  27. # SQL function "fts3_exprtest" (see comments in fts3_expr.c).
  28. #
  29. # Each test case works as follows:
  30. #
  31. # 1. A random expression tree is generated using proc [random_expr_tree].
  32. # 2. The expression tree is converted to the text of an equivalent
  33. # fts3 expression using proc [tree_to_expr].
  34. # 3. The test SQL function "fts3_exprtest" is used to parse the
  35. # expression text generated in step (2), returning a parsed expression
  36. # tree.
  37. # 4. Test that the tree returned in step (3) matches that generated in
  38. # step (1).
  39. #
  40. # In step (2), 4 different fts3 expressions are created from each
  41. # expression tree by varying the following boolean properties:
  42. #
  43. # * Whether or not superflous parenthesis are included. i.e. if
  44. # "a OR b AND (c OR d)" or "a OR (b AND (c OR d))" is generated.
  45. #
  46. # * Whether or not explict AND operators are used. i.e. if
  47. # "a OR b AND c" or "a OR b c" is generated.
  48. #
  49. set sqlite_fts3_enable_parentheses 1
  50. proc strip_phrase_data {L} {
  51. if {[lindex $L 0] eq "PHRASE"} {
  52. return [list P [lrange $L 3 end]]
  53. }
  54. return [list \
  55. [lindex $L 0] \
  56. [strip_phrase_data [lindex $L 1]] \
  57. [strip_phrase_data [lindex $L 2]] \
  58. ]
  59. }
  60. proc test_fts3expr2 {expr} {
  61. strip_phrase_data [
  62. db one {SELECT fts3_exprtest('simple', $expr, 'a', 'b', 'c')}
  63. ]
  64. }
  65. proc rnd {nMax} { expr {int(rand()*$nMax)} }
  66. proc random_phrase {} {
  67. set phrases [list one two three four "one two" "three four"]
  68. list P [lindex $phrases [rnd [llength $phrases]]]
  69. }
  70. # Generate and return a pseudo-random expression tree. Using the same
  71. # format returned by the [test_fts3expr2] proc.
  72. #
  73. proc random_expr_tree {iHeight} {
  74. if {$iHeight==0 || [rnd 3]==0} {
  75. return [random_phrase]
  76. }
  77. set operators [list NEAR NOT AND OR]
  78. set op [lindex $operators [rnd 4]]
  79. if {$op eq "NEAR"} {
  80. set iDistance [rnd 15]
  81. return [list $op/$iDistance [random_phrase] [random_phrase]]
  82. }
  83. set iNH [expr {$iHeight - 1}]
  84. return [list $op [random_expr_tree $iNH] [random_expr_tree $iNH]]
  85. }
  86. # Given an expression tree, generate a corresponding expression.
  87. #
  88. proc tree_to_expr {tree all_brackets implicit_and} {
  89. set prec(NOT) 2
  90. set prec(AND) 3
  91. set prec() 3
  92. set prec(OR) 4
  93. set op [lindex $tree 0]
  94. if {$op eq "P"} {
  95. set phrase [lindex $tree 1]
  96. if {[llength $phrase]>1} {
  97. return "\"$phrase\""
  98. } else {
  99. return $phrase
  100. }
  101. }
  102. if {$op eq "NEAR/10"} {
  103. set op "NEAR"
  104. }
  105. if {$op eq "AND" && $implicit_and} {
  106. set op ""
  107. }
  108. set lhs [lindex $tree 1]
  109. set rhs [lindex $tree 2]
  110. set zLeft [tree_to_expr $lhs $all_brackets $implicit_and]
  111. set zRight [tree_to_expr $rhs $all_brackets $implicit_and]
  112. set iPrec 5
  113. set iLeftPrec 0
  114. set iRightPrec 0
  115. catch {set iPrec $prec($op)}
  116. catch {set iLeftPrec $prec([lindex $lhs 0])}
  117. catch {set iRightPrec $prec([lindex $rhs 0])}
  118. if {$iLeftPrec > $iPrec || $all_brackets} {
  119. set zLeft "($zLeft)"
  120. }
  121. if {$iRightPrec >= $iPrec || $all_brackets} {
  122. set zRight "($zRight)"
  123. }
  124. return "$zLeft $op $zRight"
  125. }
  126. proc do_exprparse_test {name expr tree} {
  127. uplevel do_test $name [list "test_fts3expr2 {$expr}"] [list $tree]
  128. }
  129. for {set iTest 1} {$iTest<500} {incr iTest} {
  130. set t [random_expr_tree 4]
  131. set e1 [tree_to_expr $t 0 0]
  132. set e2 [tree_to_expr $t 0 1]
  133. set e3 [tree_to_expr $t 1 0]
  134. set e4 [tree_to_expr $t 1 1]
  135. do_exprparse_test fts3expr2-$iTest.1 $e1 $t
  136. do_exprparse_test fts3expr2-$iTest.2 $e2 $t
  137. do_exprparse_test fts3expr2-$iTest.3 $e3 $t
  138. do_exprparse_test fts3expr2-$iTest.4 $e4 $t
  139. }
  140. set sqlite_fts3_enable_parentheses 0
  141. finish_test