1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/satchel/test/unit/test_autocomplete.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,281 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +var testnum = 0; 1.11 +var fac; 1.12 +var prefs; 1.13 + 1.14 +let numRecords, timeGroupingSize, now; 1.15 + 1.16 +const DEFAULT_EXPIRE_DAYS = 180; 1.17 + 1.18 +function padLeft(number, length) { 1.19 + var str = number + ''; 1.20 + while (str.length < length) 1.21 + str = '0' + str; 1.22 + return str; 1.23 +} 1.24 + 1.25 +function getFormExpiryDays() { 1.26 + if (prefs.prefHasUserValue("browser.formfill.expire_days")) 1.27 + return prefs.getIntPref("browser.formfill.expire_days"); 1.28 + else 1.29 + return DEFAULT_EXPIRE_DAYS; 1.30 +} 1.31 + 1.32 +function run_test() { 1.33 + // ===== test init ===== 1.34 + var testfile = do_get_file("formhistory_autocomplete.sqlite"); 1.35 + var profileDir = dirSvc.get("ProfD", Ci.nsIFile); 1.36 + 1.37 + // Cleanup from any previous tests or failures. 1.38 + var destFile = profileDir.clone(); 1.39 + destFile.append("formhistory.sqlite"); 1.40 + if (destFile.exists()) 1.41 + destFile.remove(false); 1.42 + 1.43 + testfile.copyTo(profileDir, "formhistory.sqlite"); 1.44 + 1.45 + fac = Cc["@mozilla.org/satchel/form-autocomplete;1"]. 1.46 + getService(Ci.nsIFormAutoComplete); 1.47 + prefs = Cc["@mozilla.org/preferences-service;1"]. 1.48 + getService(Ci.nsIPrefBranch); 1.49 + 1.50 + timeGroupingSize = prefs.getIntPref("browser.formfill.timeGroupingSize") * 1000 * 1000; 1.51 + 1.52 + run_next_test(); 1.53 +} 1.54 + 1.55 +add_test(function test0() { 1.56 + var maxTimeGroupings = prefs.getIntPref("browser.formfill.maxTimeGroupings"); 1.57 + var bucketSize = prefs.getIntPref("browser.formfill.bucketSize"); 1.58 + 1.59 + // ===== Tests with constant timesUsed and varying lastUsed date ===== 1.60 + // insert 2 records per bucket to check alphabetical sort within 1.61 + now = 1000 * Date.now(); 1.62 + numRecords = Math.ceil(maxTimeGroupings / bucketSize) * 2; 1.63 + 1.64 + let changes = [ ]; 1.65 + for (let i = 0; i < numRecords; i+=2) { 1.66 + let useDate = now - (i/2 * bucketSize * timeGroupingSize); 1.67 + 1.68 + changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 1 - i, 2), 1.69 + timesUsed: 1, firstUsed: useDate, lastUsed: useDate }); 1.70 + changes.push({ op : "add", fieldname: "field1", value: "value" + padLeft(numRecords - 2 - i, 2), 1.71 + timesUsed: 1, firstUsed: useDate, lastUsed: useDate }); 1.72 + } 1.73 + 1.74 + updateFormHistory(changes, run_next_test); 1.75 +}); 1.76 + 1.77 +add_test(function test1() { 1.78 + do_log_info("Check initial state is as expected"); 1.79 + 1.80 + countEntries(null, null, function (count) { 1.81 + countEntries("field1", null, function (count) { 1.82 + do_check_true(count > 0); 1.83 + run_next_test(); 1.84 + }); 1.85 + }); 1.86 +}); 1.87 + 1.88 +add_test(function test2() { 1.89 + do_log_info("Check search contains all entries"); 1.90 + 1.91 + fac.autoCompleteSearchAsync("field1", "", null, null, { 1.92 + onSearchCompletion : function(aResults) { 1.93 + do_check_eq(numRecords, aResults.matchCount); 1.94 + run_next_test(); 1.95 + } 1.96 + }); 1.97 +}); 1.98 + 1.99 +add_test(function test3() { 1.100 + do_log_info("Check search result ordering with empty search term"); 1.101 + 1.102 + let lastFound = numRecords; 1.103 + fac.autoCompleteSearchAsync("field1", "", null, null, { 1.104 + onSearchCompletion : function(aResults) { 1.105 + for (let i = 0; i < numRecords; i+=2) { 1.106 + do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound); 1.107 + do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound); 1.108 + } 1.109 + run_next_test(); 1.110 + } 1.111 + }); 1.112 +}); 1.113 + 1.114 +add_test(function test4() { 1.115 + do_log_info("Check search result ordering with \"v\""); 1.116 + 1.117 + let lastFound = numRecords; 1.118 + fac.autoCompleteSearchAsync("field1", "v", null, null, { 1.119 + onSearchCompletion : function(aResults) { 1.120 + for (let i = 0; i < numRecords; i+=2) { 1.121 + do_check_eq(parseInt(aResults.getValueAt(i + 1).substr(5), 10), --lastFound); 1.122 + do_check_eq(parseInt(aResults.getValueAt(i).substr(5), 10), --lastFound); 1.123 + } 1.124 + run_next_test(); 1.125 + } 1.126 + }); 1.127 +}); 1.128 + 1.129 +const timesUsedSamples = 20; 1.130 + 1.131 +add_test(function test5() { 1.132 + do_log_info("Begin tests with constant use dates and varying timesUsed"); 1.133 + 1.134 + let changes = []; 1.135 + for (let i = 0; i < timesUsedSamples; i++) { 1.136 + let timesUsed = (timesUsedSamples - i); 1.137 + let change = { op : "add", fieldname: "field2", value: "value" + (timesUsedSamples - 1 - i), 1.138 + timesUsed: timesUsed * timeGroupingSize, firstUsed: now, lastUsed: now }; 1.139 + changes.push(change); 1.140 + } 1.141 + updateFormHistory(changes, run_next_test); 1.142 +}); 1.143 + 1.144 +add_test(function test6() { 1.145 + do_log_info("Check search result ordering with empty search term"); 1.146 + 1.147 + let lastFound = timesUsedSamples; 1.148 + fac.autoCompleteSearchAsync("field2", "", null, null, { 1.149 + onSearchCompletion : function(aResults) { 1.150 + for (let i = 0; i < timesUsedSamples; i++) { 1.151 + do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound); 1.152 + } 1.153 + run_next_test(); 1.154 + } 1.155 + }); 1.156 +}); 1.157 + 1.158 +add_test(function test7() { 1.159 + do_log_info("Check search result ordering with \"v\""); 1.160 + 1.161 + let lastFound = timesUsedSamples; 1.162 + fac.autoCompleteSearchAsync("field2", "v", null, null, { 1.163 + onSearchCompletion : function(aResults) { 1.164 + for (let i = 0; i < timesUsedSamples; i++) { 1.165 + do_check_eq(parseInt(aResults.getValueAt(i).substr(5)), --lastFound); 1.166 + } 1.167 + run_next_test(); 1.168 + } 1.169 + }); 1.170 +}); 1.171 + 1.172 +add_test(function test8() { 1.173 + do_log_info("Check that \"senior citizen\" entries get a bonus (browser.formfill.agedBonus)"); 1.174 + 1.175 + let agedDate = 1000 * (Date.now() - getFormExpiryDays() * 24 * 60 * 60 * 1000); 1.176 + 1.177 + let changes = [ ]; 1.178 + changes.push({ op : "add", fieldname: "field3", value: "old but not senior", 1.179 + timesUsed: 100, firstUsed: (agedDate + 60 * 1000 * 1000), lastUsed: now }); 1.180 + changes.push({ op : "add", fieldname: "field3", value: "senior citizen", 1.181 + timesUsed: 100, firstUsed: (agedDate - 60 * 1000 * 1000), lastUsed: now }); 1.182 + updateFormHistory(changes, run_next_test); 1.183 +}); 1.184 + 1.185 +add_test(function test9() { 1.186 + fac.autoCompleteSearchAsync("field3", "", null, null, { 1.187 + onSearchCompletion : function(aResults) { 1.188 + do_check_eq(aResults.getValueAt(0), "senior citizen"); 1.189 + do_check_eq(aResults.getValueAt(1), "old but not senior"); 1.190 + run_next_test(); 1.191 + } 1.192 + }); 1.193 +}); 1.194 + 1.195 +add_test(function test10() { 1.196 + do_log_info("Check entries that are really old or in the future"); 1.197 + 1.198 + let changes = [ ]; 1.199 + changes.push({ op : "add", fieldname: "field4", value: "date of 0", 1.200 + timesUsed: 1, firstUsed: 0, lastUsed: 0 }); 1.201 + changes.push({ op : "add", fieldname: "field4", value: "in the future 1", 1.202 + timesUsed: 1, firstUsed: 0, lastUsed: now * 2 }); 1.203 + changes.push({ op : "add", fieldname: "field4", value: "in the future 2", 1.204 + timesUsed: 1, firstUsed: now * 2, lastUsed: now * 2 }); 1.205 + updateFormHistory(changes, run_next_test); 1.206 +}); 1.207 + 1.208 +add_test(function test11() { 1.209 + fac.autoCompleteSearchAsync("field4", "", null, null, { 1.210 + onSearchCompletion : function(aResults) { 1.211 + do_check_eq(aResults.matchCount, 3); 1.212 + run_next_test(); 1.213 + } 1.214 + }); 1.215 +}); 1.216 + 1.217 +let syncValues = ["sync1", "sync1a", "sync2", "sync3"] 1.218 + 1.219 +add_test(function test12() { 1.220 + do_log_info("Check old synchronous api"); 1.221 + 1.222 + let changes = [ ]; 1.223 + for (let value of syncValues) { 1.224 + changes.push({ op : "add", fieldname: "field5", value: value }); 1.225 + } 1.226 + updateFormHistory(changes, run_next_test); 1.227 +}); 1.228 + 1.229 +add_test(function test13() { 1.230 + let autocompleteService = Cc["@mozilla.org/satchel/form-autocomplete;1"].getService(Ci.nsIFormAutoComplete); 1.231 + let results = autocompleteService.autoCompleteSearch("field5", "", null, null); 1.232 + do_check_eq(results.matchCount, syncValues.length, "synchronous matchCount"); 1.233 + for (let i = 0; i < results.matchCount; i++) { 1.234 + do_check_eq(results.getValueAt(i), syncValues[i]); 1.235 + } 1.236 + 1.237 + let results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null); 1.238 + do_check_eq(results.matchCount, 2, "synchronous matchCount"); 1.239 + do_check_eq(results.getValueAt(0), "sync1"); 1.240 + do_check_eq(results.getValueAt(1), "sync1a"); 1.241 + run_next_test(); 1.242 +}); 1.243 + 1.244 +add_test(function test_token_limit_DB() { 1.245 + function test_token_limit_previousResult(previousResult) { 1.246 + do_log_info("Check that the number of tokens used in a search is not capped to " + 1.247 + "MAX_SEARCH_TOKENS when using a previousResult"); 1.248 + // This provide more accuracy since performance is less of an issue. 1.249 + // Search for a string where the first 10 tokens match the previous value but the 11th does not 1.250 + // when re-using a previous result. 1.251 + fac.autoCompleteSearchAsync("field_token_cap", 1.252 + "a b c d e f g h i j .", 1.253 + null, previousResult, { 1.254 + onSearchCompletion : function(aResults) { 1.255 + do_check_eq(aResults.matchCount, 0, 1.256 + "All search tokens should be used with " + 1.257 + "previous results"); 1.258 + run_next_test(); 1.259 + } 1.260 + }); 1.261 + } 1.262 + 1.263 + do_log_info("Check that the number of tokens used in a search is capped to MAX_SEARCH_TOKENS " + 1.264 + "for performance when querying the DB"); 1.265 + let changes = [ ]; 1.266 + changes.push({ op : "add", fieldname: "field_token_cap", 1.267 + // value with 15 unique tokens 1.268 + value: "a b c d e f g h i j k l m n o", 1.269 + timesUsed: 1, firstUsed: 0, lastUsed: 0 }); 1.270 + updateFormHistory(changes, () => { 1.271 + // Search for a string where the first 10 tokens match the value above but the 11th does not 1.272 + // (which would prevent the result from being returned if the 11th term was used). 1.273 + fac.autoCompleteSearchAsync("field_token_cap", 1.274 + "a b c d e f g h i j .", 1.275 + null, null, { 1.276 + onSearchCompletion : function(aResults) { 1.277 + do_check_eq(aResults.matchCount, 1, 1.278 + "Only the first MAX_SEARCH_TOKENS tokens " + 1.279 + "should be used for DB queries"); 1.280 + test_token_limit_previousResult(aResults); 1.281 + } 1.282 + }); 1.283 + }); 1.284 +});