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

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:83a8d76ee594
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/. */
6
7 /*
8
9 Autocomplete Frecency Tests
10
11 - add a visit for each score permutation
12 - search
13 - test number of matches
14 - test each item's location in results
15
16 */
17
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 }
28
29 var bucketPrefs = [
30 [ "firstBucketCutoff", "firstBucketWeight"],
31 [ "secondBucketCutoff", "secondBucketWeight"],
32 [ "thirdBucketCutoff", "thirdBucketWeight"],
33 [ "fourthBucketCutoff", "fourthBucketWeight"],
34 [ null, "defaultBucketWeight"]
35 ];
36
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 };
47
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.";
54
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) {}
65
66 if (cutoff < 1)
67 return;
68
69 // generate a date within the cutoff period
70 var dateInPeriod = (now - ((cutoff - 1) * 86400 * 1000)) * 1000;
71
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;
107
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 }
135
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 }
147
148 function AutoCompleteInput(aSearches) {
149 this.searches = aSearches;
150 }
151 AutoCompleteInput.prototype = {
152 constructor: AutoCompleteInput,
153
154 searches: null,
155
156 minResultsForPopup: 0,
157 timeout: 10,
158 searchParam: "",
159 textValue: "",
160 disableAutoComplete: false,
161 completeDefaultIndex: false,
162
163 get searchCount() {
164 return this.searches.length;
165 },
166
167 getSearchAt: function(aIndex) {
168 return this.searches[aIndex];
169 },
170
171 onSearchBegin: function() {},
172 onSearchComplete: function() {},
173
174 popupOpen: false,
175
176 popup: {
177 setSelectedIndex: function(aIndex) {},
178 invalidate: function() {},
179
180 // nsISupports implementation
181 QueryInterface: function(iid) {
182 if (iid.equals(Ci.nsISupports) ||
183 iid.equals(Ci.nsIAutoCompletePopup))
184 return this;
185
186 throw Components.results.NS_ERROR_NO_INTERFACE;
187 }
188 },
189
190 // nsISupports implementation
191 QueryInterface: function(iid) {
192 if (iid.equals(Ci.nsISupports) ||
193 iid.equals(Ci.nsIAutoCompleteInput))
194 return this;
195
196 throw Components.results.NS_ERROR_NO_INTERFACE;
197 }
198 }
199
200 function run_test()
201 {
202 run_next_test();
203 }
204
205 add_task(function test_frecency()
206 {
207 for (let [, bucket] in Iterator(bucketPrefs)) {
208 yield task_initializeBucket(bucket);
209 }
210
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);
215
216 // DEBUG
217 //results.every(function(el) { dump("result: " + el[1] + ": " + el[0].spec + " (" + el[2] + ")\n"); return true; })
218
219 yield promiseAsyncUpdates();
220
221 var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
222 getService(Components.interfaces.nsIAutoCompleteController);
223
224 // Make an AutoCompleteInput that uses our searches
225 // and confirms results on search complete
226 var input = new AutoCompleteInput(["history"]);
227
228 controller.input = input;
229
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);
233
234 var numSearchesStarted = 0;
235 input.onSearchBegin = function() {
236 numSearchesStarted++;
237 do_check_eq(numSearchesStarted, 1);
238 };
239
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);
245
246 // test that all records with non-zero frecency were matched
247 do_check_eq(controller.matchCount, results.length);
248
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 };
269
270 controller.startSearch(searchTerm);
271
272 yield deferred.promise;
273 });

mercurial