Bug 399264 - stop hard coding folder roots in place: urls. r=dietrich
authorsdwilsh@shawnwilsher.com
Sat, 15 Mar 2008 12:39:04 -0700
changeset 13123 1199e8104a561bf2248e7ae9d5b11e177323187a
parent 13122 461b7702a5073d01126c4eeb3e8a119e7d0ab4fe
child 13124 c449cd45567d984678d87256799945ffdb418b2b
push idunknown
push userunknown
push dateunknown
reviewersdietrich
bugs399264
milestone1.9b5pre
Bug 399264 - stop hard coding folder roots in place: urls. r=dietrich
browser/base/content/browser-menubar.inc
browser/base/content/browser-places.js
browser/components/nsBrowserGlue.js
browser/components/places/content/controller.js
browser/components/places/content/utils.js
toolkit/components/places/src/nsNavHistoryQuery.cpp
toolkit/components/places/tests/unit/test_399264_query_to_string.js
toolkit/components/places/tests/unit/test_399264_string_to_query.js
toolkit/components/places/tests/unit/test_placeURIs.js
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -395,17 +395,17 @@
 
   <menu id="bookmarksMenu" 
         label="&bookmarksMenu.label;" accesskey="&bookmarksMenu.accesskey;"
         ondragenter="PlacesMenuDNDController.onBookmarksMenuDragEnter(event);"
         ondragdrop="nsDragAndDrop.drop(event, BookmarksMenuDropHandler);"
         ondragover="nsDragAndDrop.dragOver(event, BookmarksMenuDropHandler);">
     <menupopup id="bookmarksMenuPopup"
                type="places"
-               place="place:folder=2&amp;expandQueries=1"
+               place="place:folder=BOOKMARKS_MENU&amp;expandQueries=1"
                context="placesContext"
                openInTabs="children"
                oncommand="BookmarksEventHandler.onCommand(event);"
                onclick="BookmarksEventHandler.onClick(event);"
                onpopupshowing="BookmarksEventHandler.onPopupShowing(event);">
       <menuitem label="&bookmarkThisPageCmd.label;" 
                 command="Browser:AddBookmarkAs" key="addBookmarkAsKb"/>
       <menuitem id="subscribeToPageMenuitem"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1017,33 +1017,32 @@ function placesMigrationTasks() {
         // Remove the old annotation.
         annosvc.removePageAnnotation(uri, oldPostDataAnno);
       } catch(ex) {}
     }
     gPrefService.setBoolPref("browser.places.migratePostDataAnnotations", false);
   }
 
   if (gPrefService.getBoolPref("browser.places.updateRecentTagsUri")) {
-    var bmsvc = PlacesUtils.bookmarks;
-    var tagsFolder = bmsvc.tagsFolder;
-    var oldUriSpec = "place:folder=" + tagsFolder + "&group=3&queryType=1"+
+    var oldUriSpec = "place:folder=TAGS&group=3&queryType=1" +
                      "&applyOptionsToContainers=1&sort=12&maxResults=10";
 
     var maxResults = 10;
     var newUriSpec = "place:type=" + 
                      Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
                      "&sort=" + 
                      Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_DESCENDING +
                      "&maxResults=" + maxResults;
                      
     var ios = Cc["@mozilla.org/network/io-service;1"].
               getService(Ci.nsIIOService);
 
     var oldUri = ios.newURI(oldUriSpec, null, null);
     var newUri = ios.newURI(newUriSpec, null, null);
 
+    let bmsvc = PlacesUtils.bookmarks;
     let bookmarks = bmsvc.getBookmarkIdsForURI( oldUri, {});
     for (let i = 0; i < bookmarks.length; i++) {
       bmsvc.changeBookmarkURI( bookmarks[i], newUri);
     }
     gPrefService.setBoolPref("browser.places.updateRecentTagsUri", false);
   }
 }
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -624,19 +624,16 @@ BrowserGlue.prototype = {
           this._placesBundle.GetStringFromName("smartBookmarksFolderTitle");
         var mostVisitedTitle =
           this._placesBundle.GetStringFromName("mostVisitedTitle");
         var recentlyBookmarkedTitle =
           this._placesBundle.GetStringFromName("recentlyBookmarkedTitle");
         var recentTagsTitle =
           this._placesBundle.GetStringFromName("recentTagsTitle");
 
-        var bookmarksMenuFolder = bmsvc.bookmarksMenuFolder;
-        var unfiledBookmarksFolder = bmsvc.unfiledBookmarksFolder;
-        var toolbarFolder = bmsvc.toolbarFolder;
         var defaultIndex = bmsvc.DEFAULT_INDEX;
 
         // index = 0, make it the first folder
         var placesFolder = bmsvc.createFolder(toolbarFolder, smartBookmarksFolderTitle,
                                               0);
 
         // XXX should this be a pref?  see bug #399268
         var maxResults = 10;
@@ -647,19 +644,19 @@ BrowserGlue.prototype = {
               "&sort=" +
               Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
               "&maxResults=" + maxResults),
               defaultIndex, mostVisitedTitle);
 
         // excludeQueries=1 so that user created "saved searches" 
         // and these queries (added automatically) are excluded
         var recentlyBookmarkedItem = bmsvc.insertBookmark(placesFolder,
-          this._uri("place:folder=" + bookmarksMenuFolder + 
-              "&folder=" + unfiledBookmarksFolder +
-              "&folder=" + toolbarFolder +
+          this._uri("place:folder=BOOKMARKS_MENU" + 
+              "&folder=UNFILED_BOOKMARKS" +
+              "&folder=TOOLBAR" +
               "&queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
               "&sort=" +
               Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
               "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
               "&maxResults=" + maxResults +
               "&excludeQueries=1"),
               defaultIndex, recentlyBookmarkedTitle);
 
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -34,17 +34,17 @@
  * 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 ***** */
 
 // XXXmano: we should move most/all of these constants to PlacesUtils
-const ORGANIZER_ROOT_BOOKMARKS = "place:folder=2&excludeItems=1&queryType=1";
+const ORGANIZER_ROOT_BOOKMARKS = "place:folder=BOOKMARKS_MENU&excludeItems=1&queryType=1";
 const ORGANIZER_SUBSCRIPTIONS_QUERY = "place:annotation=livemark%2FfeedURI";
 
 // No change to the view, preserve current selection
 const RELOAD_ACTION_NOTHING = 0;
 // Inserting items new to the view, select the inserted rows
 const RELOAD_ACTION_INSERT = 1;
 // Removing items from the view, select the first item after the last selected
 const RELOAD_ACTION_REMOVE = 2;
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -1137,46 +1137,47 @@ var PlacesUIUtils = {
         let itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, title);
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "History", 0, EXPIRE_NEVER);
         self.leftPaneQueries["History"] = itemId;
 
         // XXX: Downloads
 
         // Tags Query
+        uri = self._uri("place:folder=TAGS");
         uri = PlacesUtils._uri("place:folder=" + PlacesUtils.tagsFolderId);
         itemId = PlacesUtils.bookmarks.insertBookmark(leftPaneRoot, uri, -1, null);
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "Tags", 0, EXPIRE_NEVER);
         self.leftPaneQueries["Tags"] = itemId;
 
         // All Bookmarks Folder
         title = self.getString("OrganizerQueryAllBookmarks");
         itemId = PlacesUtils.bookmarks.createFolder(leftPaneRoot, title, -1);
         allBookmarksId = itemId;
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "AllBookmarks", 0, EXPIRE_NEVER);
         self.leftPaneQueries["AllBookmarks"] = itemId;
 
         // All Bookmarks->Bookmarks Toolbar Query
-        uri = PlacesUtils._uri("place:folder=" + PlacesUtils.toolbarFolderId);
+        uri = self._uri("place:folder=TOOLBAR");
         itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "BookmarksToolbar", 0, EXPIRE_NEVER);
         self.leftPaneQueries["BookmarksToolbar"] = itemId;
 
         // All Bookmarks->Bookmarks Menu Query
-        uri = PlacesUtils._uri("place:folder=" + PlacesUtils.bookmarksMenuFolderId);
+        uri = self._uri("place:folder=BOOKMARKS_MENU");
         itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "BookmarksMenu", 0, EXPIRE_NEVER);
         self.leftPaneQueries["BookmarksMenu"] = itemId;
 
         // All Bookmarks->Unfiled bookmarks
-        uri = PlacesUtils._uri("place:folder=" + PlacesUtils.unfiledBookmarksFolderId);
+        uri = self._uri("place:folder=UNFILED_BOOKMARKS");
         itemId = PlacesUtils.bookmarks.insertBookmark(allBookmarksId, uri, -1, null);
         PlacesUtils.annotations.setItemAnnotation(itemId, ORGANIZER_QUERY_ANNO,
                                                   "UnfiledBookmarks", 0,
                                                   EXPIRE_NEVER);
         self.leftPaneQueries["UnfiledBookmarks"] = itemId;
 
         // disallow manipulating this folder within the organizer UI
         PlacesUtils.bookmarks.setFolderReadonly(leftPaneRoot, true);
--- a/toolkit/components/places/src/nsNavHistoryQuery.cpp
+++ b/toolkit/components/places/src/nsNavHistoryQuery.cpp
@@ -16,16 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Google Inc.
  * Portions created by the Initial Developer are Copyright (C) 2005
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Brett Wilson <brettw@gmail.com> (original author)
+ *   Shawn Wilsher <me@shawnwilsher.com>
  *
  * 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
@@ -38,16 +39,17 @@
 
 /**
  * This file contains the definitions of nsNavHistoryQuery,
  * nsNavHistoryQueryOptions, and those functions in nsINavHistory that directly
  * support queries (specifically QueryStringToQueries and QueriesToQueryString).
  */
 
 #include "nsNavHistory.h"
+#include "nsNavBookmarks.h"
 #include "nsEscape.h"
 #include "nsCOMArray.h"
 #include "nsNetUtil.h"
 #include "nsTArray.h"
 #include "prprf.h"
 
 class QueryKeyValuePair
 {
@@ -189,16 +191,100 @@ inline void AppendInt32(nsACString& str,
 }
 inline void AppendInt64(nsACString& str, PRInt64 i)
 {
   nsCString tmp;
   tmp.AppendInt(i);
   str.Append(tmp);
 }
 
+namespace PlacesFolderConversion {
+  #define PLACES_ROOT_FOLDER "PLACES_ROOT"
+  #define BOOKMARKS_MENU_FOLDER "BOOKMARKS_MENU"
+  #define TAGS_FOLDER "TAGS"
+  #define UNFILED_BOOKMARKS_FOLDER "UNFILED_BOOKMARKS"
+  #define TOOLBAR_FOLDER "TOOLBAR"
+  
+  /**
+   * Converts a folder name to a folder id.
+   *
+   * @param aName
+   *        The name of the folder to convert to a folder id.
+   * @returns the folder id if aName is a recognizable name, -1 otherwise.
+   */
+  inline PRInt64 DecodeFolder(const nsCString &aName)
+  {
+    nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
+    NS_ENSURE_TRUE(bs, PR_FALSE);
+    PRInt64 folderID = -1;
+
+    if (aName.EqualsLiteral(PLACES_ROOT_FOLDER))
+      (void)bs->GetPlacesRoot(&folderID);
+    else if (aName.EqualsLiteral(BOOKMARKS_MENU_FOLDER))
+      (void)bs->GetBookmarksMenuFolder(&folderID);
+    else if (aName.EqualsLiteral(TAGS_FOLDER))
+      (void)bs->GetTagsFolder(&folderID);
+    else if (aName.EqualsLiteral(UNFILED_BOOKMARKS_FOLDER))
+      (void)bs->GetUnfiledBookmarksFolder(&folderID);
+    else if (aName.EqualsLiteral(TOOLBAR_FOLDER))
+      (void)bs->GetToolbarFolder(&folderID);
+
+    return folderID;
+  }
+
+  /**
+   * Converts a folder id to a named constant, or a string representation of the
+   * folder id if there is no named constant for the folder, and appends it to
+   * aQuery.
+   *
+   * @param aQuery
+   *        The string to append the folder string to.  This is generally a
+   *        query string, but could really be anything.
+   * @param aFolderID
+   *        The folder ID to convert to the proper named constant.
+   */
+  inline void AppendFolder(nsCString &aQuery, PRInt64 aFolderID)
+  {
+    nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
+    PRInt64 folderID;
+
+    (void)bs->GetPlacesRoot(&folderID);
+    if (aFolderID == folderID) {
+      aQuery.AppendLiteral(PLACES_ROOT_FOLDER);
+      return;
+    }
+
+    (void)bs->GetBookmarksMenuFolder(&folderID);
+    if (aFolderID == folderID) {
+      aQuery.AppendLiteral(BOOKMARKS_MENU_FOLDER);
+      return;
+    }
+
+    (void)bs->GetTagsFolder(&folderID);
+    if (aFolderID == folderID) {
+      aQuery.AppendLiteral(TAGS_FOLDER);
+      return;
+    }
+
+    (void)bs->GetUnfiledBookmarksFolder(&folderID);
+    if (aFolderID == folderID) {
+      aQuery.AppendLiteral(UNFILED_BOOKMARKS_FOLDER);
+      return;
+    }
+
+    (void)bs->GetToolbarFolder(&folderID);
+    if (aFolderID == folderID) {
+      aQuery.AppendLiteral(TOOLBAR_FOLDER);
+      return;
+    }
+
+    // It wasn't one of our named constants, so just convert it to a string 
+    aQuery.AppendInt(aFolderID);
+  }
+}
 
 // nsNavHistory::QueryStringToQueries
 //
 //    From C++ places code, you should use QueryStringToQueryArray, this is
 //    the harder-to-use XPCOM version.
 
 NS_IMETHODIMP
 nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
@@ -406,17 +492,17 @@ nsNavHistory::QueriesToQueryString(nsINa
 
     // folders
     PRInt64 *folders = nsnull;
     PRUint32 folderCount = 0;
     query->GetFolders(&folderCount, &folders);
     for (PRUint32 i = 0; i < folderCount; ++i) {
       AppendAmpersandIfNonempty(queryString);
       queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
-      AppendInt64(queryString, folders[i]);
+      PlacesFolderConversion::AppendFolder(queryString, folders[i]);
     }
     nsMemory::Free(folders);
   }
 
   // sorting
   if (options->SortingMode() != nsINavHistoryQueryOptions::SORT_BY_NONE) {
     AppendAmpersandIfNonempty(queryString);
     queryString += NS_LITERAL_CSTRING(QUERYKEY_SORT "=");
@@ -626,17 +712,21 @@ nsNavHistory::TokensToQueries(const nsTA
       NS_ENSURE_SUCCESS(rv, rv);
 
     // folders
     } else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDER)) {
       PRInt64 folder;
       if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) {
         NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
       } else {
-        NS_WARNING("folders value in query is invalid, ignoring");
+        folder = PlacesFolderConversion::DecodeFolder(kvp.value);
+        if (folder != -1)
+          NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
+        else
+          NS_WARNING("folders value in query is invalid, ignoring");
       }
 
     // uri
     } else if (kvp.key.EqualsLiteral(QUERYKEY_URI)) {
       nsCAutoString unescapedUri(kvp.value);
       NS_UnescapeURL(unescapedUri); // modifies input
       nsCOMPtr<nsIURI> uri;
       nsresult rv = NS_NewURI(getter_AddRefs(uri), unescapedUri);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_399264_query_to_string.js
@@ -0,0 +1,86 @@
+/* -*- 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 unit test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Shawn Wilsher <me@shawnwilsher.com> (Original Author)
+ *
+ * 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 ***** */
+
+/**
+ * Obtains the id of the folder obtained from the query.
+ *
+ * @param aFolderID
+ *        The id of the folder we want to generate a query for.
+ * @returns the string representation of the query for the given folder.
+ */
+function query_string(aFolderID)
+{
+  var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
+           getService(Ci.nsINavHistoryService);
+
+  var query = hs.getNewQuery();
+  query.setFolders([aFolderID], 1);
+  var options = hs.getNewQueryOptions();
+  return hs.queriesToQueryString([query], 1, options);
+}
+
+function run_test()
+{
+  var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
+           getService(Ci.nsINavHistoryService);
+  var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+           getService(Ci.nsINavBookmarksService);
+
+  const QUERIES = [
+      "folder=PLACES_ROOT"
+    , "folder=BOOKMARKS_MENU"
+    , "folder=TAGS"
+    , "folder=UNFILED_BOOKMARKS"
+    , "folder=TOOLBAR"
+  ];
+  const FOLDER_IDS = [
+      bs.placesRoot
+    , bs.bookmarksMenuFolder
+    , bs.tagsFolder
+    , bs.unfiledBookmarksFolder
+    , bs.toolbarFolder
+  ];
+
+
+  for (var i = 0; i < QUERIES.length; i++) {
+    var result = query_string(FOLDER_IDS[i]);
+    dump("Looking for '" + QUERIES[i] + "' in '" + result + "'\n");
+    do_check_neq(-1, result.indexOf(QUERIES[i]));
+  }
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_399264_string_to_query.js
@@ -0,0 +1,110 @@
+/* -*- 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 unit test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Shawn Wilsher <me@shawnwilsher.com> (Original Author)
+ *
+ * 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 ***** */
+
+/**
+ * Obtains the id of the folder obtained from the query.
+ *
+ * @param aQuery
+ *        The query to obtain the folder id from.
+ * @returns the folder id of the folder of the root node of the query.
+ */
+function folder_id(aQuery)
+{
+  var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
+           getService(Ci.nsINavHistoryService);
+
+  dump("Checking query '" + aQuery + "'\n");
+  var options = { };
+  var queries = { };
+  var size = { };
+  hs.queryStringToQueries(aQuery, queries, size, options);
+  var result = hs.executeQueries(queries.value, size.value, options.value);
+  var root = result.root;
+  root.containerOpen = true;
+  do_check_true(root.hasChildren);
+  var folderID = root.getChild(0).parent.itemId;
+  root.containerOpen = false;
+  return folderID;
+}
+
+function run_test()
+{
+  var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
+           getService(Ci.nsINavHistoryService);
+  var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+           getService(Ci.nsINavBookmarksService);
+
+  const QUERIES = [
+      "place:folder=PLACES_ROOT"
+    , "place:folder=BOOKMARKS_MENU"
+    , "place:folder=TAGS"
+    , "place:folder=UNFILED_BOOKMARKS"
+    , "place:folder=TOOLBAR"
+  ];
+  const FOLDER_IDS = [
+      bs.placesRoot
+    , bs.bookmarksMenuFolder
+    , bs.tagsFolder
+    , bs.unfiledBookmarksFolder
+    , bs.toolbarFolder
+  ];
+
+  // add something in the bookmarks menu folder so a query to it returns results
+  bs.insertBookmark(bs.bookmarksMenuFolder, uri("http://example.com/bmf/"),
+                    Ci.nsINavBookmarksService.DEFAULT_INDEX, "bmf");
+
+  // add something to the tags folder
+  var ts = Cc["@mozilla.org/browser/tagging-service;1"].
+           getService(Ci.nsITaggingService);
+  ts.tagURI(uri("http://www.example.com/"), ["tag"]);
+
+  // add something to the unfiled bookmarks folder
+  bs.insertBookmark(bs.unfiledBookmarksFolder, uri("http://example.com/ubf/"),
+                    Ci.nsINavBookmarksService.DEFAULT_INDEX, "ubf");
+
+  // add something to the toolbar folder
+  bs.insertBookmark(bs.toolbarFolder, uri("http://example.com/tf/"),
+                    Ci.nsINavBookmarksService.DEFAULT_INDEX, "tf");
+
+  for (var i = 0; i < QUERIES.length; i++) {
+    var result = folder_id(QUERIES[i]);
+    dump("expected " + FOLDER_IDS[i] + ", got " + result + "\n");
+    do_check_eq(FOLDER_IDS[i], result);
+  }
+}
--- a/toolkit/components/places/tests/unit/test_placeURIs.js
+++ b/toolkit/components/places/tests/unit/test_placeURIs.js
@@ -44,29 +44,31 @@ try {
   do_throw("Could not get history service\n");
 } 
 
 // main
 function run_test() {
   // XXX Full testing coverage for QueriesToQueryString and
   // QueryStringToQueries
 
+  var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+           getService(Ci.nsINavBookmarksService);
   const NHQO = Ci.nsINavHistoryQueryOptions;
   // Bug 376798
   var query = histsvc.getNewQuery();
-  query.setFolders([1],1);
+  query.setFolders([bs.placesRoot], 1);
   do_check_eq(histsvc.queriesToQueryString([query], 1, histsvc.getNewQueryOptions()),
-              "place:folder=1");
+              "place:folder=PLACES_ROOT");
 
   // Bug 378828
   var options = histsvc.getNewQueryOptions();
   options.sortingAnnotation = "test anno";
   options.sortingMode = NHQO.SORT_BY_ANNOTATION_DESCENDING;
   var placeURI =
-    "place:folder=1&sort=" + NHQO.SORT_BY_ANNOTATION_DESCENDING +
+    "place:folder=PLACES_ROOT&sort=" + NHQO.SORT_BY_ANNOTATION_DESCENDING +
     "&sortingAnnotation=test%20anno";
   do_check_eq(histsvc.queriesToQueryString([query], 1, options),
               placeURI);
   var options = {};
   histsvc.queryStringToQueries(placeURI, { }, {}, options);
   do_check_eq(options.value.sortingAnnotation, "test anno");
   do_check_eq(options.value.sortingMode, NHQO.SORT_BY_ANNOTATION_DESCENDING);
 }