Bug 1421664 - Part 1: Force any tag queries to have query result type bookmarks. r?mak draft
authorMilindL <i.milind.luthra@gmail.com>
Thu, 30 Nov 2017 17:45:24 +0530
changeset 705698 fbbf0bc4311601f0481e3a84a15c8634eada18e8
parent 685447 967c95cee709756596860ed2a3e6ac06ea3a053f
child 705699 5e2d70ae96aa632a06ac17e615db528b67ebddf7
push id91548
push userbmo:i.milind.luthra@gmail.com
push dateThu, 30 Nov 2017 14:18:29 +0000
reviewersmak
bugs1421664
milestone58.0a1
Bug 1421664 - Part 1: Force any tag queries to have query result type bookmarks. r?mak MozReview-Commit-ID: HV4p6Xz3mX2
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/tests/queries/test_tags.js
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -2148,16 +2148,24 @@ nsNavHistory::ConstructQueryString(
 
     nsAutoCString additionalQueryOptions;
 
     queryString.ReplaceSubstring("{QUERY_OPTIONS}",
                                   additionalQueryOptions.get());
     return NS_OK;
   }
 
+  // If even one of the queries is a tag query, the query type is bookmarks.
+  for (int32_t i = 0; i < aQueries.Count(); i++) {
+    if (!aQueries[i]->Tags().IsEmpty()) {
+      aOptions->SetQueryType(nsNavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS);
+      break;
+    }
+  }
+
   nsAutoCString conditions;
   for (int32_t i = 0; i < aQueries.Count(); i++) {
     nsCString queryClause;
     rv = QueryToSelectClause(aQueries[i], aOptions, i, &queryClause);
     NS_ENSURE_SUCCESS(rv, rv);
     if (! queryClause.IsEmpty()) {
       aParamsPresent = true;
       if (! conditions.IsEmpty()) // exists previous clause: multiple ones are ORed
--- a/toolkit/components/places/tests/queries/test_tags.js
+++ b/toolkit/components/places/tests/queries/test_tags.js
@@ -1,16 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
- * Tests bookmark and history queries with tags.  See bug 399799.
+ * Tests bookmark queries with tags.  See bug 399799.
  */
 
 "use strict";
 
 add_task(async function tags_getter_setter() {
   do_print("Tags getter/setter should work correctly");
   do_print("Without setting tags, tags getter should return empty array");
   var [query] = makeQuery();
@@ -138,166 +138,90 @@ add_task(async function() {
     "Abracadabra",
     "123",
     "Here's a pretty long tag name with some = signs and 1 2 3s and spaces oh jeez will it work I hope so!",
     "アスキーでございません",
     "あいうえお",
   ], true);
 });
 
-add_task(async function tag_to_uri() {
-  do_print("Querying history on tag associated with a URI should return " +
+add_task(async function tag_to_bookmark() {
+  do_print("Querying on tag associated with a URI should return " +
            "that URI");
-  await task_doWithVisit(["foo", "bar", "baz"], function(aURI) {
+  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
     var [query, opts] = makeQuery(["foo"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["bar"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["baz"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
   });
 });
 
-add_task(async function tags_to_uri() {
-  do_print("Querying history on many tags associated with a URI should " +
+add_task(async function tags_to_bookmark() {
+  do_print("Querying on many tags associated with a URI should " +
            "return that URI");
-  await task_doWithVisit(["foo", "bar", "baz"], function(aURI) {
+  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
     var [query, opts] = makeQuery(["foo", "bar"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["foo", "baz"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["bar", "baz"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["foo", "bar", "baz"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
   });
 });
 
 add_task(async function repeated_tag() {
-  do_print("Specifying the same tag multiple times in a history query " +
+  do_print("Specifying the same tag multiple times in a query " +
            "should not matter");
-  await task_doWithVisit(["foo", "bar", "baz"], function(aURI) {
+  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
     var [query, opts] = makeQuery(["foo", "foo"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
     [query, opts] = makeQuery(["foo", "foo", "foo", "bar", "bar", "baz"]);
     executeAndCheckQueryResults(query, opts, [aURI.spec]);
   });
 });
 
-add_task(async function many_tags_no_uri() {
-  do_print("Querying history on many tags associated with a URI and " +
+add_task(async function many_tags_no_bookmarks() {
+  do_print("Querying on many tags associated with a URI and " +
            "tags not associated with that URI should not return that URI");
-  await task_doWithVisit(["foo", "bar", "baz"], function(aURI) {
+  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
     var [query, opts] = makeQuery(["foo", "bogus"]);
     executeAndCheckQueryResults(query, opts, []);
     [query, opts] = makeQuery(["foo", "bar", "bogus"]);
     executeAndCheckQueryResults(query, opts, []);
     [query, opts] = makeQuery(["foo", "bar", "baz", "bogus"]);
     executeAndCheckQueryResults(query, opts, []);
   });
 });
 
 add_task(async function nonexistent_tags() {
-  do_print("Querying history on nonexistent tags should return no results");
-  await task_doWithVisit(["foo", "bar", "baz"], function(aURI) {
+  do_print("Querying on nonexistent tags should return no results");
+  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
     var [query, opts] = makeQuery(["bogus"]);
     executeAndCheckQueryResults(query, opts, []);
     [query, opts] = makeQuery(["bogus", "gnarly"]);
     executeAndCheckQueryResults(query, opts, []);
   });
 });
 
-add_task(async function tag_to_bookmark() {
-  do_print("Querying bookmarks on tag associated with a URI should " +
-           "return that URI");
-  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
-    var [query, opts] = makeQuery(["foo"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["bar"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["baz"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-  });
-});
-
-add_task(async function many_tags_to_bookmark() {
-  do_print("Querying bookmarks on many tags associated with a URI " +
-           "should return that URI");
-  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
-    var [query, opts] = makeQuery(["foo", "bar"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["foo", "baz"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["bar", "baz"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["foo", "bar", "baz"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-  });
-});
-
-add_task(async function repeated_tag_to_bookmarks() {
-  do_print("Specifying the same tag multiple times in a bookmark query " +
-           "should not matter");
-  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
-    var [query, opts] = makeQuery(["foo", "foo"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-    [query, opts] = makeQuery(["foo", "foo", "foo", "bar", "bar", "baz"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, [aURI.spec]);
-  });
-});
-
-add_task(async function many_tags_no_bookmark() {
-  do_print("Querying bookmarks on many tags associated with a URI and " +
-           "tags not associated with that URI should not return that URI");
-  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
-    var [query, opts] = makeQuery(["foo", "bogus"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, []);
-    [query, opts] = makeQuery(["foo", "bar", "bogus"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, []);
-    [query, opts] = makeQuery(["foo", "bar", "baz", "bogus"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, []);
-  });
-});
-
-add_task(async function nonexistent_tags_bookmark() {
-  do_print("Querying bookmarks on nonexistent tag should return no results");
-  await task_doWithBookmark(["foo", "bar", "baz"], function(aURI) {
-    var [query, opts] = makeQuery(["bogus"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, []);
-    [query, opts] = makeQuery(["bogus", "gnarly"]);
-    opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-    executeAndCheckQueryResults(query, opts, []);
-  });
-});
-
-add_task(async function tagsAreNot_history() {
-  do_print("Querying history using tagsAreNot should work correctly");
+add_task(async function tagsAreNot_bookmark() {
+  do_print("Querying using tagsAreNot should work correctly");
   var urisAndTags = {
     "http://example.com/1": ["foo", "bar"],
     "http://example.com/2": ["baz", "qux"],
     "http://example.com/3": null
   };
 
   do_print("Add visits and tag the URIs");
   for (let [pURI, tags] of Object.entries(urisAndTags)) {
     let nsiuri = uri(pURI);
-    await PlacesTestUtils.addVisits(nsiuri);
+    await addBookmark(nsiuri);
     if (tags)
       PlacesUtils.tagging.tagURI(nsiuri, tags);
   }
 
   do_print('  Querying for "foo" should match only /2 and /3');
   var [query, opts] = makeQuery(["foo"], true);
   queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
                   ["http://example.com/2", "http://example.com/3"]);
@@ -328,73 +252,16 @@ add_task(async function tagsAreNot_histo
   for (let [pURI, tags] of Object.entries(urisAndTags)) {
     let nsiuri = uri(pURI);
     if (tags)
       PlacesUtils.tagging.untagURI(nsiuri, tags);
   }
   await task_cleanDatabase();
 });
 
-add_task(async function tagsAreNot_bookmarks() {
-  do_print("Querying bookmarks using tagsAreNot should work correctly");
-  var urisAndTags = {
-    "http://example.com/1": ["foo", "bar"],
-    "http://example.com/2": ["baz", "qux"],
-    "http://example.com/3": null
-  };
-
-  do_print("Add bookmarks and tag the URIs");
-  for (let [pURI, tags] of Object.entries(urisAndTags)) {
-    let nsiuri = uri(pURI);
-    await addBookmark(nsiuri);
-    if (tags)
-      PlacesUtils.tagging.tagURI(nsiuri, tags);
-  }
-
-  do_print('  Querying for "foo" should match only /2 and /3');
-  var [query, opts] = makeQuery(["foo"], true);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-  queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
-                  ["http://example.com/2", "http://example.com/3"]);
-
-  do_print('  Querying for "foo" and "bar" should match only /2 and /3');
-  [query, opts] = makeQuery(["foo", "bar"], true);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-  queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
-                  ["http://example.com/2", "http://example.com/3"]);
-
-  do_print('  Querying for "foo" and "bogus" should match only /2 and /3');
-  [query, opts] = makeQuery(["foo", "bogus"], true);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-  queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
-                  ["http://example.com/2", "http://example.com/3"]);
-
-  do_print('  Querying for "foo" and "baz" should match only /3');
-  [query, opts] = makeQuery(["foo", "baz"], true);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-  queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
-                  ["http://example.com/3"]);
-
-  do_print('  Querying for "bogus" should match all');
-  [query, opts] = makeQuery(["bogus"], true);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
-  queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root,
-                  ["http://example.com/1",
-                   "http://example.com/2",
-                   "http://example.com/3"]);
-
-  // Clean up.
-  for (let [pURI, tags] of Object.entries(urisAndTags)) {
-    let nsiuri = uri(pURI);
-    if (tags)
-      PlacesUtils.tagging.untagURI(nsiuri, tags);
-  }
-  await task_cleanDatabase();
-});
-
 add_task(async function duplicate_tags() {
   do_print("Duplicate existing tags (i.e., multiple tag folders with " +
            "same name) should not throw off query results");
   var tagName = "foo";
 
   do_print("Add bookmark and tag it normally");
   await addBookmark(TEST_URI);
   PlacesUtils.tagging.tagURI(TEST_URI, [tagName]);
@@ -410,17 +277,16 @@ add_task(async function duplicate_tags()
   await PlacesUtils.bookmarks.insert({
     parentGuid: dupTag.guid,
     title: "title",
     url: TEST_URI
   });
 
   do_print("Querying for tag should match URI");
   var [query, opts] = makeQuery([tagName]);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
   queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root, [TEST_URI.spec]);
 
   PlacesUtils.tagging.untagURI(TEST_URI, [tagName]);
   await task_cleanDatabase();
 });
 
 add_task(async function folder_named_as_tag() {
   do_print("Regular folders with the same name as tag should not throw " +
@@ -435,17 +301,16 @@ add_task(async function folder_named_as_
   await PlacesUtils.bookmarks.insert({
     parentGuid: PlacesUtils.bookmarks.unfiledGuid,
     type: PlacesUtils.bookmarks.TYPE_FOLDER,
     title: tagName
   });
 
   do_print("Querying for tag should match URI");
   var [query, opts] = makeQuery([tagName]);
-  opts.queryType = opts.QUERY_TYPE_BOOKMARKS;
   queryResultsAre(PlacesUtils.history.executeQuery(query, opts).root, [TEST_URI.spec]);
 
   PlacesUtils.tagging.untagURI(TEST_URI, [tagName]);
   await task_cleanDatabase();
 });
 
 add_task(async function ORed_queries() {
   do_print("Multiple queries ORed together should work");
@@ -459,17 +324,17 @@ add_task(async function ORed_queries() {
   for (let i = 0; i < 11; i++) {
     urisAndTags["http://example.com/1"].push("/1 tag " + i);
     urisAndTags["http://example.com/2"].push("/2 tag " + i);
   }
 
   do_print("Add visits and tag the URIs");
   for (let [pURI, tags] of Object.entries(urisAndTags)) {
     let nsiuri = uri(pURI);
-    await PlacesTestUtils.addVisits(nsiuri);
+    await addBookmark(nsiuri);
     if (tags)
       PlacesUtils.tagging.tagURI(nsiuri, tags);
   }
 
   do_print("Query for /1 OR query for /2 should match both /1 and /2");
   var [query1, opts] = makeQuery(urisAndTags["http://example.com/1"]);
   var [query2] = makeQuery(urisAndTags["http://example.com/2"]);
   var root = PlacesUtils.history.executeQueries([query1, query2], 2, opts).root;
@@ -580,34 +445,16 @@ async function task_doWithBookmark(aTags
   await addBookmark(TEST_URI);
   PlacesUtils.tagging.tagURI(TEST_URI, aTags);
   await aCallback(TEST_URI);
   PlacesUtils.tagging.untagURI(TEST_URI, aTags);
   await task_cleanDatabase();
 }
 
 /**
- * Asynchronous task that executes a callback function in a "scoped" database
- * state.  A history visit is added and tagged before the callback is called,
- * and afterward the database is cleared.
- *
- * @param aTags
- *        A history visit will be added and tagged with this array of tags
- * @param aCallback
- *        A function that will be called after the visit has been tagged
- */
-async function task_doWithVisit(aTags, aCallback) {
-  await PlacesTestUtils.addVisits(TEST_URI);
-  PlacesUtils.tagging.tagURI(TEST_URI, aTags);
-  await aCallback(TEST_URI);
-  PlacesUtils.tagging.untagURI(TEST_URI, aTags);
-  await task_cleanDatabase();
-}
-
-/**
  * queriesToQueryString() encodes every character in the query URI that doesn't
  * match /[a-zA-Z]/.  There's no simple JavaScript function that does the same,
  * but encodeURIComponent() comes close, only missing some punctuation.  This
  * function takes care of all of that.
  *
  * @param  aTag
  *         A tag name to encode
  * @return A UTF-8 escaped string suitable for inclusion in a query URI