summaryrefslogtreecommitdiffstats
path: root/toolkit/components/satchel/test/unit/test_autocomplete.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/satchel/test/unit/test_autocomplete.js')
-rw-r--r--toolkit/components/satchel/test/unit/test_autocomplete.js388
1 files changed, 388 insertions, 0 deletions
diff --git a/toolkit/components/satchel/test/unit/test_autocomplete.js b/toolkit/components/satchel/test/unit/test_autocomplete.js
new file mode 100644
index 0000000000..13f66eb0f2
--- /dev/null
+++ b/toolkit/components/satchel/test/unit/test_autocomplete.js
@@ -0,0 +1,388 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var fac;
+
+var numRecords, timeGroupingSize, now;
+
+const DEFAULT_EXPIRE_DAYS = 180;
+
+function padLeft(number, length) {
+ let str = number + "";
+ while (str.length < length) {
+ str = "0" + str;
+ }
+ return str;
+}
+
+function getFormExpiryDays() {
+ if (Services.prefs.prefHasUserValue("browser.formfill.expire_days")) {
+ return Services.prefs.getIntPref("browser.formfill.expire_days");
+ }
+ return DEFAULT_EXPIRE_DAYS;
+}
+
+function run_test() {
+ // ===== test init =====
+ let testfile = do_get_file("formhistory_autocomplete.sqlite");
+ let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+
+ // Cleanup from any previous tests or failures.
+ let destFile = profileDir.clone();
+ destFile.append("formhistory.sqlite");
+ if (destFile.exists()) {
+ destFile.remove(false);
+ }
+
+ testfile.copyTo(profileDir, "formhistory.sqlite");
+
+ fac = Cc["@mozilla.org/satchel/form-autocomplete;1"].getService(
+ Ci.nsIFormAutoComplete
+ );
+
+ timeGroupingSize =
+ Services.prefs.getIntPref("browser.formfill.timeGroupingSize") *
+ 1000 *
+ 1000;
+
+ run_next_test();
+}
+
+add_test(function test0() {
+ let maxTimeGroupings = Services.prefs.getIntPref(
+ "browser.formfill.maxTimeGroupings"
+ );
+ let bucketSize = Services.prefs.getIntPref("browser.formfill.bucketSize");
+
+ // ===== Tests with constant timesUsed and varying lastUsed date =====
+ // insert 2 records per bucket to check alphabetical sort within
+ now = 1000 * Date.now();
+ numRecords = Math.ceil(maxTimeGroupings / bucketSize) * 2;
+
+ let changes = [];
+ for (let i = 0; i < numRecords; i += 2) {
+ let useDate = now - (i / 2) * bucketSize * timeGroupingSize;
+
+ changes.push({
+ op: "add",
+ fieldname: "field1",
+ value: "value" + padLeft(numRecords - 1 - i, 2),
+ timesUsed: 1,
+ firstUsed: useDate,
+ lastUsed: useDate,
+ });
+ changes.push({
+ op: "add",
+ fieldname: "field1",
+ value: "value" + padLeft(numRecords - 2 - i, 2),
+ timesUsed: 1,
+ firstUsed: useDate,
+ lastUsed: useDate,
+ });
+ }
+
+ updateFormHistory(changes, run_next_test);
+});
+
+add_test(function test1() {
+ do_log_info("Check initial state is as expected");
+
+ countEntries(null, null, function () {
+ countEntries("field1", null, function (count) {
+ Assert.ok(count > 0);
+ run_next_test();
+ });
+ });
+});
+
+add_test(function test2() {
+ do_log_info("Check search contains all entries");
+
+ fac.autoCompleteSearchAsync("field1", "", null, null, false, {
+ onSearchCompletion(aResults) {
+ Assert.equal(numRecords, aResults.matchCount);
+ run_next_test();
+ },
+ });
+});
+
+add_test(function test3() {
+ do_log_info("Check search result ordering with empty search term");
+
+ let lastFound = numRecords;
+ fac.autoCompleteSearchAsync("field1", "", null, null, false, {
+ onSearchCompletion(aResults) {
+ for (let i = 0; i < numRecords; i += 2) {
+ Assert.equal(
+ parseInt(aResults.getValueAt(i + 1).substr(5), 10),
+ --lastFound
+ );
+ Assert.equal(
+ parseInt(aResults.getValueAt(i).substr(5), 10),
+ --lastFound
+ );
+ }
+ run_next_test();
+ },
+ });
+});
+
+add_test(function test4() {
+ do_log_info('Check search result ordering with "v"');
+
+ let lastFound = numRecords;
+ fac.autoCompleteSearchAsync("field1", "v", null, null, false, {
+ onSearchCompletion(aResults) {
+ for (let i = 0; i < numRecords; i += 2) {
+ Assert.equal(
+ parseInt(aResults.getValueAt(i + 1).substr(5), 10),
+ --lastFound
+ );
+ Assert.equal(
+ parseInt(aResults.getValueAt(i).substr(5), 10),
+ --lastFound
+ );
+ }
+ run_next_test();
+ },
+ });
+});
+
+const timesUsedSamples = 20;
+
+add_test(function test5() {
+ do_log_info("Begin tests with constant use dates and varying timesUsed");
+
+ let changes = [];
+ for (let i = 0; i < timesUsedSamples; i++) {
+ let timesUsed = timesUsedSamples - i;
+ let change = {
+ op: "add",
+ fieldname: "field2",
+ value: "value" + (timesUsedSamples - 1 - i),
+ timesUsed: timesUsed * timeGroupingSize,
+ firstUsed: now,
+ lastUsed: now,
+ };
+ changes.push(change);
+ }
+ updateFormHistory(changes, run_next_test);
+});
+
+add_test(function test6() {
+ do_log_info("Check search result ordering with empty search term");
+
+ let lastFound = timesUsedSamples;
+ fac.autoCompleteSearchAsync("field2", "", null, null, false, {
+ onSearchCompletion(aResults) {
+ for (let i = 0; i < timesUsedSamples; i++) {
+ Assert.equal(
+ parseInt(aResults.getValueAt(i).substr(5), 10),
+ --lastFound
+ );
+ }
+ run_next_test();
+ },
+ });
+});
+
+add_test(function test7() {
+ do_log_info('Check search result ordering with "v"');
+
+ let lastFound = timesUsedSamples;
+ fac.autoCompleteSearchAsync("field2", "v", null, null, false, {
+ onSearchCompletion(aResults) {
+ for (let i = 0; i < timesUsedSamples; i++) {
+ Assert.equal(
+ parseInt(aResults.getValueAt(i).substr(5), 10),
+ --lastFound
+ );
+ }
+ run_next_test();
+ },
+ });
+});
+
+add_test(function test8() {
+ do_log_info(
+ 'Check that "senior citizen" entries get a bonus (browser.formfill.agedBonus)'
+ );
+
+ let agedDate =
+ 1000 * (Date.now() - getFormExpiryDays() * 24 * 60 * 60 * 1000);
+
+ let changes = [];
+ changes.push({
+ op: "add",
+ fieldname: "field3",
+ value: "old but not senior",
+ timesUsed: 100,
+ firstUsed: agedDate + 60 * 1000 * 1000,
+ lastUsed: now,
+ });
+ changes.push({
+ op: "add",
+ fieldname: "field3",
+ value: "senior citizen",
+ timesUsed: 100,
+ firstUsed: agedDate - 60 * 1000 * 1000,
+ lastUsed: now,
+ });
+ updateFormHistory(changes, run_next_test);
+});
+
+add_test(function test9() {
+ fac.autoCompleteSearchAsync("field3", "", null, null, false, {
+ onSearchCompletion(aResults) {
+ Assert.equal(aResults.getValueAt(0), "senior citizen");
+ Assert.equal(aResults.getValueAt(1), "old but not senior");
+ run_next_test();
+ },
+ });
+});
+
+add_test(function test10() {
+ do_log_info("Check entries that are really old or in the future");
+
+ let changes = [];
+ changes.push({
+ op: "add",
+ fieldname: "field4",
+ value: "date of 0",
+ timesUsed: 1,
+ firstUsed: 0,
+ lastUsed: 0,
+ });
+ changes.push({
+ op: "add",
+ fieldname: "field4",
+ value: "in the future 1",
+ timesUsed: 1,
+ firstUsed: 0,
+ lastUsed: now * 2,
+ });
+ changes.push({
+ op: "add",
+ fieldname: "field4",
+ value: "in the future 2",
+ timesUsed: 1,
+ firstUsed: now * 2,
+ lastUsed: now * 2,
+ });
+ updateFormHistory(changes, run_next_test);
+});
+
+add_test(function test11() {
+ fac.autoCompleteSearchAsync("field4", "", null, null, false, {
+ onSearchCompletion(aResults) {
+ Assert.equal(aResults.matchCount, 3);
+ run_next_test();
+ },
+ });
+});
+
+var syncValues = ["sync1", "sync1a", "sync2", "sync3"];
+
+add_test(function test12() {
+ do_log_info("Check old synchronous api");
+
+ let changes = [];
+ for (let value of syncValues) {
+ changes.push({ op: "add", fieldname: "field5", value });
+ }
+ updateFormHistory(changes, run_next_test);
+});
+
+add_test(function test_token_limit_DB() {
+ function test_token_limit_previousResult(previousResult) {
+ do_log_info(
+ "Check that the number of tokens used in a search is not capped to " +
+ "MAX_SEARCH_TOKENS when using a previousResult"
+ );
+ // This provide more accuracy since performance is less of an issue.
+ // Search for a string where the first 10 tokens match the previous value but the 11th does not
+ // when re-using a previous result.
+ fac.autoCompleteSearchAsync(
+ "field_token_cap",
+ "a b c d e f g h i j .",
+ null,
+ previousResult,
+ false,
+ {
+ onSearchCompletion(aResults) {
+ Assert.equal(
+ aResults.matchCount,
+ 0,
+ "All search tokens should be used with previous results"
+ );
+ run_next_test();
+ },
+ }
+ );
+ }
+
+ do_log_info(
+ "Check that the number of tokens used in a search is capped to MAX_SEARCH_TOKENS " +
+ "for performance when querying the DB"
+ );
+ let changes = [];
+ changes.push({
+ op: "add",
+ fieldname: "field_token_cap",
+ // value with 15 unique tokens
+ value: "a b c d e f g h i j k l m n o",
+ timesUsed: 1,
+ firstUsed: 0,
+ lastUsed: 0,
+ });
+ updateFormHistory(changes, () => {
+ // Search for a string where the first 10 tokens match the value above but the 11th does not
+ // (which would prevent the result from being returned if the 11th term was used).
+ fac.autoCompleteSearchAsync(
+ "field_token_cap",
+ "a b c d e f g h i j .",
+ null,
+ null,
+ false,
+ {
+ onSearchCompletion(aResults) {
+ Assert.equal(
+ aResults.matchCount,
+ 1,
+ "Only the first MAX_SEARCH_TOKENS tokens " +
+ "should be used for DB queries"
+ );
+ test_token_limit_previousResult(aResults);
+ },
+ }
+ );
+ });
+});
+
+add_test(async function can_search_escape_marker() {
+ await promiseUpdate({
+ op: "add",
+ fieldname: "field1",
+ value: "/* Further reading */ test",
+ timesUsed: 1,
+ firstUsed: now,
+ lastUsed: now,
+ });
+
+ fac.autoCompleteSearchAsync(
+ "field1",
+ "/* Further reading */ t",
+ null,
+ null,
+ false,
+ {
+ onSearchCompletion(aResults) {
+ Assert.equal(1, aResults.matchCount);
+ run_next_test();
+ },
+ }
+ );
+});