Bug 633266 - nsINavHistoryObserver: also pass in GUID whenever we pass in a URI. r=mak
Part 1: Tests
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -605,40 +605,60 @@ function do_check_valid_places_guid(aGui
{
if (!aStack) {
aStack = Components.stack.caller;
}
do_check_true(/^[a-zA-Z0-9\-_]{12}$/.test(aGuid), aStack);
}
/**
+ * Retrieves the guid for a given uri.
+ *
+ * @param aURI
+ * The uri to check.
+ * @param [optional] aStack
+ * The stack frame used to report the error.
+ * @return the associated the guid.
+ */
+function do_get_guid_for_uri(aURI,
+ aStack)
+{
+ if (!aStack) {
+ aStack = Components.stack.caller;
+ }
+ let stmt = DBConn().createStatement(
+ "SELECT guid "
+ + "FROM moz_places "
+ + "WHERE url = :url "
+ );
+ stmt.params.url = aURI.spec;
+ do_check_true(stmt.executeStep(), aStack);
+ let guid = stmt.row.guid;
+ stmt.finalize();
+ do_check_valid_places_guid(guid, aStack);
+ return guid;
+}
+
+/**
* Tests that a guid was set in moz_places for a given uri.
*
* @param aURI
* The uri to check.
* @param [optional] aGUID
* The expected guid in the database.
*/
function do_check_guid_for_uri(aURI,
aGUID)
{
let caller = Components.stack.caller;
- let stmt = DBConn().createStatement(
- "SELECT guid "
- + "FROM moz_places "
- + "WHERE url = :url "
- );
- stmt.params.url = aURI.spec;
- do_check_true(stmt.executeStep(), caller);
- do_check_valid_places_guid(stmt.row.guid, caller);
+ let guid = do_get_guid_for_uri(aURI, caller);
if (aGUID) {
do_check_valid_places_guid(aGUID, caller);
- do_check_eq(stmt.row.guid, aGUID, caller);
+ do_check_eq(guid, aGUID, caller);
}
- stmt.finalize();
}
/**
* Logs info to the console in the standard way (includes the filename).
*
* @param aMessage
* The message to log to the console.
*/
--- a/toolkit/components/places/tests/unit/test_async_history_api.js
+++ b/toolkit/components/places/tests/unit/test_async_history_api.js
@@ -102,34 +102,37 @@ TitleChangedObserver.prototype = {
*
* @param aURI
* The URI of the page we expect a notification for.
* @param aCallback
* The method to call when we have gotten the proper notification about
* being visited.
*/
function VisitObserver(aURI,
+ aGUID,
aCallback)
{
this.uri = aURI;
+ this.guid = aGUID;
this.callback = aCallback;
}
VisitObserver.prototype = {
__proto__: NavHistoryObserver.prototype,
onVisit: function(aURI,
aVisitId,
aTime,
aSessionId,
aReferringId,
- aTransitionType)
+ aTransitionType,
+ aGUID)
{
do_log_info("onVisit(" + aURI.spec + ", " + aVisitId + ", " + aTime +
", " + aSessionId + ", " + aReferringId + ", " +
- aTransitionType + ")");
- if (!this.uri.equals(aURI)) {
+ aTransitionType + ", " + aGUID + ")");
+ if (!this.uri.equals(aURI) || this.guid != aGUID) {
return;
}
this.callback(aTime, aTransitionType);
},
};
/**
* Tests that a title was set properly in the database.
@@ -1168,31 +1171,33 @@ function test_title_change_notifies()
gHistory.updatePlaces(place);
}
function test_visit_notifies()
{
// There are two observers we need to see for each visit. One is an
// nsINavHistoryObserver and the other is the uri-visit-saved observer topic.
let place = {
+ guid: "abcdefghijkl",
uri: NetUtil.newURI(TEST_DOMAIN + "test_visit_notifies"),
visits: [
new VisitInfo(),
],
};
do_check_false(gGlobalHistory.isVisited(place.uri));
let callbackCount = 0;
let finisher = function() {
if (++callbackCount == 2) {
waitForAsyncUpdates(run_next_test);
}
}
- let visitObserver = new VisitObserver(place.uri, function(aVisitDate,
- aTransitionType) {
+ let visitObserver = new VisitObserver(place.uri, place.guid,
+ function(aVisitDate,
+ aTransitionType) {
let visit = place.visits[0];
do_check_eq(visit.visitDate, aVisitDate);
do_check_eq(visit.transitionType, aTransitionType);
PlacesUtils.history.removeObserver(visitObserver);
finisher();
});
PlacesUtils.history.addObserver(visitObserver, false);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_history_observer.js
@@ -0,0 +1,91 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Generic nsINavHistoryObserver that doesn't implement anything, but provides
+ * dummy methods to prevent errors about an object not having a certain method.
+ */
+function NavHistoryObserver() {
+}
+NavHistoryObserver.prototype = {
+ onBeginUpdateBatch: function() { },
+ onEndUpdateBatch: function() { },
+ onVisit: function() { },
+ onTitleChanged: function() { },
+ onBeforeDeleteURI: function() { },
+ onDeleteURI: function() { },
+ onClearHistory: function() { },
+ onPageChanged: function() { },
+ onDeleteVisits: function() { },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
+};
+
+/**
+ * Registers a one-time history observer for and calls the callback
+ * when the specified nsINavHistoryObserver method is called.
+ */
+function onNotify(callback) {
+ let obs = new NavHistoryObserver();
+ obs[callback.name] = function () {
+ PlacesUtils.history.removeObserver(this);
+ callback.apply(this, arguments);
+ };
+ PlacesUtils.history.addObserver(obs, false);
+}
+
+/**
+ * Adds a TRANSITION_TYPED visit to the history database.
+ */
+function add_visit(uri, timestamp) {
+ uri = uri || NetUtil.newURI("http://firefox.com/");
+ timestamp = timestamp || Date.now() * 1000;
+ PlacesUtils.history.addVisit(
+ uri, timestamp, null, Ci.nsINavHistoryService.TRANSITION_TYPED, false, 0);
+ return [uri, timestamp];
+}
+
+function run_test() {
+ run_next_test();
+}
+
+add_test(function test_onVisit() {
+ onNotify(function onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID,
+ aTransitionType, aGUID) {
+ do_check_true(aURI.equals(testuri));
+ do_check_true(aVisitID > 0);
+ do_check_eq(aTime, testtime);
+ do_check_eq(aSessionID, 0);
+ do_check_eq(aReferringID, 0);
+ do_check_eq(aTransitionType, Ci.nsINavHistoryService.TRANSITION_TYPED);
+ do_check_guid_for_uri(aURI, aGUID);
+
+ run_next_test();
+ });
+ let testuri = NetUtil.newURI("http://firefox.com/");
+ let testtime = Date.now() * 1000;
+ add_visit(testuri, testtime);
+});
+
+add_test(function test_onBeforeDeleteURI() {
+ onNotify(function onBeforeDeleteURI(aURI, aGUID) {
+ do_check_true(aURI.equals(testuri));
+ do_check_guid_for_uri(aURI, aGUID);
+
+ run_next_test();
+ });
+ let [testuri] = add_visit();
+ PlacesUtils.bhistory.removePage(testuri);
+});
+
+add_test(function test_onDeleteURI() {
+ onNotify(function onDeleteURI(aURI, aGUID) {
+ do_check_true(aURI.equals(testuri));
+ // Can't use do_check_guid_for_uri() here because the visit is already gone.
+ do_check_eq(aGUID, testguid);
+
+ run_next_test();
+ });
+ let [testuri] = add_visit();
+ let testguid = do_get_guid_for_uri(testuri);
+ PlacesUtils.bhistory.removePage(testuri);
+});
--- a/toolkit/components/places/tests/unit/test_onBeforeDeleteURI_observer.js
+++ b/toolkit/components/places/tests/unit/test_onBeforeDeleteURI_observer.js
@@ -63,24 +63,27 @@ Observer.prototype =
},
onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
aTransitionType, _added)
{
},
onTitleChanged: function(aURI, aPageTable)
{
},
- onBeforeDeleteURI: function(aURI)
+ onBeforeDeleteURI: function(aURI, aGUID)
{
this.removedURI = aURI;
+ this.removedGUID = aGUID;
+ do_check_guid_for_uri(aURI, aGUID);
},
- onDeleteURI: function(aURI)
+ onDeleteURI: function(aURI, aGUID)
{
do_check_false(this.checked);
do_check_true(this.removedURI.equals(aURI));
+ do_check_eq(this.removedGUID, aGUID);
this.checked = true;
},
onPageChanged: function(aURI, aWhat, aValue)
{
},
onDeleteVisits: function()
{
},
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -59,16 +59,17 @@ tail =
[test_favicons.js]
[test_frecency.js]
[test_getChildIndex.js]
[test_history.js]
[test_history_autocomplete_tags.js]
[test_history_catobs.js]
[test_history_import.js]
[test_history_notifications.js]
+[test_history_observer.js]
[test_history_removeAllPages.js]
[test_history_sidebar.js]
[test_isvisited.js]
[test_lastModified.js]
[test_livemarkService_getLivemarkIdForFeedURI.js]
[test_markpageas.js]
[test_migrateFrecency.js]
[test_moz-anno_favicon_mime_type.js]