|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 var testnum = 0; |
|
8 var fac; |
|
9 var prefs; |
|
10 |
|
11 let numRecords, timeGroupingSize, now; |
|
12 |
|
13 const DEFAULT_EXPIRE_DAYS = 180; |
|
14 |
|
15 function padLeft(number, length) { |
|
16 var str = number + ''; |
|
17 while (str.length < length) |
|
18 str = '0' + str; |
|
19 return str; |
|
20 } |
|
21 |
|
22 function getFormExpiryDays() { |
|
23 if (prefs.prefHasUserValue("browser.formfill.expire_days")) |
|
24 return prefs.getIntPref("browser.formfill.expire_days"); |
|
25 else |
|
26 return DEFAULT_EXPIRE_DAYS; |
|
27 } |
|
28 |
|
29 function run_test() { |
|
30 // ===== test init ===== |
|
31 var testfile = do_get_file("formhistory_autocomplete.sqlite"); |
|
32 var profileDir = dirSvc.get("ProfD", Ci.nsIFile); |
|
33 |
|
34 // Cleanup from any previous tests or failures. |
|
35 var destFile = profileDir.clone(); |
|
36 destFile.append("formhistory.sqlite"); |
|
37 if (destFile.exists()) |
|
38 destFile.remove(false); |
|
39 |
|
40 testfile.copyTo(profileDir, "formhistory.sqlite"); |
|
41 |
|
42 fac = Cc["@mozilla.org/satchel/form-autocomplete;1"]. |
|
43 getService(Ci.nsIFormAutoComplete); |
|
44 prefs = Cc["@mozilla.org/preferences-service;1"]. |
|
45 getService(Ci.nsIPrefBranch); |
|
46 |
|
47 timeGroupingSize = prefs.getIntPref("browser.formfill.timeGroupingSize") * 1000 * 1000; |
|
48 |
|
49 run_next_test(); |
|
50 } |
|
51 |
|
52 add_test(function test0() { |
|
53 var maxTimeGroupings = prefs.getIntPref("browser.formfill.maxTimeGroupings"); |
|
54 var bucketSize = prefs.getIntPref("browser.formfill.bucketSize"); |
|
55 |
|
56 // ===== Tests with constant timesUsed and varying lastUsed date ===== |
|
57 // insert 2 records per bucket to check alphabetical sort within |
|
58 now = 1000 * Date.now(); |
|
59 numRecords = Math.ceil(maxTimeGroupings / bucketSize) * 2; |
|
60 |
|
61 let changes = [ ]; |
|
62 for (let i = 0; i < numRecords; i+=2) { |
|
63 let useDate = now - (i/2 * bucketSize * timeGroupingSize); |
|
64 |
|
65 changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 1 - i, 2), |
|
66 timesUsed: 1, firstUsed: useDate, lastUsed: useDate }); |
|
67 changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 2 - i, 2), |
|
68 timesUsed: 1, firstUsed: useDate, lastUsed: useDate }); |
|
69 } |
|
70 |
|
71 updateFormHistory(changes, run_next_test); |
|
72 }); |
|
73 |
|
74 add_test(function test1() { |
|
75 do_log_info("Check initial state is as expected"); |
|
76 |
|
77 countEntries(null, null, function (count) { |
|
78 countEntries("field1", null, function (count) { |
|
79 do_check_true(count > 0); |
|
80 run_next_test(); |
|
81 }); |
|
82 }); |
|
83 }); |
|
84 |
|
85 add_test(function test2() { |
|
86 do_log_info("Check search contains all entries"); |
|
87 |
|
88 fac.autoCompleteSearchAsync("field1", "", null, null, { |
|
89 onSearchCompletion : function(aResults) { |
|
90 do_check_eq(numRecords, aResults.matchCount); |
|
91 run_next_test(); |
|
92 } |
|
93 }); |
|
94 }); |
|
95 |
|
96 add_test(function test3() { |
|
97 do_log_info("Check search result ordering with empty search term"); |
|
98 |
|
99 let lastFound = numRecords; |
|
100 fac.autoCompleteSearchAsync("field1", "", null, null, { |
|
101 onSearchCompletion : function(aResults) { |
|
102 for (let i = 0; i < numRecords; i+=2) { |
|
103 do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound); |
|
104 do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound); |
|
105 } |
|
106 run_next_test(); |
|
107 } |
|
108 }); |
|
109 }); |
|
110 |
|
111 add_test(function test4() { |
|
112 do_log_info("Check search result ordering with \"v\""); |
|
113 |
|
114 let lastFound = numRecords; |
|
115 fac.autoCompleteSearchAsync("field1", "v", null, null, { |
|
116 onSearchCompletion : function(aResults) { |
|
117 for (let i = 0; i < numRecords; i+=2) { |
|
118 do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound); |
|
119 do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound); |
|
120 } |
|
121 run_next_test(); |
|
122 } |
|
123 }); |
|
124 }); |
|
125 |
|
126 const timesUsedSamples = 20; |
|
127 |
|
128 add_test(function test5() { |
|
129 do_log_info("Begin tests with constant use dates and varying timesUsed"); |
|
130 |
|
131 let changes = []; |
|
132 for (let i = 0; i < timesUsedSamples; i++) { |
|
133 let timesUsed = (timesUsedSamples - i); |
|
134 let change = { op : "add", fieldname: "field2", value: "value" + (timesUsedSamples - 1 - i), |
|
135 timesUsed: timesUsed * timeGroupingSize, firstUsed: now, lastUsed: now }; |
|
136 changes.push(change); |
|
137 } |
|
138 updateFormHistory(changes, run_next_test); |
|
139 }); |
|
140 |
|
141 add_test(function test6() { |
|
142 do_log_info("Check search result ordering with empty search term"); |
|
143 |
|
144 let lastFound = timesUsedSamples; |
|
145 fac.autoCompleteSearchAsync("field2", "", null, null, { |
|
146 onSearchCompletion : function(aResults) { |
|
147 for (let i = 0; i < timesUsedSamples; i++) { |
|
148 do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound); |
|
149 } |
|
150 run_next_test(); |
|
151 } |
|
152 }); |
|
153 }); |
|
154 |
|
155 add_test(function test7() { |
|
156 do_log_info("Check search result ordering with \"v\""); |
|
157 |
|
158 let lastFound = timesUsedSamples; |
|
159 fac.autoCompleteSearchAsync("field2", "v", null, null, { |
|
160 onSearchCompletion : function(aResults) { |
|
161 for (let i = 0; i < timesUsedSamples; i++) { |
|
162 do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound); |
|
163 } |
|
164 run_next_test(); |
|
165 } |
|
166 }); |
|
167 }); |
|
168 |
|
169 add_test(function test8() { |
|
170 do_log_info("Check that \"senior citizen\" entries get a bonus (browser.formfill.agedBonus)"); |
|
171 |
|
172 let agedDate = 1000 * (Date.now() - getFormExpiryDays() * 24 * 60 * 60 * 1000); |
|
173 |
|
174 let changes = [ ]; |
|
175 changes.push({ op : "add", fieldname: "field3", value: "old but not senior", |
|
176 timesUsed: 100, firstUsed: (agedDate + 60 * 1000 * 1000), lastUsed: now }); |
|
177 changes.push({ op : "add", fieldname: "field3", value: "senior citizen", |
|
178 timesUsed: 100, firstUsed: (agedDate - 60 * 1000 * 1000), lastUsed: now }); |
|
179 updateFormHistory(changes, run_next_test); |
|
180 }); |
|
181 |
|
182 add_test(function test9() { |
|
183 fac.autoCompleteSearchAsync("field3", "", null, null, { |
|
184 onSearchCompletion : function(aResults) { |
|
185 do_check_eq(aResults.getValueAt(0), "senior citizen"); |
|
186 do_check_eq(aResults.getValueAt(1), "old but not senior"); |
|
187 run_next_test(); |
|
188 } |
|
189 }); |
|
190 }); |
|
191 |
|
192 add_test(function test10() { |
|
193 do_log_info("Check entries that are really old or in the future"); |
|
194 |
|
195 let changes = [ ]; |
|
196 changes.push({ op : "add", fieldname: "field4", value: "date of 0", |
|
197 timesUsed: 1, firstUsed: 0, lastUsed: 0 }); |
|
198 changes.push({ op : "add", fieldname: "field4", value: "in the future 1", |
|
199 timesUsed: 1, firstUsed: 0, lastUsed: now * 2 }); |
|
200 changes.push({ op : "add", fieldname: "field4", value: "in the future 2", |
|
201 timesUsed: 1, firstUsed: now * 2, lastUsed: now * 2 }); |
|
202 updateFormHistory(changes, run_next_test); |
|
203 }); |
|
204 |
|
205 add_test(function test11() { |
|
206 fac.autoCompleteSearchAsync("field4", "", null, null, { |
|
207 onSearchCompletion : function(aResults) { |
|
208 do_check_eq(aResults.matchCount, 3); |
|
209 run_next_test(); |
|
210 } |
|
211 }); |
|
212 }); |
|
213 |
|
214 let syncValues = ["sync1", "sync1a", "sync2", "sync3"] |
|
215 |
|
216 add_test(function test12() { |
|
217 do_log_info("Check old synchronous api"); |
|
218 |
|
219 let changes = [ ]; |
|
220 for (let value of syncValues) { |
|
221 changes.push({ op : "add", fieldname: "field5", value: value }); |
|
222 } |
|
223 updateFormHistory(changes, run_next_test); |
|
224 }); |
|
225 |
|
226 add_test(function test13() { |
|
227 let autocompleteService = Cc["@mozilla.org/satchel/form-autocomplete;1"].getService(Ci.nsIFormAutoComplete); |
|
228 let results = autocompleteService.autoCompleteSearch("field5", "", null, null); |
|
229 do_check_eq(results.matchCount, syncValues.length, "synchronous matchCount"); |
|
230 for (let i = 0; i < results.matchCount; i++) { |
|
231 do_check_eq(results.getValueAt(i), syncValues[i]); |
|
232 } |
|
233 |
|
234 let results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null); |
|
235 do_check_eq(results.matchCount, 2, "synchronous matchCount"); |
|
236 do_check_eq(results.getValueAt(0), "sync1"); |
|
237 do_check_eq(results.getValueAt(1), "sync1a"); |
|
238 run_next_test(); |
|
239 }); |
|
240 |
|
241 add_test(function test_token_limit_DB() { |
|
242 function test_token_limit_previousResult(previousResult) { |
|
243 do_log_info("Check that the number of tokens used in a search is not capped to " + |
|
244 "MAX_SEARCH_TOKENS when using a previousResult"); |
|
245 // This provide more accuracy since performance is less of an issue. |
|
246 // Search for a string where the first 10 tokens match the previous value but the 11th does not |
|
247 // when re-using a previous result. |
|
248 fac.autoCompleteSearchAsync("field_token_cap", |
|
249 "a b c d e f g h i j .", |
|
250 null, previousResult, { |
|
251 onSearchCompletion : function(aResults) { |
|
252 do_check_eq(aResults.matchCount, 0, |
|
253 "All search tokens should be used with " + |
|
254 "previous results"); |
|
255 run_next_test(); |
|
256 } |
|
257 }); |
|
258 } |
|
259 |
|
260 do_log_info("Check that the number of tokens used in a search is capped to MAX_SEARCH_TOKENS " + |
|
261 "for performance when querying the DB"); |
|
262 let changes = [ ]; |
|
263 changes.push({ op : "add", fieldname: "field_token_cap", |
|
264 // value with 15 unique tokens |
|
265 value: "a b c d e f g h i j k l m n o", |
|
266 timesUsed: 1, firstUsed: 0, lastUsed: 0 }); |
|
267 updateFormHistory(changes, () => { |
|
268 // Search for a string where the first 10 tokens match the value above but the 11th does not |
|
269 // (which would prevent the result from being returned if the 11th term was used). |
|
270 fac.autoCompleteSearchAsync("field_token_cap", |
|
271 "a b c d e f g h i j .", |
|
272 null, null, { |
|
273 onSearchCompletion : function(aResults) { |
|
274 do_check_eq(aResults.matchCount, 1, |
|
275 "Only the first MAX_SEARCH_TOKENS tokens " + |
|
276 "should be used for DB queries"); |
|
277 test_token_limit_previousResult(aResults); |
|
278 } |
|
279 }); |
|
280 }); |
|
281 }); |