Bug 1281421 - add new test to cover the new FinderIterator module code. r=jaws
authorMike de Boer <mdeboer@mozilla.com>
Thu, 28 Jul 2016 12:34:17 +0200
changeset 346915 f962e7e8fb1099c29e3ff816ff0eb0a2c8fff5df
parent 346914 276b214dde0de481b91b93e1d2a5654661b0cb44
child 346916 705ce7870772b7d68b771edc924111cff49e3a60
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1281421
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1281421 - add new test to cover the new FinderIterator module code. r=jaws MozReview-Commit-ID: HZHdjyqFiYq
toolkit/modules/FinderIterator.jsm
toolkit/modules/tests/xpcshell/test_FinderIterator.js
toolkit/modules/tests/xpcshell/xpcshell.ini
--- a/toolkit/modules/FinderIterator.jsm
+++ b/toolkit/modules/FinderIterator.jsm
@@ -21,16 +21,19 @@ this.FinderIterator = {
   _listeners: new Map(),
   _catchingUp: new Set(),
   _previousParams: null,
   _previousRanges: [],
   _spawnId: 0,
   ranges: [],
   running: false,
 
+  // Expose `kIterationSizeMax` to the outside world for unit tests to use.
+  get kIterationSizeMax() kIterationSizeMax,
+
   /**
    * Start iterating the active Finder docShell, using the options below. When
    * it already started at the request of another consumer, we first yield the
    * results we already collected before continuing onward to yield fresh results.
    * We make sure to pause every `kIterationSizeMax` iterations to make sure we
    * don't block the host process too long. In the case of a break like this, we
    * yield `undefined`, instead of a range.
    * Upon re-entrance after a break, we check if `stop()` was called during the
new file mode 100644
--- /dev/null
+++ b/toolkit/modules/tests/xpcshell/test_FinderIterator.js
@@ -0,0 +1,184 @@
+const { interfaces: Ci, classes: Cc, utils: Cu } = Components;
+const { FinderIterator } = Cu.import("resource://gre/modules/FinderIterator.jsm", {});
+Cu.import("resource://gre/modules/Promise.jsm");
+
+var gFindResults = [];
+// Stub the method that instantiates nsIFind and does all the interaction with
+// the docShell to be searched through.
+FinderIterator._iterateDocument = function* (word, window, finder) {
+  for (let range of gFindResults)
+    yield range;
+};
+
+FinderIterator._rangeStartsInLink = fakeRange => fakeRange.startsInLink;
+
+function FakeRange(textContent, startsInLink = false) {
+  this.startContainer = {};
+  this.startsInLink = startsInLink;
+  this.toString = () => textContent;
+}
+
+var gMockWindow = {
+  setTimeout(cb, delay) {
+    Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
+      .initWithCallback(cb, delay, Ci.nsITimer.TYPE_ONE_SHOT);
+  }
+};
+
+var gMockFinder = {
+  _getWindow() { return gMockWindow; }
+};
+
+function prepareIterator(findText, rangeCount) {
+  gFindResults = [];
+  for (let i = rangeCount; --i >= 0;)
+    gFindResults.push(new FakeRange(findText));
+}
+
+add_task(function* test_start() {
+  let findText = "test";
+  let rangeCount = 300;
+  prepareIterator(findText, rangeCount);
+
+  let count = 0;
+  yield FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => {
+      ++count;
+      Assert.equal(range.toString(), findText, "Text content should match");
+    },
+    word: findText
+  });
+
+  Assert.equal(rangeCount, count, "Amount of ranges yielded should match!");
+  Assert.ok(!FinderIterator.running, "Running state should match");
+  Assert.equal(FinderIterator._previousRanges.length, rangeCount, "Ranges cache should match");
+});
+
+add_task(function* test_valid_arguments() {
+  let findText = "foo";
+  let rangeCount = 20;
+  prepareIterator(findText, rangeCount);
+
+  let count = 0;
+
+  yield FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count,
+    word: findText
+  });
+
+  let params = FinderIterator._previousParams;
+  Assert.ok(!params.linksOnly, "Default for linksOnly is false");
+  Assert.ok(!params.useCache, "Default for useCache is false");
+  Assert.equal(params.word, findText, "Words should match");
+
+  count = 0;
+  Assert.throws(() => FinderIterator.start({
+    onRange: range => ++count,
+    word: findText
+  }), /Missing required option 'finder'/, "Should throw when missing an argument");
+  FinderIterator.reset();
+
+  Assert.throws(() => FinderIterator.start({
+    finder: gMockFinder,
+    word: findText
+  }), /Missing valid, required option 'onRange'/, "Should throw when missing an argument");
+  FinderIterator.reset();
+
+  Assert.throws(() => FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count
+  }), /Missing required option 'word'/, "Should throw when missing an argument");
+  FinderIterator.reset();
+
+  Assert.equal(count, 0, "No ranges should've been counted");
+});
+
+add_task(function* test_stop() {
+  let findText = "bar";
+  let rangeCount = 120;
+  prepareIterator(findText, rangeCount);
+
+  let count = 0;
+  let whenDone = FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count,
+    word: findText
+  });
+
+  FinderIterator.stop();
+
+  yield whenDone;
+
+  Assert.equal(count, 100, "Number of ranges should match `kIterationSizeMax`");
+});
+
+add_task(function* test_reset() {
+  let findText = "tik";
+  let rangeCount = 142;
+  prepareIterator(findText, rangeCount);
+
+  let count = 0;
+  let whenDone = FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count,
+    word: findText
+  });
+
+  Assert.ok(FinderIterator.running, "Yup, running we are");
+  Assert.equal(count, 100, "Number of ranges should match `kIterationSizeMax`");
+  Assert.equal(FinderIterator.ranges.length, 100,
+    "Number of ranges should match `kIterationSizeMax`");
+
+  FinderIterator.reset();
+
+  Assert.ok(!FinderIterator.running, "Nope, running we are not");
+  Assert.equal(FinderIterator.ranges.length, 0, "No ranges after reset");
+  Assert.equal(FinderIterator._previousRanges.length, 0, "No ranges after reset");
+
+  yield whenDone;
+
+  Assert.equal(count, 100, "Number of ranges should match `kIterationSizeMax`");
+});
+
+add_task(function* test_parallel_starts() {
+  let findText = "tak";
+  let rangeCount = 2143;
+  prepareIterator(findText, rangeCount);
+
+  // Start off the iterator.
+  let count = 0;
+  let whenDone = FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count,
+    word: findText
+  });
+
+  // Start again after a few milliseconds.
+  yield new Promise(resolve => gMockWindow.setTimeout(resolve, 2));
+  Assert.ok(FinderIterator.running, "We ought to be running here");
+
+  let count2 = 0;
+  let whenDone2 = FinderIterator.start({
+    finder: gMockFinder,
+    onRange: range => ++count2,
+    word: findText
+  });
+
+  // Let the iterator run for a little while longer before we assert the world.
+  yield new Promise(resolve => gMockWindow.setTimeout(resolve, 10));
+  FinderIterator.stop();
+
+  Assert.ok(!FinderIterator.running, "Stop means stop");
+
+  yield whenDone;
+  yield whenDone2;
+
+  Assert.greater(count, FinderIterator.kIterationSizeMax, "At least one range should've been found");
+  Assert.less(count, rangeCount, "Not all ranges should've been found");
+  Assert.greater(count2, FinderIterator.kIterationSizeMax, "At least one range should've been found");
+  Assert.less(count2, rangeCount, "Not all ranges should've been found");
+
+  Assert.less(count2, count, "The second start was later, so should have fewer results");
+});
--- a/toolkit/modules/tests/xpcshell/xpcshell.ini
+++ b/toolkit/modules/tests/xpcshell/xpcshell.ini
@@ -14,16 +14,17 @@ skip-if = toolkit == 'android'
 [test_CanonicalJSON.js]
 [test_client_id.js]
 skip-if = toolkit == 'android'
 [test_Color.js]
 [test_DeferredTask.js]
 skip-if = toolkit == 'android'
 [test_FileUtils.js]
 skip-if = toolkit == 'android'
+[test_FinderIterator.js]
 [test_GMPInstallManager.js]
 skip-if = toolkit == 'android'
 [test_Http.js]
 skip-if = toolkit == 'android'
 [test_Integration.js]
 [test_jsesc.js]
 skip-if = toolkit == 'android'
 [test_Log.js]