michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: // See also browser/base/content/test/newtab/. michael@0: michael@0: const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; michael@0: Cu.import("resource://gre/modules/NewTabUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Promise.jsm"); michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(function multipleProviders() { michael@0: // Make each provider generate NewTabUtils.links.maxNumLinks links to check michael@0: // that no more than maxNumLinks are actually returned in the merged list. michael@0: let evenLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks, 2); michael@0: let evenProvider = new TestProvider(done => done(evenLinks)); michael@0: let oddLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks - 1, 2); michael@0: let oddProvider = new TestProvider(done => done(oddLinks)); michael@0: michael@0: NewTabUtils.initWithoutProviders(); michael@0: NewTabUtils.links.addProvider(evenProvider); michael@0: NewTabUtils.links.addProvider(oddProvider); michael@0: michael@0: // This is sync since the providers' getLinks are sync. michael@0: NewTabUtils.links.populateCache(function () {}, false); michael@0: michael@0: let links = NewTabUtils.links.getLinks(); michael@0: let expectedLinks = makeLinks(NewTabUtils.links.maxNumLinks, michael@0: 2 * NewTabUtils.links.maxNumLinks, michael@0: 1); michael@0: do_check_eq(links.length, NewTabUtils.links.maxNumLinks); michael@0: do_check_links(links, expectedLinks); michael@0: michael@0: NewTabUtils.links.removeProvider(evenProvider); michael@0: NewTabUtils.links.removeProvider(oddProvider); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function changeLinks() { michael@0: let expectedLinks = makeLinks(0, 20, 2); michael@0: let provider = new TestProvider(done => done(expectedLinks)); michael@0: michael@0: NewTabUtils.initWithoutProviders(); michael@0: NewTabUtils.links.addProvider(provider); michael@0: michael@0: // This is sync since the provider's getLinks is sync. michael@0: NewTabUtils.links.populateCache(function () {}, false); michael@0: michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: // Notify of a new link. michael@0: let newLink = makeLink(19); michael@0: expectedLinks.splice(1, 0, newLink); michael@0: provider.notifyLinkChanged(newLink); michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: // Notify of a link that's changed sort criteria. michael@0: newLink.frecency = 17; michael@0: expectedLinks.splice(1, 1); michael@0: expectedLinks.splice(2, 0, newLink); michael@0: provider.notifyLinkChanged({ michael@0: url: newLink.url, michael@0: frecency: 17, michael@0: }); michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: // Notify of a link that's changed title. michael@0: newLink.title = "My frecency is now 17"; michael@0: provider.notifyLinkChanged({ michael@0: url: newLink.url, michael@0: title: newLink.title, michael@0: }); michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: // Notify of a new link again, but this time make it overflow maxNumLinks. michael@0: provider.maxNumLinks = expectedLinks.length; michael@0: newLink = makeLink(21); michael@0: expectedLinks.unshift(newLink); michael@0: expectedLinks.pop(); michael@0: do_check_eq(expectedLinks.length, provider.maxNumLinks); // Sanity check. michael@0: provider.notifyLinkChanged(newLink); michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: // Notify of many links changed. michael@0: expectedLinks = makeLinks(0, 3, 1); michael@0: provider.notifyManyLinksChanged(); michael@0: // NewTabUtils.links will now repopulate its cache, which is sync since michael@0: // the provider's getLinks is sync. michael@0: do_check_links(NewTabUtils.links.getLinks(), expectedLinks); michael@0: michael@0: NewTabUtils.links.removeProvider(provider); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_task(function oneProviderAlreadyCached() { michael@0: let links1 = makeLinks(0, 10, 1); michael@0: let provider1 = new TestProvider(done => done(links1)); michael@0: michael@0: NewTabUtils.initWithoutProviders(); michael@0: NewTabUtils.links.addProvider(provider1); michael@0: michael@0: // This is sync since the provider's getLinks is sync. michael@0: NewTabUtils.links.populateCache(function () {}, false); michael@0: do_check_links(NewTabUtils.links.getLinks(), links1); michael@0: michael@0: let links2 = makeLinks(10, 20, 1); michael@0: let provider2 = new TestProvider(done => done(links2)); michael@0: NewTabUtils.links.addProvider(provider2); michael@0: michael@0: NewTabUtils.links.populateCache(function () {}, false); michael@0: do_check_links(NewTabUtils.links.getLinks(), links2.concat(links1)); michael@0: michael@0: NewTabUtils.links.removeProvider(provider1); michael@0: NewTabUtils.links.removeProvider(provider2); michael@0: }); michael@0: michael@0: add_task(function newLowRankedLink() { michael@0: // Init a provider with 10 links and make its maximum number also 10. michael@0: let links = makeLinks(0, 10, 1); michael@0: let provider = new TestProvider(done => done(links)); michael@0: provider.maxNumLinks = links.length; michael@0: michael@0: NewTabUtils.initWithoutProviders(); michael@0: NewTabUtils.links.addProvider(provider); michael@0: michael@0: // This is sync since the provider's getLinks is sync. michael@0: NewTabUtils.links.populateCache(function () {}, false); michael@0: do_check_links(NewTabUtils.links.getLinks(), links); michael@0: michael@0: // Notify of a new link that's low-ranked enough not to make the list. michael@0: let newLink = makeLink(0); michael@0: provider.notifyLinkChanged(newLink); michael@0: do_check_links(NewTabUtils.links.getLinks(), links); michael@0: michael@0: // Notify about the new link's title change. michael@0: provider.notifyLinkChanged({ michael@0: url: newLink.url, michael@0: title: "a new title", michael@0: }); michael@0: do_check_links(NewTabUtils.links.getLinks(), links); michael@0: michael@0: NewTabUtils.links.removeProvider(provider); michael@0: }); michael@0: michael@0: function TestProvider(getLinksFn) { michael@0: this.getLinks = getLinksFn; michael@0: this._observers = new Set(); michael@0: } michael@0: michael@0: TestProvider.prototype = { michael@0: addObserver: function (observer) { michael@0: this._observers.add(observer); michael@0: }, michael@0: notifyLinkChanged: function (link) { michael@0: this._notifyObservers("onLinkChanged", link); michael@0: }, michael@0: notifyManyLinksChanged: function () { michael@0: this._notifyObservers("onManyLinksChanged"); michael@0: }, michael@0: _notifyObservers: function (observerMethodName, arg) { michael@0: for (let obs of this._observers) { michael@0: if (obs[observerMethodName]) michael@0: obs[observerMethodName](this, arg); michael@0: } michael@0: }, michael@0: }; michael@0: michael@0: function do_check_links(actualLinks, expectedLinks) { michael@0: do_check_true(Array.isArray(actualLinks)); michael@0: do_check_eq(actualLinks.length, expectedLinks.length); michael@0: for (let i = 0; i < expectedLinks.length; i++) { michael@0: let expected = expectedLinks[i]; michael@0: let actual = actualLinks[i]; michael@0: do_check_eq(actual.url, expected.url); michael@0: do_check_eq(actual.title, expected.title); michael@0: do_check_eq(actual.frecency, expected.frecency); michael@0: do_check_eq(actual.lastVisitDate, expected.lastVisitDate); michael@0: } michael@0: } michael@0: michael@0: function makeLinks(frecRangeStart, frecRangeEnd, step) { michael@0: let links = []; michael@0: // Remember, links are ordered by frecency descending. michael@0: for (let i = frecRangeEnd; i > frecRangeStart; i -= step) { michael@0: links.push(makeLink(i)); michael@0: } michael@0: return links; michael@0: } michael@0: michael@0: function makeLink(frecency) { michael@0: return { michael@0: url: "http://example.com/" + frecency, michael@0: title: "My frecency is " + frecency, michael@0: frecency: frecency, michael@0: lastVisitDate: 0, michael@0: }; michael@0: }