toolkit/components/places/tests/unit/test_000_frecency.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     9 Autocomplete Frecency Tests
    11 - add a visit for each score permutation
    12 - search
    13 - test number of matches
    14 - test each item's location in results
    16 */
    18 try {
    19   var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
    20                 getService(Ci.nsINavHistoryService);
    21   var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
    22               getService(Ci.nsINavBookmarksService);
    23   var prefs = Cc["@mozilla.org/preferences-service;1"].
    24               getService(Ci.nsIPrefBranch);
    25 } catch(ex) {
    26   do_throw("Could not get services\n");
    27 }
    29 var bucketPrefs = [
    30   [ "firstBucketCutoff", "firstBucketWeight"],
    31   [ "secondBucketCutoff", "secondBucketWeight"],
    32   [ "thirdBucketCutoff", "thirdBucketWeight"],
    33   [ "fourthBucketCutoff", "fourthBucketWeight"],
    34   [ null, "defaultBucketWeight"]
    35 ];
    37 var bonusPrefs = {
    38   embedVisitBonus: Ci.nsINavHistoryService.TRANSITION_EMBED,
    39   framedLinkVisitBonus: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
    40   linkVisitBonus: Ci.nsINavHistoryService.TRANSITION_LINK,
    41   typedVisitBonus: Ci.nsINavHistoryService.TRANSITION_TYPED,
    42   bookmarkVisitBonus: Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
    43   downloadVisitBonus: Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
    44   permRedirectVisitBonus: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
    45   tempRedirectVisitBonus: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
    46 };
    48 // create test data
    49 var searchTerm = "frecency";
    50 var results = [];
    51 var matchCount = 0;
    52 var now = Date.now();
    53 var prefPrefix = "places.frecency.";
    55 function task_initializeBucket(bucket) {
    56   let [cutoffName, weightName] = bucket;
    57   // get pref values
    58   var weight = 0, cutoff = 0, bonus = 0;
    59   try {
    60     weight = prefs.getIntPref(prefPrefix + weightName);
    61   } catch(ex) {}
    62   try {
    63     cutoff = prefs.getIntPref(prefPrefix + cutoffName);
    64   } catch(ex) {}
    66   if (cutoff < 1)
    67     return;
    69   // generate a date within the cutoff period
    70   var dateInPeriod = (now - ((cutoff - 1) * 86400 * 1000)) * 1000;
    72   for (let [bonusName, visitType] in Iterator(bonusPrefs)) {
    73     var frecency = -1;
    74     var calculatedURI = null;
    75     var matchTitle = "";
    76     var bonusValue = prefs.getIntPref(prefPrefix + bonusName);
    77     // unvisited (only for first cutoff date bucket)
    78     if (bonusName == "unvisitedBookmarkBonus" || bonusName == "unvisitedTypedBonus") {
    79       if (cutoffName == "firstBucketCutoff") {
    80         var points = Math.ceil(bonusValue / parseFloat(100.0) * weight);
    81         var visitCount = 1; //bonusName == "unvisitedBookmarkBonus" ? 1 : 0;
    82         frecency = Math.ceil(visitCount * points);
    83         calculatedURI = uri("http://" + searchTerm + ".com/" +
    84           bonusName + ":" + bonusValue + "/cutoff:" + cutoff +
    85           "/weight:" + weight + "/frecency:" + frecency);
    86         if (bonusName == "unvisitedBookmarkBonus") {
    87           matchTitle = searchTerm + "UnvisitedBookmark";
    88           bmsvc.insertBookmark(bmsvc.unfiledBookmarksFolder, calculatedURI, bmsvc.DEFAULT_INDEX, matchTitle);
    89         }
    90         else {
    91           matchTitle = searchTerm + "UnvisitedTyped";
    92           yield promiseAddVisits({
    93             uri: calculatedURI,
    94             title: matchTitle,
    95             transition: visitType,
    96             visitDate: now
    97           });
    98           histsvc.markPageAsTyped(calculatedURI);
    99         }
   100       }
   101     }
   102     else {
   103       // visited
   104       // visited bookmarks get the visited bookmark bonus twice
   105       if (visitType == Ci.nsINavHistoryService.TRANSITION_BOOKMARK)
   106         bonusValue = bonusValue * 2;
   108       var points = Math.ceil(1 * ((bonusValue / parseFloat(100.000000)).toFixed(6) * weight) / 1);
   109       if (!points) {
   110         if (visitType == Ci.nsINavHistoryService.TRANSITION_EMBED ||
   111             visitType == Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK ||
   112             visitType == Ci.nsINavHistoryService.TRANSITION_DOWNLOAD ||
   113             bonusName == "defaultVisitBonus")
   114           frecency = 0;
   115         else
   116           frecency = -1;
   117       }
   118       else
   119         frecency = points;
   120       calculatedURI = uri("http://" + searchTerm + ".com/" +
   121         bonusName + ":" + bonusValue + "/cutoff:" + cutoff +
   122         "/weight:" + weight + "/frecency:" + frecency);
   123       if (visitType == Ci.nsINavHistoryService.TRANSITION_BOOKMARK) {
   124         matchTitle = searchTerm + "Bookmarked";
   125         bmsvc.insertBookmark(bmsvc.unfiledBookmarksFolder, calculatedURI, bmsvc.DEFAULT_INDEX, matchTitle);
   126       }
   127       else
   128         matchTitle = calculatedURI.spec.substr(calculatedURI.spec.lastIndexOf("/")+1);
   129       yield promiseAddVisits({
   130         uri: calculatedURI,
   131         transition: visitType,
   132         visitDate: dateInPeriod
   133       });
   134     }
   136     if (calculatedURI && frecency) {
   137       results.push([calculatedURI, frecency, matchTitle]);
   138       yield promiseAddVisits({
   139         uri: calculatedURI,
   140         title: matchTitle,
   141         transition: visitType,
   142         visitDate: dateInPeriod
   143       });
   144     }
   145   }
   146 }
   148 function AutoCompleteInput(aSearches) {
   149   this.searches = aSearches;
   150 }
   151 AutoCompleteInput.prototype = {
   152   constructor: AutoCompleteInput,
   154   searches: null,
   156   minResultsForPopup: 0,
   157   timeout: 10,
   158   searchParam: "",
   159   textValue: "",
   160   disableAutoComplete: false,
   161   completeDefaultIndex: false,
   163   get searchCount() {
   164     return this.searches.length;
   165   },
   167   getSearchAt: function(aIndex) {
   168     return this.searches[aIndex];
   169   },
   171   onSearchBegin: function() {},
   172   onSearchComplete: function() {},
   174   popupOpen: false,
   176   popup: {
   177     setSelectedIndex: function(aIndex) {},
   178     invalidate: function() {},
   180     // nsISupports implementation
   181     QueryInterface: function(iid) {
   182       if (iid.equals(Ci.nsISupports) ||
   183           iid.equals(Ci.nsIAutoCompletePopup))
   184         return this;
   186       throw Components.results.NS_ERROR_NO_INTERFACE;
   187     }
   188   },
   190   // nsISupports implementation
   191   QueryInterface: function(iid) {
   192     if (iid.equals(Ci.nsISupports) ||
   193         iid.equals(Ci.nsIAutoCompleteInput))
   194       return this;
   196     throw Components.results.NS_ERROR_NO_INTERFACE;
   197   }
   198 }
   200 function run_test()
   201 {
   202   run_next_test();
   203 }
   205 add_task(function test_frecency()
   206 {
   207   for (let [, bucket] in Iterator(bucketPrefs)) {
   208     yield task_initializeBucket(bucket);
   209   }
   211   // sort results by frecency
   212   results.sort(function(a,b) b[1] - a[1]);
   213   // Make sure there's enough results returned
   214   prefs.setIntPref("browser.urlbar.maxRichResults", results.length);
   216   // DEBUG
   217   //results.every(function(el) { dump("result: " + el[1] + ": " + el[0].spec + " (" + el[2] + ")\n"); return true; })
   219   yield promiseAsyncUpdates();
   221   var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
   222                    getService(Components.interfaces.nsIAutoCompleteController);
   224   // Make an AutoCompleteInput that uses our searches
   225   // and confirms results on search complete
   226   var input = new AutoCompleteInput(["history"]);
   228   controller.input = input;
   230   // always search in history + bookmarks, no matter what the default is
   231   prefs.setIntPref("browser.urlbar.search.sources", 3);
   232   prefs.setIntPref("browser.urlbar.default.behavior", 0);
   234   var numSearchesStarted = 0;
   235   input.onSearchBegin = function() {
   236     numSearchesStarted++;
   237     do_check_eq(numSearchesStarted, 1);
   238   };
   240   let deferred = Promise.defer();
   241   input.onSearchComplete = function() {
   242     do_check_eq(numSearchesStarted, 1);
   243     do_check_eq(controller.searchStatus,
   244                 Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
   246     // test that all records with non-zero frecency were matched
   247     do_check_eq(controller.matchCount, results.length);
   249     // test that matches are sorted by frecency
   250     for (var i = 0; i < controller.matchCount; i++) {
   251       let searchURL = controller.getValueAt(i);
   252       let expectURL = results[i][0].spec;
   253       if (searchURL == expectURL) {
   254         do_check_eq(controller.getValueAt(i), results[i][0].spec);
   255         do_check_eq(controller.getCommentAt(i), results[i][2]);
   256       } else {
   257         // If the results didn't match exactly, perhaps it's still the right
   258         // frecency just in the wrong "order" (order of same frecency is
   259         // undefined), so check if frecency matches. This is okay because we
   260         // can still ensure the correct number of expected frecencies.
   261         let getFrecency = function(aURL) aURL.match(/frecency:(-?\d+)$/)[1];
   262         print("### checking for same frecency between '" + searchURL +
   263               "' and '" + expectURL + "'");
   264         do_check_eq(getFrecency(searchURL), getFrecency(expectURL));
   265       }
   266     }
   267     deferred.resolve();
   268   };
   270   controller.startSearch(searchTerm);
   272   yield deferred.promise;
   273 });

mercurial