diff options
Diffstat (limited to 'toolkit/components/places/tests/favicons')
27 files changed, 1268 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/favicons/.eslintrc.js b/toolkit/components/places/tests/favicons/.eslintrc.js new file mode 100644 index 000000000..d35787cd2 --- /dev/null +++ b/toolkit/components/places/tests/favicons/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "../../../../../testing/xpcshell/xpcshell.eslintrc.js" + ] +}; diff --git a/toolkit/components/places/tests/favicons/expected-favicon-big32.jpg.png b/toolkit/components/places/tests/favicons/expected-favicon-big32.jpg.png Binary files differnew file mode 100644 index 000000000..723008771 --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-big32.jpg.png diff --git a/toolkit/components/places/tests/favicons/expected-favicon-big4.jpg.png b/toolkit/components/places/tests/favicons/expected-favicon-big4.jpg.png Binary files differnew file mode 100644 index 000000000..9932c18fb --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-big4.jpg.png diff --git a/toolkit/components/places/tests/favicons/expected-favicon-big48.ico.png b/toolkit/components/places/tests/favicons/expected-favicon-big48.ico.png Binary files differnew file mode 100644 index 000000000..9f16bef43 --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-big48.ico.png diff --git a/toolkit/components/places/tests/favicons/expected-favicon-big64.png.png b/toolkit/components/places/tests/favicons/expected-favicon-big64.png.png Binary files differnew file mode 100644 index 000000000..ed158d161 --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-big64.png.png diff --git a/toolkit/components/places/tests/favicons/expected-favicon-scale160x3.jpg.png b/toolkit/components/places/tests/favicons/expected-favicon-scale160x3.jpg.png Binary files differnew file mode 100644 index 000000000..585c9e897 --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-scale160x3.jpg.png diff --git a/toolkit/components/places/tests/favicons/expected-favicon-scale3x160.jpg.png b/toolkit/components/places/tests/favicons/expected-favicon-scale3x160.jpg.png Binary files differnew file mode 100644 index 000000000..e07dabc79 --- /dev/null +++ b/toolkit/components/places/tests/favicons/expected-favicon-scale3x160.jpg.png diff --git a/toolkit/components/places/tests/favicons/favicon-big16.ico b/toolkit/components/places/tests/favicons/favicon-big16.ico Binary files differnew file mode 100644 index 000000000..d44438903 --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-big16.ico diff --git a/toolkit/components/places/tests/favicons/favicon-big32.jpg b/toolkit/components/places/tests/favicons/favicon-big32.jpg Binary files differnew file mode 100644 index 000000000..b2131bf0c --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-big32.jpg diff --git a/toolkit/components/places/tests/favicons/favicon-big4.jpg b/toolkit/components/places/tests/favicons/favicon-big4.jpg Binary files differnew file mode 100644 index 000000000..b84fcd35a --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-big4.jpg diff --git a/toolkit/components/places/tests/favicons/favicon-big48.ico b/toolkit/components/places/tests/favicons/favicon-big48.ico Binary files differnew file mode 100644 index 000000000..f22522411 --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-big48.ico diff --git a/toolkit/components/places/tests/favicons/favicon-big64.png b/toolkit/components/places/tests/favicons/favicon-big64.png Binary files differnew file mode 100644 index 000000000..2756cf0cb --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-big64.png diff --git a/toolkit/components/places/tests/favicons/favicon-normal16.png b/toolkit/components/places/tests/favicons/favicon-normal16.png Binary files differnew file mode 100644 index 000000000..62b69a3d0 --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-normal16.png diff --git a/toolkit/components/places/tests/favicons/favicon-normal32.png b/toolkit/components/places/tests/favicons/favicon-normal32.png Binary files differnew file mode 100644 index 000000000..5535363c9 --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-normal32.png diff --git a/toolkit/components/places/tests/favicons/favicon-scale160x3.jpg b/toolkit/components/places/tests/favicons/favicon-scale160x3.jpg Binary files differnew file mode 100644 index 000000000..422ee7ea0 --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-scale160x3.jpg diff --git a/toolkit/components/places/tests/favicons/favicon-scale3x160.jpg b/toolkit/components/places/tests/favicons/favicon-scale3x160.jpg Binary files differnew file mode 100644 index 000000000..e8514966a --- /dev/null +++ b/toolkit/components/places/tests/favicons/favicon-scale3x160.jpg diff --git a/toolkit/components/places/tests/favicons/head_favicons.js b/toolkit/components/places/tests/favicons/head_favicons.js new file mode 100644 index 000000000..cc81791e8 --- /dev/null +++ b/toolkit/components/places/tests/favicons/head_favicons.js @@ -0,0 +1,105 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +var Ci = Components.interfaces; +var Cc = Components.classes; +var Cr = Components.results; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); + +// Import common head. +{ + let commonFile = do_get_file("../head_common.js", false); + let uri = Services.io.newFileURI(commonFile); + Services.scriptloader.loadSubScript(uri.spec, this); +} + +// Put any other stuff relative to this test folder below. + + +// This error icon must stay in sync with FAVICON_ERRORPAGE_URL in +// nsIFaviconService.idl, aboutCertError.xhtml and netError.xhtml. +const FAVICON_ERRORPAGE_URI = + NetUtil.newURI("chrome://global/skin/icons/warning-16.png"); + +/** + * Waits for the first OnPageChanged notification for ATTRIBUTE_FAVICON, and + * verifies that it matches the expected page URI and associated favicon URI. + * + * This function also double-checks the GUID parameter of the notification. + * + * @param aExpectedPageURI + * nsIURI object of the page whose favicon should change. + * @param aExpectedFaviconURI + * nsIURI object of the newly associated favicon. + * @param aCallback + * This function is called after the check finished. + */ +function waitForFaviconChanged(aExpectedPageURI, aExpectedFaviconURI, + aCallback) { + let historyObserver = { + __proto__: NavHistoryObserver.prototype, + onPageChanged: function WFFC_onPageChanged(aURI, aWhat, aValue, aGUID) { + if (aWhat != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) { + return; + } + PlacesUtils.history.removeObserver(this); + + do_check_true(aURI.equals(aExpectedPageURI)); + do_check_eq(aValue, aExpectedFaviconURI.spec); + do_check_guid_for_uri(aURI, aGUID); + aCallback(); + } + }; + PlacesUtils.history.addObserver(historyObserver, false); +} + +/** + * Checks that the favicon for the given page matches the provided data. + * + * @param aPageURI + * nsIURI object for the page to check. + * @param aExpectedMimeType + * Expected MIME type of the icon, for example "image/png". + * @param aExpectedData + * Expected icon data, expressed as an array of byte values. + * @param aCallback + * This function is called after the check finished. + */ +function checkFaviconDataForPage(aPageURI, aExpectedMimeType, aExpectedData, + aCallback) { + PlacesUtils.favicons.getFaviconDataForPage(aPageURI, + function (aURI, aDataLen, aData, aMimeType) { + do_check_eq(aExpectedMimeType, aMimeType); + do_check_true(compareArrays(aExpectedData, aData)); + do_check_guid_for_uri(aPageURI); + aCallback(); + }); +} + +/** + * Checks that the given page has no associated favicon. + * + * @param aPageURI + * nsIURI object for the page to check. + * @param aCallback + * This function is called after the check finished. + */ +function checkFaviconMissingForPage(aPageURI, aCallback) { + PlacesUtils.favicons.getFaviconURLForPage(aPageURI, + function (aURI, aDataLen, aData, aMimeType) { + do_check_true(aURI === null); + aCallback(); + }); +} + +function promiseFaviconMissingForPage(aPageURI) { + return new Promise(resolve => checkFaviconMissingForPage(aPageURI, resolve)); +} + +function promiseFaviconChanged(aExpectedPageURI, aExpectedFaviconURI) { + return new Promise(resolve => waitForFaviconChanged(aExpectedPageURI, aExpectedFaviconURI, resolve)); +} diff --git a/toolkit/components/places/tests/favicons/test_expireAllFavicons.js b/toolkit/components/places/tests/favicons/test_expireAllFavicons.js new file mode 100644 index 000000000..c5d8edfdd --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_expireAllFavicons.js @@ -0,0 +1,39 @@ +/** + * This file tests that favicons are correctly expired by expireAllFavicons. + */ + +"use strict"; + +const TEST_PAGE_URI = NetUtil.newURI("http://example.com/"); +const BOOKMARKED_PAGE_URI = NetUtil.newURI("http://example.com/bookmarked"); + +add_task(function* test_expireAllFavicons() { + // Add a visited page. + yield PlacesTestUtils.addVisits({ uri: TEST_PAGE_URI, transition: TRANSITION_TYPED }); + + // Set a favicon for our test page. + yield promiseSetIconForPage(TEST_PAGE_URI, SMALLPNG_DATA_URI); + + // Add a page with a bookmark. + yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: BOOKMARKED_PAGE_URI, + title: "Test bookmark" + }); + + // Set a favicon for our bookmark. + yield promiseSetIconForPage(BOOKMARKED_PAGE_URI, SMALLPNG_DATA_URI); + + // Start expiration only after data has been saved in the database. + let promise = promiseTopicObserved(PlacesUtils.TOPIC_FAVICONS_EXPIRED); + PlacesUtils.favicons.expireAllFavicons(); + yield promise; + + // Check that the favicons for the pages we added were removed. + yield promiseFaviconMissingForPage(TEST_PAGE_URI); + yield promiseFaviconMissingForPage(BOOKMARKED_PAGE_URI); +}); + +function run_test() { + run_next_test(); +} diff --git a/toolkit/components/places/tests/favicons/test_favicons_conversions.js b/toolkit/components/places/tests/favicons/test_favicons_conversions.js new file mode 100644 index 000000000..fa0d332ec --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_favicons_conversions.js @@ -0,0 +1,131 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * This file tests the image conversions done by the favicon service. + */ + +// Globals + +// The pixel values we get on Windows are sometimes +/- 1 value compared to +// other platforms, so we need to skip some image content tests. +var isWindows = ("@mozilla.org/windows-registry-key;1" in Cc); + +/** + * Checks the conversion of the given test image file. + * + * @param aFileName + * File that contains the favicon image, located in the test folder. + * @param aFileMimeType + * MIME type of the image contained in the file. + * @param aFileLength + * Expected length of the file. + * @param aExpectConversion + * If false, the icon should be stored as is. If true, the expected data + * is loaded from a file named "expected-" + aFileName + ".png". + * @param aVaryOnWindows + * Indicates that the content of the converted image can be different on + * Windows and should not be checked on that platform. + * @param aCallback + * This function is called after the check finished. + */ +function checkFaviconDataConversion(aFileName, aFileMimeType, aFileLength, + aExpectConversion, aVaryOnWindows, + aCallback) { + let pageURI = NetUtil.newURI("http://places.test/page/" + aFileName); + PlacesTestUtils.addVisits({ uri: pageURI, transition: TRANSITION_TYPED }).then( + function () { + let faviconURI = NetUtil.newURI("http://places.test/icon/" + aFileName); + let fileData = readFileOfLength(aFileName, aFileLength); + + PlacesUtils.favicons.replaceFaviconData(faviconURI, fileData, fileData.length, + aFileMimeType); + PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, faviconURI, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function CFDC_verify(aURI, aDataLen, aData, aMimeType) { + if (!aExpectConversion) { + do_check_true(compareArrays(aData, fileData)); + do_check_eq(aMimeType, aFileMimeType); + } else { + if (!aVaryOnWindows || !isWindows) { + let expectedFile = do_get_file("expected-" + aFileName + ".png"); + do_check_true(compareArrays(aData, readFileData(expectedFile))); + } + do_check_eq(aMimeType, "image/png"); + } + + aCallback(); + }, Services.scriptSecurityManager.getSystemPrincipal()); + }); +} + +// Tests + +function run_test() { + run_next_test(); +} + +add_test(function test_storing_a_normal_16x16_icon() { + // 16x16 png, 286 bytes. + // optimized: no + checkFaviconDataConversion("favicon-normal16.png", "image/png", 286, + false, false, run_next_test); +}); + +add_test(function test_storing_a_normal_32x32_icon() { + // 32x32 png, 344 bytes. + // optimized: no + checkFaviconDataConversion("favicon-normal32.png", "image/png", 344, + false, false, run_next_test); +}); + +add_test(function test_storing_a_big_16x16_icon() { + // in: 16x16 ico, 1406 bytes. + // optimized: no + checkFaviconDataConversion("favicon-big16.ico", "image/x-icon", 1406, + false, false, run_next_test); +}); + +add_test(function test_storing_an_oversize_4x4_icon() { + // in: 4x4 jpg, 4751 bytes. + // optimized: yes + checkFaviconDataConversion("favicon-big4.jpg", "image/jpeg", 4751, + true, false, run_next_test); +}); + +add_test(function test_storing_an_oversize_32x32_icon() { + // in: 32x32 jpg, 3494 bytes. + // optimized: yes + checkFaviconDataConversion("favicon-big32.jpg", "image/jpeg", 3494, + true, true, run_next_test); +}); + +add_test(function test_storing_an_oversize_48x48_icon() { + // in: 48x48 ico, 56646 bytes. + // (howstuffworks.com icon, contains 13 icons with sizes from 16x16 to + // 48x48 in varying depths) + // optimized: yes + checkFaviconDataConversion("favicon-big48.ico", "image/x-icon", 56646, + true, false, run_next_test); +}); + +add_test(function test_storing_an_oversize_64x64_icon() { + // in: 64x64 png, 10698 bytes. + // optimized: yes + checkFaviconDataConversion("favicon-big64.png", "image/png", 10698, + true, false, run_next_test); +}); + +add_test(function test_scaling_an_oversize_160x3_icon() { + // in: 160x3 jpg, 5095 bytes. + // optimized: yes + checkFaviconDataConversion("favicon-scale160x3.jpg", "image/jpeg", 5095, + true, false, run_next_test); +}); + +add_test(function test_scaling_an_oversize_3x160_icon() { + // in: 3x160 jpg, 5059 bytes. + // optimized: yes + checkFaviconDataConversion("favicon-scale3x160.jpg", "image/jpeg", 5059, + true, false, run_next_test); +}); diff --git a/toolkit/components/places/tests/favicons/test_getFaviconDataForPage.js b/toolkit/components/places/tests/favicons/test_getFaviconDataForPage.js new file mode 100644 index 000000000..73eea7436 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_getFaviconDataForPage.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * This file tests getFaviconDataForPage. + */ + +// Globals + +const FAVICON_URI = NetUtil.newURI(do_get_file("favicon-normal32.png")); +const FAVICON_DATA = readFileData(do_get_file("favicon-normal32.png")); +const FAVICON_MIMETYPE = "image/png"; + +// Tests + +function run_test() +{ + // Check that the favicon loaded correctly before starting the actual tests. + do_check_eq(FAVICON_DATA.length, 344); + run_next_test(); +} + +add_test(function test_normal() +{ + let pageURI = NetUtil.newURI("http://example.com/normal"); + + PlacesTestUtils.addVisits(pageURI).then(function () { + PlacesUtils.favicons.setAndFetchFaviconForPage( + pageURI, FAVICON_URI, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function () { + PlacesUtils.favicons.getFaviconDataForPage(pageURI, + function (aURI, aDataLen, aData, aMimeType) { + do_check_true(aURI.equals(FAVICON_URI)); + do_check_eq(FAVICON_DATA.length, aDataLen); + do_check_true(compareArrays(FAVICON_DATA, aData)); + do_check_eq(FAVICON_MIMETYPE, aMimeType); + run_next_test(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + }); +}); + +add_test(function test_missing() +{ + let pageURI = NetUtil.newURI("http://example.com/missing"); + + PlacesUtils.favicons.getFaviconDataForPage(pageURI, + function (aURI, aDataLen, aData, aMimeType) { + // Check also the expected data types. + do_check_true(aURI === null); + do_check_true(aDataLen === 0); + do_check_true(aData.length === 0); + do_check_true(aMimeType === ""); + run_next_test(); + }); +}); diff --git a/toolkit/components/places/tests/favicons/test_getFaviconURLForPage.js b/toolkit/components/places/tests/favicons/test_getFaviconURLForPage.js new file mode 100644 index 000000000..fb2e23ff9 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_getFaviconURLForPage.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * This file tests getFaviconURLForPage. + */ + +// Tests + +function run_test() +{ + run_next_test(); +} + +add_test(function test_normal() +{ + let pageURI = NetUtil.newURI("http://example.com/normal"); + + PlacesTestUtils.addVisits(pageURI).then(function () { + PlacesUtils.favicons.setAndFetchFaviconForPage( + pageURI, SMALLPNG_DATA_URI, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function () { + PlacesUtils.favicons.getFaviconURLForPage(pageURI, + function (aURI, aDataLen, aData, aMimeType) { + do_check_true(aURI.equals(SMALLPNG_DATA_URI)); + + // Check also the expected data types. + do_check_true(aDataLen === 0); + do_check_true(aData.length === 0); + do_check_true(aMimeType === ""); + run_next_test(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + }); +}); + +add_test(function test_missing() +{ + let pageURI = NetUtil.newURI("http://example.com/missing"); + + PlacesUtils.favicons.getFaviconURLForPage(pageURI, + function (aURI, aDataLen, aData, aMimeType) { + // Check also the expected data types. + do_check_true(aURI === null); + do_check_true(aDataLen === 0); + do_check_true(aData.length === 0); + do_check_true(aMimeType === ""); + run_next_test(); + }); +}); diff --git a/toolkit/components/places/tests/favicons/test_moz-anno_favicon_mime_type.js b/toolkit/components/places/tests/favicons/test_moz-anno_favicon_mime_type.js new file mode 100644 index 000000000..d055d8d61 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_moz-anno_favicon_mime_type.js @@ -0,0 +1,90 @@ +/* -*- 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/. */ + +/** + * This test ensures that the mime type is set for moz-anno channels of favicons + * properly. Added with work in bug 481227. + */ + +// Constants +Cu.import("resource://gre/modules/NetUtil.jsm"); + +const testFaviconData = "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%06%00%00%00%1F%F3%FFa%00%00%00%04gAMA%00%00%AF%C87%05%8A%E9%00%00%00%19tEXtSoftware%00Adobe%20ImageReadyq%C9e%3C%00%00%01%D6IDATx%DAb%FC%FF%FF%3F%03%25%00%20%80%98%909%EF%DF%BFg%EF%EC%EC%FC%AD%AC%AC%FC%DF%95%91%F1%BF%89%89%C9%7F%20%FF%D7%EA%D5%AB%B7%DF%BBwO%16%9B%01%00%01%C4%00r%01%08%9F9s%C6%CD%D8%D8%F8%BF%0B%03%C3%FF3%40%BC%0A%88%EF%02q%1A%10%BB%40%F1%AAU%ABv%C1%D4%C30%40%00%81%89%993g%3E%06%1A%F6%3F%14%AA%11D%97%03%F1%7Fc%08%0D%E2%2B))%FD%17%04%89%A1%19%00%10%40%0C%D00%F8%0F3%00%C8%F8%BF%1B%E4%0Ac%88a%E5%60%17%19%FF%0F%0D%0D%05%1B%02v%D9%DD%BB%0A0%03%00%02%08%AC%B9%A3%A3%E3%17%03%D4v%90%01%EF%18%106%C3%0Cz%07%C5%BB%A1%DE%82y%07%20%80%A0%A6%08B%FCn%0C1%60%26%D4%20d%C3VA%C3%06%26%BE%0A%EA-%80%00%82%B9%E0%F7L4%0D%EF%90%F8%C6%60%2F%0A%82%BD%01%13%07%0700%D0%01%02%88%11%E4%02P%B41%DC%BB%C7%D0%014%0D%E8l%06W%20%06%BA%88%A1%1C%1AS%15%40%7C%16%CA6.%2Fgx%BFg%0F%83%CB%D9%B3%0C%7B%80%7C%80%00%02%BB%00%E8%9F%ED%20%1B%3A%A0%A6%9F%81%DA%DC%01%C5%B0%80%ED%80%FA%BF%BC%BC%FC%3F%83%12%90%9D%96%F6%1F%20%80%18%DE%BD%7B%C7%0E%8E%05AD%20%FEGr%A6%A0%A0%E0%7F%25P%80%02%9D%0F%D28%13%18%23%C6%C0%B0%02E%3D%C8%F5%00%01%04%8F%05P%A8%BA%40my%87%E4%12c%A8%8D%20%8B%D0%D3%00%08%03%04%10%9C%01R%E4%82d%3B%C8%A0%99%C6%90%90%C6%A5%19%84%01%02%08%9E%17%80%C9x%F7%7B%A0%DBVC%F9%A0%C0%5C%7D%16%2C%CE%00%F4%C6O%5C%99%09%20%800L%04y%A5%03%1A%95%A0%80%05%05%14.%DBA%18%20%80%18)%CD%CE%00%01%06%00%0C'%94%C7%C0k%C9%2C%00%00%00%00IEND%AEB%60%82"; +const moz_anno_favicon_prefix = "moz-anno:favicon:"; + +// streamListener + +function streamListener(aExpectedContentType) +{ + this._expectedContentType = aExpectedContentType; +} +streamListener.prototype = +{ + onStartRequest: function(aRequest, aContext) + { + // We have other tests that make sure the data is what we expect. We just + // need to check the content type here. + let channel = aRequest.QueryInterface(Ci.nsIChannel); + dump("*** Checking " + channel.URI.spec + "\n"); + do_check_eq(channel.contentType, this._expectedContentType); + + // If we somehow throw before doing the above check, the test will pass, so + // we do this for extra sanity. + this._checked = true; + }, + onStopRequest: function() + { + do_check_true(this._checked); + do_test_finished(); + }, + onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) + { + aRequest.cancel(Cr.NS_ERROR_ABORT); + } +}; + +// Test Runner + +function run_test() +{ + let fs = Cc["@mozilla.org/browser/favicon-service;1"]. + getService(Ci.nsIFaviconService); + + // Test that the default icon has the content type of image/png. + let channel = NetUtil.newChannel({ + uri: fs.defaultFavicon, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON + }); + channel.asyncOpen2(new streamListener("image/png")); + do_test_pending(); + + // Test URI that we don't know anything about. Will end up being the default + // icon, so expect image/png. + channel = NetUtil.newChannel({ + uri: moz_anno_favicon_prefix + "http://mozilla.org", + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON + }); + channel.asyncOpen2(new streamListener("image/png")); + do_test_pending(); + + // Test that the content type of a favicon we add ends up being image/png. + let testURI = uri("http://mozilla.org/"); + // Add the data before opening + fs.replaceFaviconDataFromDataURL(testURI, testFaviconData, + (Date.now() + 60 * 60 * 24 * 1000) * 1000, + Services.scriptSecurityManager.getSystemPrincipal()); + + // Open the channel + channel = NetUtil.newChannel({ + uri: moz_anno_favicon_prefix + testURI.spec, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON + }); + channel.asyncOpen2(new streamListener("image/png")); + do_test_pending(); +} diff --git a/toolkit/components/places/tests/favicons/test_page-icon_protocol.js b/toolkit/components/places/tests/favicons/test_page-icon_protocol.js new file mode 100644 index 000000000..5533d5135 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_page-icon_protocol.js @@ -0,0 +1,66 @@ +const ICON_DATA = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg=="; +const TEST_URI = NetUtil.newURI("http://mozilla.org/"); +const ICON_URI = NetUtil.newURI("http://mozilla.org/favicon.ico"); + +function fetchIconForSpec(spec) { + return new Promise((resolve, reject) => { + NetUtil.asyncFetch({ + uri: NetUtil.newURI("page-icon:" + TEST_URI.spec), + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON + }, (input, status, request) => { + if (!Components.isSuccessCode(status)) { + reject(new Error("unable to load icon")); + return; + } + + try { + let data = NetUtil.readInputStreamToString(input, input.available()); + let contentType = request.QueryInterface(Ci.nsIChannel).contentType; + input.close(); + resolve({ data, contentType }); + } catch (ex) { + reject(ex); + } + }); + }); +} + +var gDefaultFavicon; +var gFavicon; + +add_task(function* setup() { + yield PlacesTestUtils.addVisits({ uri: TEST_URI }); + + PlacesUtils.favicons.replaceFaviconDataFromDataURL( + ICON_URI, ICON_DATA, (Date.now() + 8640000) * 1000, + Services.scriptSecurityManager.getSystemPrincipal()); + + yield new Promise(resolve => { + PlacesUtils.favicons.setAndFetchFaviconForPage( + TEST_URI, ICON_URI, false, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + resolve, Services.scriptSecurityManager.getSystemPrincipal()); + }); + + gDefaultFavicon = yield fetchIconForSpec(PlacesUtils.favicons.defaultFavicon); + gFavicon = yield fetchIconForSpec(ICON_DATA); +}); + +add_task(function* known_url() { + let {data, contentType} = yield fetchIconForSpec(TEST_URI.spec); + Assert.equal(contentType, gFavicon.contentType); + Assert.ok(data == gFavicon.data, "Got the favicon data"); +}); + +add_task(function* unknown_url() { + let {data, contentType} = yield fetchIconForSpec("http://www.moz.org/"); + Assert.equal(contentType, gDefaultFavicon.contentType); + Assert.ok(data == gDefaultFavicon.data, "Got the default favicon data"); +}); + +add_task(function* invalid_url() { + let {data, contentType} = yield fetchIconForSpec("test"); + Assert.equal(contentType, gDefaultFavicon.contentType); + Assert.ok(data == gDefaultFavicon.data, "Got the default favicon data"); +}); diff --git a/toolkit/components/places/tests/favicons/test_query_result_favicon_changed_on_child.js b/toolkit/components/places/tests/favicons/test_query_result_favicon_changed_on_child.js new file mode 100644 index 000000000..df61c22cd --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_query_result_favicon_changed_on_child.js @@ -0,0 +1,74 @@ +/** + * Test for bug 451499 <https://bugzilla.mozilla.org/show_bug.cgi?id=451499>: + * Wrong folder icon appears on smart bookmarks. + */ + +"use strict"; + +const PAGE_URI = NetUtil.newURI("http://example.com/test_query_result"); + +add_task(function* test_query_result_favicon_changed_on_child() { + // Bookmark our test page, so it will appear in the query resultset. + yield PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + title: "test_bookmark", + url: PAGE_URI + }); + + // Get the last 10 bookmarks added to the menu or the toolbar. + let query = PlacesUtils.history.getNewQuery(); + query.setFolders([PlacesUtils.bookmarksMenuFolderId, + PlacesUtils.toolbarFolderId], 2); + + let options = PlacesUtils.history.getNewQueryOptions(); + options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS; + options.maxResults = 10; + options.excludeQueries = 1; + options.sortingMode = options.SORT_BY_DATE_DESCENDING; + + let result = PlacesUtils.history.executeQuery(query, options); + let resultObserver = { + __proto__: NavHistoryResultObserver.prototype, + containerStateChanged(aContainerNode, aOldState, aNewState) { + if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) { + // We set a favicon on PAGE_URI while the container is open. The + // favicon for the page must have data associated with it in order for + // the icon changed notifications to be sent, so we use a valid image + // data URI. + PlacesUtils.favicons.setAndFetchFaviconForPage(PAGE_URI, + SMALLPNG_DATA_URI, + false, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + null, + Services.scriptSecurityManager.getSystemPrincipal()); + } + }, + nodeIconChanged(aNode) { + do_throw("The icon should be set only for the page," + + " not for the containing query."); + } + }; + result.addObserver(resultObserver, false); + + // Open the container and wait for containerStateChanged. We should start + // observing before setting |containerOpen| as that's caused by the + // setAndFetchFaviconForPage() call caused by the containerStateChanged + // observer above. + let promise = promiseFaviconChanged(PAGE_URI, SMALLPNG_DATA_URI); + result.root.containerOpen = true; + yield promise; + + // We must wait for the asynchronous database thread to finish the + // operation, and then for the main thread to process any pending + // notifications that came from the asynchronous thread, before we can be + // sure that nodeIconChanged was not invoked in the meantime. + yield PlacesTestUtils.promiseAsyncUpdates(); + result.removeObserver(resultObserver); + + // Free the resources immediately. + result.root.containerOpen = false; +}); + +function run_test() { + run_next_test(); +} diff --git a/toolkit/components/places/tests/favicons/test_replaceFaviconData.js b/toolkit/components/places/tests/favicons/test_replaceFaviconData.js new file mode 100644 index 000000000..ac53e70e9 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_replaceFaviconData.js @@ -0,0 +1,264 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Tests for mozIAsyncFavicons::replaceFaviconData() + */ + +var iconsvc = PlacesUtils.favicons; +var histsvc = PlacesUtils.history; +var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal(); + +var originalFavicon = { + file: do_get_file("favicon-normal16.png"), + uri: uri(do_get_file("favicon-normal16.png")), + data: readFileData(do_get_file("favicon-normal16.png")), + mimetype: "image/png" +}; + +var uniqueFaviconId = 0; +function createFavicon(fileName) { + let tempdir = Services.dirsvc.get("TmpD", Ci.nsILocalFile); + + // remove any existing file at the path we're about to copy to + let outfile = tempdir.clone(); + outfile.append(fileName); + try { outfile.remove(false); } catch (e) {} + + originalFavicon.file.copyToFollowingLinks(tempdir, fileName); + + let stream = Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream); + stream.init(outfile, 0x02 | 0x08 | 0x10, 0o600, 0); + + // append some data that sniffers/encoders will ignore that will distinguish + // the different favicons we'll create + uniqueFaviconId++; + let uniqueStr = "uid:" + uniqueFaviconId; + stream.write(uniqueStr, uniqueStr.length); + stream.close(); + + do_check_eq(outfile.leafName.substr(0, fileName.length), fileName); + + return { + file: outfile, + uri: uri(outfile), + data: readFileData(outfile), + mimetype: "image/png" + }; +} + +function checkCallbackSucceeded(callbackMimetype, callbackData, sourceMimetype, sourceData) { + do_check_eq(callbackMimetype, sourceMimetype); + do_check_true(compareArrays(callbackData, sourceData)); +} + +function run_test() { + // check that the favicon loaded correctly + do_check_eq(originalFavicon.data.length, 286); + run_next_test(); +} + +add_task(function* test_replaceFaviconData_validHistoryURI() { + do_print("test replaceFaviconData for valid history uri"); + + let pageURI = uri("http://test1.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let favicon = createFavicon("favicon1.png"); + + iconsvc.replaceFaviconData(favicon.uri, favicon.data, favicon.data.length, + favicon.mimetype); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage(pageURI, favicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconData_validHistoryURI_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, favicon.mimetype, favicon.data); + checkFaviconDataForPage( + pageURI, favicon.mimetype, favicon.data, + function test_replaceFaviconData_validHistoryURI_callback() { + favicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, systemPrincipal); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconData_overrideDefaultFavicon() { + do_print("test replaceFaviconData to override a later setAndFetchFaviconForPage"); + + let pageURI = uri("http://test2.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon2.png"); + let secondFavicon = createFavicon("favicon3.png"); + + iconsvc.replaceFaviconData( + firstFavicon.uri, secondFavicon.data, secondFavicon.data.length, + secondFavicon.mimetype); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconData_overrideDefaultFavicon_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconData_overrideDefaultFavicon_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, systemPrincipal); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconData_replaceExisting() { + do_print("test replaceFaviconData to override a previous setAndFetchFaviconForPage"); + + let pageURI = uri("http://test3.bar"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon4.png"); + let secondFavicon = createFavicon("favicon5.png"); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconData_replaceExisting_firstSet_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, firstFavicon.mimetype, firstFavicon.data); + checkFaviconDataForPage( + pageURI, firstFavicon.mimetype, firstFavicon.data, + function test_replaceFaviconData_overrideDefaultFavicon_firstCallback() { + iconsvc.replaceFaviconData( + firstFavicon.uri, secondFavicon.data, secondFavicon.data.length, + secondFavicon.mimetype); + PlacesTestUtils.promiseAsyncUpdates().then(() => { + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconData_overrideDefaultFavicon_secondCallback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }, systemPrincipal); + }); + }); + }, systemPrincipal); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconData_unrelatedReplace() { + do_print("test replaceFaviconData to not make unrelated changes"); + + let pageURI = uri("http://test4.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let favicon = createFavicon("favicon6.png"); + let unrelatedFavicon = createFavicon("favicon7.png"); + + iconsvc.replaceFaviconData( + unrelatedFavicon.uri, unrelatedFavicon.data, unrelatedFavicon.data.length, + unrelatedFavicon.mimetype); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, favicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconData_unrelatedReplace_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, favicon.mimetype, favicon.data); + checkFaviconDataForPage( + pageURI, favicon.mimetype, favicon.data, + function test_replaceFaviconData_unrelatedReplace_callback() { + favicon.file.remove(false); + unrelatedFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, systemPrincipal); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconData_badInputs() { + do_print("test replaceFaviconData to throw on bad inputs"); + + let favicon = createFavicon("favicon8.png"); + + let ex = null; + try { + iconsvc.replaceFaviconData( + favicon.uri, favicon.data, favicon.data.length, ""); + } catch (e) { + ex = e; + } finally { + do_check_true(!!ex); + } + + ex = null; + try { + iconsvc.replaceFaviconData( + null, favicon.data, favicon.data.length, favicon.mimeType); + } catch (e) { + ex = e; + } finally { + do_check_true(!!ex); + } + + ex = null; + try { + iconsvc.replaceFaviconData( + favicon.uri, null, 0, favicon.mimeType); + } catch (e) { + ex = e; + } finally { + do_check_true(!!ex); + } + + favicon.file.remove(false); + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconData_twiceReplace() { + do_print("test replaceFaviconData on multiple replacements"); + + let pageURI = uri("http://test5.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon9.png"); + let secondFavicon = createFavicon("favicon10.png"); + + iconsvc.replaceFaviconData( + firstFavicon.uri, firstFavicon.data, firstFavicon.data.length, + firstFavicon.mimetype); + iconsvc.replaceFaviconData( + firstFavicon.uri, secondFavicon.data, secondFavicon.data.length, + secondFavicon.mimetype); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconData_twiceReplace_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconData_twiceReplace_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }, systemPrincipal); + }, systemPrincipal); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); diff --git a/toolkit/components/places/tests/favicons/test_replaceFaviconDataFromDataURL.js b/toolkit/components/places/tests/favicons/test_replaceFaviconDataFromDataURL.js new file mode 100644 index 000000000..69a5ba852 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_replaceFaviconDataFromDataURL.js @@ -0,0 +1,352 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* + * Tests for mozIAsyncFavicons::replaceFaviconData() + */ + +var iconsvc = PlacesUtils.favicons; +var histsvc = PlacesUtils.history; + +var originalFavicon = { + file: do_get_file("favicon-normal16.png"), + uri: uri(do_get_file("favicon-normal16.png")), + data: readFileData(do_get_file("favicon-normal16.png")), + mimetype: "image/png" +}; + +var uniqueFaviconId = 0; +function createFavicon(fileName) { + let tempdir = Services.dirsvc.get("TmpD", Ci.nsILocalFile); + + // remove any existing file at the path we're about to copy to + let outfile = tempdir.clone(); + outfile.append(fileName); + try { outfile.remove(false); } catch (e) {} + + originalFavicon.file.copyToFollowingLinks(tempdir, fileName); + + let stream = Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream); + stream.init(outfile, 0x02 | 0x08 | 0x10, 0o600, 0); + + // append some data that sniffers/encoders will ignore that will distinguish + // the different favicons we'll create + uniqueFaviconId++; + let uniqueStr = "uid:" + uniqueFaviconId; + stream.write(uniqueStr, uniqueStr.length); + stream.close(); + + do_check_eq(outfile.leafName.substr(0, fileName.length), fileName); + + return { + file: outfile, + uri: uri(outfile), + data: readFileData(outfile), + mimetype: "image/png" + }; +} + +function createDataURLForFavicon(favicon) { + return "data:" + favicon.mimetype + ";base64," + toBase64(favicon.data); +} + +function checkCallbackSucceeded(callbackMimetype, callbackData, sourceMimetype, sourceData) { + do_check_eq(callbackMimetype, sourceMimetype); + do_check_true(compareArrays(callbackData, sourceData)); +} + +function run_test() { + // check that the favicon loaded correctly + do_check_eq(originalFavicon.data.length, 286); + run_next_test(); +} + +add_task(function* test_replaceFaviconDataFromDataURL_validHistoryURI() { + do_print("test replaceFaviconDataFromDataURL for valid history uri"); + + let pageURI = uri("http://test1.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let favicon = createFavicon("favicon1.png"); + iconsvc.replaceFaviconDataFromDataURL(favicon.uri, createDataURLForFavicon(favicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage(pageURI, favicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_validHistoryURI_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, favicon.mimetype, favicon.data); + checkFaviconDataForPage( + pageURI, favicon.mimetype, favicon.data, + function test_replaceFaviconDataFromDataURL_validHistoryURI_callback() { + favicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_overrideDefaultFavicon() { + do_print("test replaceFaviconDataFromDataURL to override a later setAndFetchFaviconForPage"); + + let pageURI = uri("http://test2.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon2.png"); + let secondFavicon = createFavicon("favicon3.png"); + + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(secondFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_overrideDefaultFavicon_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconDataFromDataURL_overrideDefaultFavicon_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_replaceExisting() { + do_print("test replaceFaviconDataFromDataURL to override a previous setAndFetchFaviconForPage"); + + let pageURI = uri("http://test3.bar"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon4.png"); + let secondFavicon = createFavicon("favicon5.png"); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_replaceExisting_firstSet_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, firstFavicon.mimetype, firstFavicon.data); + checkFaviconDataForPage( + pageURI, firstFavicon.mimetype, firstFavicon.data, + function test_replaceFaviconDataFromDataURL_replaceExisting_firstCallback() { + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(secondFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconDataFromDataURL_replaceExisting_secondCallback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_unrelatedReplace() { + do_print("test replaceFaviconDataFromDataURL to not make unrelated changes"); + + let pageURI = uri("http://test4.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let favicon = createFavicon("favicon6.png"); + let unrelatedFavicon = createFavicon("favicon7.png"); + + iconsvc.replaceFaviconDataFromDataURL(unrelatedFavicon.uri, createDataURLForFavicon(unrelatedFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, favicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_unrelatedReplace_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, favicon.mimetype, favicon.data); + checkFaviconDataForPage( + pageURI, favicon.mimetype, favicon.data, + function test_replaceFaviconDataFromDataURL_unrelatedReplace_callback() { + favicon.file.remove(false); + unrelatedFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_badInputs() { + do_print("test replaceFaviconDataFromDataURL to throw on bad inputs"); + + let favicon = createFavicon("favicon8.png"); + + let ex = null; + try { + iconsvc.replaceFaviconDataFromDataURL(favicon.uri, "", 0, + Services.scriptSecurityManager.getSystemPrincipal()); + } catch (e) { + ex = e; + } finally { + do_check_true(!!ex); + } + + ex = null; + try { + iconsvc.replaceFaviconDataFromDataURL(null, createDataURLForFavicon(favicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + } catch (e) { + ex = e; + } finally { + do_check_true(!!ex); + } + + favicon.file.remove(false); + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_twiceReplace() { + do_print("test replaceFaviconDataFromDataURL on multiple replacements"); + + let pageURI = uri("http://test5.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon9.png"); + let secondFavicon = createFavicon("favicon10.png"); + + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(firstFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(secondFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_twiceReplace_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconDataFromDataURL_twiceReplace_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_afterRegularAssign() { + do_print("test replaceFaviconDataFromDataURL after replaceFaviconData"); + + let pageURI = uri("http://test6.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon11.png"); + let secondFavicon = createFavicon("favicon12.png"); + + iconsvc.replaceFaviconData( + firstFavicon.uri, firstFavicon.data, firstFavicon.data.length, + firstFavicon.mimetype); + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(secondFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_afterRegularAssign_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconDataFromDataURL_afterRegularAssign_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +add_task(function* test_replaceFaviconDataFromDataURL_beforeRegularAssign() { + do_print("test replaceFaviconDataFromDataURL before replaceFaviconData"); + + let pageURI = uri("http://test7.bar/"); + yield PlacesTestUtils.addVisits(pageURI); + + let firstFavicon = createFavicon("favicon13.png"); + let secondFavicon = createFavicon("favicon14.png"); + + iconsvc.replaceFaviconDataFromDataURL(firstFavicon.uri, createDataURLForFavicon(firstFavicon), 0, + Services.scriptSecurityManager.getSystemPrincipal()); + iconsvc.replaceFaviconData( + firstFavicon.uri, secondFavicon.data, secondFavicon.data.length, + secondFavicon.mimetype); + + let deferSetAndFetchFavicon = Promise.defer(); + iconsvc.setAndFetchFaviconForPage( + pageURI, firstFavicon.uri, true, + PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, + function test_replaceFaviconDataFromDataURL_beforeRegularAssign_check(aURI, aDataLen, aData, aMimeType) { + checkCallbackSucceeded(aMimeType, aData, secondFavicon.mimetype, secondFavicon.data); + checkFaviconDataForPage( + pageURI, secondFavicon.mimetype, secondFavicon.data, + function test_replaceFaviconDataFromDataURL_beforeRegularAssign_callback() { + firstFavicon.file.remove(false); + secondFavicon.file.remove(false); + deferSetAndFetchFavicon.resolve(); + }); + }, Services.scriptSecurityManager.getSystemPrincipal()); + yield deferSetAndFetchFavicon.promise; + + yield PlacesTestUtils.clearHistory(); +}); + +/* toBase64 copied from image/test/unit/test_encoder_png.js */ + +/* Convert data (an array of integers) to a Base64 string. */ +const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + + '0123456789+/'; +const base64Pad = '='; +function toBase64(data) { + let result = ''; + let length = data.length; + let i; + // Convert every three bytes to 4 ascii characters. + for (i = 0; i < (length - 2); i += 3) { + result += toBase64Table[data[i] >> 2]; + result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; + result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)]; + result += toBase64Table[data[i+2] & 0x3f]; + } + + // Convert the remaining 1 or 2 bytes, pad out to 4 characters. + if (length%3) { + i = length - (length%3); + result += toBase64Table[data[i] >> 2]; + if ((length%3) == 2) { + result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; + result += toBase64Table[(data[i+1] & 0x0f) << 2]; + result += base64Pad; + } else { + result += toBase64Table[(data[i] & 0x03) << 4]; + result += base64Pad + base64Pad; + } + } + + return result; +} diff --git a/toolkit/components/places/tests/favicons/xpcshell.ini b/toolkit/components/places/tests/favicons/xpcshell.ini new file mode 100644 index 000000000..851f193c7 --- /dev/null +++ b/toolkit/components/places/tests/favicons/xpcshell.ini @@ -0,0 +1,32 @@ +[DEFAULT] +head = head_favicons.js +tail = +skip-if = toolkit == 'android' +support-files = + expected-favicon-big32.jpg.png + expected-favicon-big4.jpg.png + expected-favicon-big48.ico.png + expected-favicon-big64.png.png + expected-favicon-scale160x3.jpg.png + expected-favicon-scale3x160.jpg.png + favicon-big16.ico + favicon-big32.jpg + favicon-big4.jpg + favicon-big48.ico + favicon-big64.png + favicon-normal16.png + favicon-normal32.png + favicon-scale160x3.jpg + favicon-scale3x160.jpg + +[test_expireAllFavicons.js] +[test_favicons_conversions.js] +# Bug 676989: test fails consistently on Android +fail-if = os == "android" +[test_getFaviconDataForPage.js] +[test_getFaviconURLForPage.js] +[test_moz-anno_favicon_mime_type.js] +[test_page-icon_protocol.js] +[test_query_result_favicon_changed_on_child.js] +[test_replaceFaviconData.js] +[test_replaceFaviconDataFromDataURL.js] |