Bug 452000 - Sort by keyword in Library does not work, r=dietrich
authorMarco Bonardo <mak77@bonardo.net>
Sat, 17 Jan 2009 15:45:37 +0100
changeset 23868 7c2dc72c7ace60756d8426e9bcad391afdc9e7ee
parent 23867 0689654a46ece5dea03392e6974d7de7089e3c2e
child 23869 f8642a26ef86c3dcd1c01d0366c6a2e2bfea824c
push id4764
push usermak77@bonardo.net
push dateSat, 17 Jan 2009 14:55:00 +0000
treeherdermozilla-central@a3abe1807f71 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdietrich
bugs452000
milestone1.9.2a1pre
Bug 452000 - Sort by keyword in Library does not work, r=dietrich
toolkit/components/places/src/nsNavHistoryResult.cpp
toolkit/components/places/tests/queries/head_queries.js
toolkit/components/places/tests/queries/test_sorting.js
--- a/toolkit/components/places/src/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/src/nsNavHistoryResult.cpp
@@ -978,31 +978,31 @@ PRInt32 nsNavHistoryContainerResultNode:
 
 // nsNavHistoryContainerResultNode::SortComparison_Keyword*
 PRInt32 nsNavHistoryContainerResultNode::SortComparison_KeywordLess(
     nsNavHistoryResultNode* a, nsNavHistoryResultNode* b, void* closure)
 {
   PRInt32 value = 0;
   if (a->mItemId != -1 || b->mItemId != -1) {
     // compare the keywords
-    nsAutoString aKeyword, bKeyword;
+    nsAutoString keywordA, keywordB;
     nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
     NS_ENSURE_TRUE(bookmarks, 0);
 
     nsresult rv;
     if (a->mItemId != -1) {
-      rv = bookmarks->GetKeywordForBookmark(a->mItemId, aKeyword);
+      rv = bookmarks->GetKeywordForBookmark(a->mItemId, keywordA);
       NS_ENSURE_SUCCESS(rv, 0);
     }
     if (b->mItemId != -1) {
-      rv = bookmarks->GetKeywordForBookmark(b->mItemId, aKeyword);
+      rv = bookmarks->GetKeywordForBookmark(b->mItemId, keywordB);
       NS_ENSURE_SUCCESS(rv, 0);
     }
 
-    value = SortComparison_StringLess(aKeyword, bKeyword);
+    value = SortComparison_StringLess(keywordA, keywordB);
   }
 
   // fall back to title sorting
   if (value == 0)
     value = SortComparison_TitleLess(a, b, closure);
 
   return value;
 }
--- a/toolkit/components/places/tests/queries/head_queries.js
+++ b/toolkit/components/places/tests/queries/head_queries.js
@@ -31,16 +31,18 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
+const NS_APP_HISTORY_50_FILE = "UHist";
+
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
 // Some Useful Date constants - PRTime uses microseconds, so convert
 const DAY_MICROSEC = 86400000000;
 const today = Date.now() * 1000;
 const yesterday = today - DAY_MICROSEC;
@@ -65,16 +67,21 @@ if (!profileDir) {
  // Register our own provider for the profile directory.
  // It will simply return the current directory.
  var provider = {
    getFile: function(prop, persistent) {
      persistent.value = true;
      if (prop == NS_APP_USER_PROFILE_50_DIR) {
        return dirSvc.get("CurProcD", Ci.nsIFile);
      }
+     if (prop == NS_APP_HISTORY_50_FILE) {
+       var histFile = dirSvc.get("CurProcD", Ci.nsIFile);
+       histFile.append("history.dat");
+       return histFile;
+     }
      throw Cr.NS_ERROR_FAILURE;
    },
    QueryInterface: function(iid) {
      if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
          iid.equals(Ci.nsISupports)) {
        return this;
      }
      throw Cr.NS_ERROR_NO_INTERFACE;
@@ -158,20 +165,20 @@ function populateDB(aArray) {
   aArray.forEach(function(data) {
     try {
       // make the data object into a query data object in order to create proper
       // default values for anything left unspecified
       var qdata = new queryData(data);
       if (qdata.isVisit) {
         // Then we should add a visit for this node
         var referrer = qdata.referrer ? uri(qdata.referrer) : null;
-        var placeID = histsvc.addVisit(uri(qdata.uri), qdata.lastVisit,
+        var visitId = histsvc.addVisit(uri(qdata.uri), qdata.lastVisit,
                                        referrer, qdata.transType,
                                        qdata.isRedirect, qdata.sessionID);
-        do_check_true(placeID > 0);
+        do_check_true(visitId > 0);
       }
 
       if (qdata.isDetails) {
         // Then we add extraneous page details for testing
         bhistsvc.addPageWithDetails(uri(qdata.uri), qdata.title, qdata.lastVisit);
       }
 
       if (qdata.markPageAsTyped){
@@ -226,18 +233,25 @@ function populateDB(aArray) {
       }
 
       if (qdata.isLivemark) {
         lmsvc.createLivemark(qdata.parentFolder, qdata.title, uri(qdata.uri),
                        uri(qdata.feedURI), qdata.index);
       }
 
       if (qdata.isBookmark) {
-        bmsvc.insertBookmark(qdata.parentFolder, uri(qdata.uri), qdata.index,
-                               qdata.title);
+        let itemId = bmsvc.insertBookmark(qdata.parentFolder, uri(qdata.uri),
+                                          qdata.index, qdata.title);
+        if (qdata.keyword)
+          bmsvc.setKeywordForBookmark(itemId, qdata.keyword);
+        if (qdata.dateAdded)
+          bmsvc.setItemDateAdded(itemId, qdata.dateAdded);
+        if (qdata.lastModified)
+          bmsvc.setItemLastModified(itemId, qdata.lastModified);
+
         LOG("added bookmark");
       }
 
       if (qdata.isDynContainer) {
         bmsvc.createDynamicContainer(qdata.parentFolder, qdata.title,
                                        qdata.contractId, qdata.index);
       }
     } catch (ex) {
@@ -386,8 +400,35 @@ function displayResultSet(aRoot) {
     return;
   }
 
   for (var i=0; i < aRoot.childCount; ++i) {
     LOG("Result Set URI: " + aRoot.getChild(i).uri + " Title: " +
         aRoot.getChild(i).title);
   }
 }
+
+/*
+ * Removes all bookmarks and checks for correct cleanup
+ */
+function remove_all_bookmarks() {
+  // Clear all bookmarks
+  bmsvc.removeFolderChildren(bmsvc.bookmarksMenuFolder);
+  bmsvc.removeFolderChildren(bmsvc.toolbarFolder);
+  bmsvc.removeFolderChildren(bmsvc.unfiledBookmarksFolder);
+  // Check for correct cleanup
+  check_no_bookmarks()
+}
+
+/*
+ * Checks that we don't have any bookmark
+ */
+function check_no_bookmarks() {
+  var query = histsvc.getNewQuery();
+  query.setFolders([bmsvc.toolbarFolder, bmsvc.bookmarksMenuFolder, bmsvc.unfiledBookmarksFolder], 3);
+  var options = histsvc.getNewQueryOptions();
+  options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
+  var result = histsvc.executeQuery(query, options);
+  var root = result.root;
+  root.containerOpen = true;
+  do_check_eq(root.childCount, 0);
+  root.containerOpen = false;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/queries/test_sorting.js
@@ -0,0 +1,692 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places Test Code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Corporation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Marco Bonardo <mak77@bonardo.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var tests = [];
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_NONE,
+
+  setup: function() {
+    LOG("Sorting test 1: SORT BY NONE");
+
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://urlB.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleB",
+        keyword: "keywordB",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://urlA.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleA",
+        keyword: "keywordA",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://urlC.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleC",
+        keyword: "keywordC",
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData;
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    // no reverse sorting for SORT BY NONE
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_TITLE_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 2: SORT BY TITLE");
+
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://urlB.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleB",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://urlA.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleA",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://urlC.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "titleC",
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData = [
+      this._unsortedData[1],
+      this._unsortedData[0],
+      this._unsortedData[2],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_TITLE_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_DATE_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 3: SORT BY DATE");
+
+    var timeInMicroseconds = Date.now() * 1000;
+    this._unsortedData = [
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://moz.com/",
+        lastVisit: timeInMicroseconds - 2,
+        title: "I",
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://is.com/",
+        lastVisit: timeInMicroseconds - 1,
+        title: "love",
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://best.com/",
+        lastVisit: timeInMicroseconds - 3,
+        title: "moz",
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData = [
+      this._unsortedData[2],
+      this._unsortedData[0],
+      this._unsortedData[1],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_DATE_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_URI_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 4: SORT BY URI");
+
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://is.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "I",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://moz.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "love",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://best.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "moz",
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData = [
+      this._unsortedData[2],
+      this._unsortedData[0],
+      this._unsortedData[1],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_URI_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_VISITCOUNT_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 5: SORT BY VISITCOUNT");
+
+    var timeInMicroseconds = Date.now() * 1000;
+    this._unsortedData = [
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://moz.com/",
+        lastVisit: timeInMicroseconds,
+        title: "I",
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://is.com/",
+        lastVisit: timeInMicroseconds,
+        title: "love",
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://best.com/",
+        lastVisit: timeInMicroseconds,
+        title: "moz",
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData = [
+      this._unsortedData[0],
+      this._unsortedData[2],
+      this._unsortedData[1],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+    // add visits to increase visit count
+    histsvc.addVisit(uri("http://is.com/"), timeInMicroseconds, null,
+                     histsvc.TRANSITION_TYPED, false, 0);
+    histsvc.addVisit(uri("http://is.com/"), timeInMicroseconds, null,
+                     histsvc.TRANSITION_TYPED, false, 0);
+    histsvc.addVisit(uri("http://best.com/"), timeInMicroseconds, null,
+                     histsvc.TRANSITION_TYPED, false, 0);                     
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_VISITCOUNT_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_KEYWORD_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 6: SORT BY KEYWORD");
+
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://moz.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "I",
+        keyword: "a",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://is.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "love",
+        keyword: "c",
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://best.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "moz",
+        keyword: "b",
+        isInQuery: true },
+    ];
+
+    this._sortedData = [
+      this._unsortedData[0],
+      this._unsortedData[2],
+      this._unsortedData[1],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_KEYWORD_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_DATEADDED_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 7: SORT BY DATEADDED");
+
+    var timeInMicroseconds = Date.now() * 1000;
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://moz.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "I",
+        dateAdded: timeInMicroseconds -1,
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://is.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "love",
+        dateAdded: timeInMicroseconds - 2,
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://best.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "moz",
+        dateAdded: timeInMicroseconds,
+        isInQuery: true },
+    ];
+
+    this._sortedData = [
+      this._unsortedData[1],
+      this._unsortedData[0],
+      this._unsortedData[2],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_DATEADDED_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_LASTMODIFIED_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 8: SORT BY LASTMODIFIED");
+
+    var timeInMicroseconds = Date.now() * 1000;
+    this._unsortedData = [
+      { isBookmark: true,
+        uri: "http://moz.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "I",
+        lastModified: timeInMicroseconds -1,
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://is.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "love",
+        lastModified: timeInMicroseconds - 2,
+        isInQuery: true },
+
+      { isBookmark: true,
+        uri: "http://best.com/",
+        parentFolder: bmsvc.toolbarFolder,
+        index: bmsvc.DEFAULT_INDEX,
+        title: "moz",
+        lastModified: timeInMicroseconds,
+        isInQuery: true },
+    ];
+
+    this._sortedData = [
+      this._unsortedData[1],
+      this._unsortedData[0],
+      this._unsortedData[2],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+    query.setFolders([bmsvc.toolbarFolder], 1);
+    query.onlyBookmarked = true;
+    
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_LASTMODIFIED_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+// TEST 9
+// SORT_BY_TAGS_ASCENDING
+// SORT_BY_TAGS_DESCENDING
+//XXX bug 444179
+
+////////////////////////////////////////////////////////////////////////////////
+// SORT_BY_ANNOTATION_ASCENDING = 19;
+
+tests.push({
+  _sortingMode: histsvc.SORT_BY_ANNOTATION_ASCENDING,
+
+  setup: function() {
+    LOG("Sorting test 10: SORT BY ANNOTATION");
+
+    var timeInMicroseconds = Date.now() * 1000;
+    this._unsortedData = [
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://moz.com/",
+        lastVisit: timeInMicroseconds,
+        title: "I",
+        isPageAnnotation: true,
+        annoName: "sorting",
+        annoVal: 2,
+        annoFlags: 0,
+        annoExpiration: Ci.nsIAnnotationService.EXPIRE_NEVER,
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://is.com/",
+        lastVisit: timeInMicroseconds,
+        title: "love",
+        isPageAnnotation: true,
+        annoName: "sorting",
+        annoVal: 1,
+        annoFlags: 0,
+        annoExpiration: Ci.nsIAnnotationService.EXPIRE_NEVER,
+        isInQuery: true },
+
+      { isVisit: true,
+        isDetails: true,
+        uri: "http://best.com/",
+        lastVisit: timeInMicroseconds,
+        title: "moz",
+        isPageAnnotation: true,
+        annoName: "sorting",
+        annoVal: 3,
+        annoFlags: 0,
+        annoExpiration: Ci.nsIAnnotationService.EXPIRE_NEVER,
+        isInQuery: true },
+    ];
+
+    this._sortedData = this._unsortedData = [
+      this._unsortedData[1],
+      this._unsortedData[0],
+      this._unsortedData[2],
+    ];
+
+    // This function in head_queries.js creates our database with the above data
+    populateDB(this._unsortedData);                  
+  },
+
+  check: function() {
+    // Query
+    var query = histsvc.getNewQuery();
+
+    // query options
+    var options = histsvc.getNewQueryOptions();
+    options.sortingMode = this._sortingMode;
+
+    // Results - this gets the result set and opens it for reading and modification.
+    var result = histsvc.executeQuery(query, options);
+    var root = result.root;
+    root.containerOpen = true;
+    compareArrayToResult(this._sortedData, root);
+    root.containerOpen = false;
+  },
+
+  check_reverse: function() {
+    this._sortingMode = histsvc.SORT_BY_ANNOTATION_DESCENDING;
+    this._sortedData.reverse();
+    this.check();
+  }
+});
+
+////////////////////////////////////////////////////////////////////////////////
+
+function prepare_for_next_test() {
+  // Execute cleanup tasks
+  bhistsvc.removeAllPages();
+  remove_all_bookmarks();
+}
+
+/**
+ * run_test is where the magic happens.  This is automatically run by the test
+ * harness.  It is where you do the work of creating the query, running it, and
+ * playing with the result set.
+ */
+function run_test() {
+  prepare_for_next_test();
+  while (tests.length) {
+    let test = tests.shift();
+    test.setup();
+    test.check();
+    // sorting reversed, usually SORT_BY have ASC and DESC
+    test.check_reverse();
+    prepare_for_next_test();
+  }
+}