Line # | Frequency | Source Line |
1 | | <?php
|
2 | | // $Id: search.test,v 1.7 2008/03/24 02:36:46 boombatower Exp $
|
3 | |
|
4 | | define('SEARCH_TYPE', '_test_');
|
5 | |
|
6 | | class SearchMatchTestCase extends DrupalTestCase {
|
7 | |
|
8 | | function getInfo() {
|
9 | | return array(
|
10 | 1 | 'name' => t('Search engine queries'),
|
11 | | 'description' => t('Indexes content and queries it.'),
|
12 | | 'group' => t('Search'),
|
13 | | );
|
14 | | }
|
15 | |
|
16 | | function setUp() {
|
17 | | parent::setUp();
|
18 | |
|
19 | | $this->drupalModuleEnable('search');
|
20 | | }
|
21 | |
|
22 | | function testMatching() {
|
23 | | $this->_cleanup();
|
24 | | $this->_setup();
|
25 | | $this->_testQueries();
|
26 | | $this->_cleanup();
|
27 | | }
|
28 | |
|
29 | | /**
|
30 | | * Set up a small index of items to test against.
|
31 | | */
|
32 | | function _setup() {
|
33 | | $this->drupalVariableSet('minimum_word_size', 3);
|
34 | |
|
35 | | for ($i = 1; $i <= 7; ++$i) {
|
36 | | search_index($i, SEARCH_TYPE, $this->getText($i));
|
37 | | }
|
38 | | search_update_totals();
|
39 | | }
|
40 | |
|
41 | | /**
|
42 | | * Clean up the indexed test content.
|
43 | | */
|
44 | | function _cleanup() {
|
45 | | for ($i = 1; $i < 7; ++$i) {
|
46 | | search_wipe($i, SEARCH_TYPE);
|
47 | | }
|
48 | | search_update_totals();
|
49 | | }
|
50 | |
|
51 | |
|
52 | | /**
|
53 | | * Helper method for generating snippets of content.
|
54 | | *
|
55 | | * Generated items to test against:
|
56 | | * 1 ipsum
|
57 | | * 2 dolore sit
|
58 | | * 3 sit am ut
|
59 | | * 4 am ut enim am
|
60 | | * 5 ut enim am minim veniam
|
61 | | * 6 enim am minim veniam es cillum
|
62 | | * 7 am minim veniam es cillum dolore eu
|
63 | | */
|
64 | | function getText($n) {
|
65 | | $words = explode(' ', "Ipsum dolore sit am. Ut enim am minim veniam. Es cillum dolore eu.");
|
66 | | return implode(' ', array_slice($words, $n - 1, $n));
|
67 | | }
|
68 | |
|
69 | | /**
|
70 | | */
|
71 | | function _testQueries() {
|
72 | | /*
|
73 | | Note: OR queries that include short words in OR groups are only accepted
|
74 | | if the ORed terms are ANDed with at least one long word in the rest of the query.
|
75 | |
|
76 | | e.g. enim dolore OR ut = enim (dolore OR ut) = (enim dolor) OR (enim ut) -> good
|
77 | | e.g. dolore OR ut = (dolore) OR (ut) -> bad
|
78 | |
|
79 | | This is a design limitation to avoid full table scans.
|
80 | | */
|
81 | | $queries = array(
|
82 | | // Simple AND queries.
|
83 | | 'ipsum' => array(1),
|
84 | | 'enim' => array(4, 5, 6),
|
85 | | 'xxxxx' => array(),
|
86 | | 'enim minim' => array(5, 6),
|
87 | | 'enim xxxxx' => array(),
|
88 | | 'dolore eu' => array(7),
|
89 | | 'dolore xx' => array(),
|
90 | | 'ut minim' => array(5),
|
91 | | 'xx minim' => array(),
|
92 | | 'enim veniam am minim ut' => array(5),
|
93 | | // Simple OR queries.
|
94 | | 'dolore OR ipsum' => array(1, 2, 7),
|
95 | | 'dolore OR xxxxx' => array(2, 7),
|
96 | | 'dolore OR ipsum OR enim' => array(1, 2, 4, 5, 6, 7),
|
97 | | 'ipsum OR dolore sit OR cillum' => array(2, 7),
|
98 | | 'minim dolore OR ipsum' => array(7),
|
99 | | 'dolore OR ipsum veniam' => array(7),
|
100 | | 'minim dolore OR ipsum OR enim' => array(5, 6, 7),
|
101 | | 'dolore xx OR yy' => array(),
|
102 | | 'xxxxx dolore OR ipsum' => array(),
|
103 | | // Negative queries.
|
104 | | 'dolore -sit' => array(7),
|
105 | | 'dolore -eu' => array(2),
|
106 | | 'dolore -xxxxx' => array(2, 7),
|
107 | | 'dolore -xx' => array(2, 7),
|
108 | | // Phrase queries.
|
109 | | '"dolore sit"' => array(2),
|
110 | | '"sit dolore"' => array(),
|
111 | | '"am minim veniam es"' => array(6, 7),
|
112 | | '"minim am veniam es"' => array(),
|
113 | | // Mixed queries.
|
114 | | '"am minim veniam es" OR dolore' => array(2, 6, 7),
|
115 | | '"minim am veniam es" OR "dolore sit"' => array(2),
|
116 | | '"minim am veniam es" OR "sit dolore"' => array(),
|
117 | | '"am minim veniam es" -eu' => array(6),
|
118 | | '"am minim veniam" -"cillum dolore"' => array(5, 6),
|
119 | | '"am minim veniam" -"dolore cillum"' => array(5, 6, 7),
|
120 | | 'xxxxx "minim am veniam es" OR dolore' => array(),
|
121 | | 'xx "minim am veniam es" OR dolore' => array(),
|
122 | | );
|
123 | | foreach ($queries as $query => $results) {
|
124 | | $set = do_search($query, SEARCH_TYPE);
|
125 | | $this->_testQueryMatching($query, $set, $results);
|
126 | | $this->_testQueryScores($query, $set, $results);
|
127 | | $this->cleanupQuery();
|
128 | | }
|
129 | | }
|
130 | |
|
131 | | /**
|
132 | | * Test the matching abilities of the engine.
|
133 | | *
|
134 | | * Verify if a query produces the correct results.
|
135 | | */
|
136 | | function _testQueryMatching($query, $set, $results) {
|
137 | | // Get result IDs.
|
138 | | $found = array();
|
139 | | foreach ($set as $item) {
|
140 | | $found[] = $item->sid;
|
141 | | }
|
142 | |
|
143 | | // Compare $results and $found.
|
144 | | sort($found);
|
145 | | sort($results);
|
146 | | $this->assertEqual($found, $results, "Query matching '$query'");
|
147 | | }
|
148 | |
|
149 | | /**
|
150 | | * Test the scoring abilities of the engine.
|
151 | | *
|
152 | | * Verify if a query produces normalized, monotonous scores.
|
153 | | */
|
154 | | function _testQueryScores($query, $set, $results) {
|
155 | | // Get result scores.
|
156 | | $scores = array();
|
157 | | foreach ($set as $item) {
|
158 | | $scores[] = $item->score;
|
159 | | }
|
160 | | $this->cleanupQuery();
|
161 | |
|
162 | | // Check order.
|
163 | | $sorted = $scores;
|
164 | | sort($sorted);
|
165 | | $this->assertEqual($scores, array_reverse($sorted), "Query order '$query'");
|
166 | |
|
167 | | // Check range.
|
168 | | $this->assertEqual(!count($scores) || (min($scores) > 0.0 && max($scores) <= 1.0001), TRUE, "Query scoring '$query'");
|
169 | | }
|
170 | |
|
171 | | /**
|
172 | | * Remove the temporary tables created in a query, since multiple queries per page
|
173 | | * are not supported.
|
174 | | *
|
175 | | * (Drupal 5.0 and below)
|
176 | | */
|
177 | | function cleanupQuery() {
|
178 | | db_query('DROP TABLE IF EXISTS temp_search_sids');
|
179 | | db_query('DROP TABLE IF EXISTS temp_search_results');
|
180 | | }
|
181 | |
|
182 | | }
|