This repository has been archived by the owner on Feb 26, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 861955: getFavicon async method in io/data
- Loading branch information
Showing
4 changed files
with
234 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* 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/. */ | ||
|
||
"use strict"; | ||
|
||
module.metadata = { | ||
"stability": "experimental" | ||
}; | ||
|
||
const { Cc, Ci, Cr } = require("chrome"); | ||
const IOService = Cc["@mozilla.org/network/io-service;1"]. | ||
getService(Ci.nsIIOService); | ||
const { isValidURI } = require("../url"); | ||
|
||
function newURI (uri) { | ||
if (!isValidURI(uri)) | ||
throw new Error("malformed URI: " + uri); | ||
return IOService.newURI(uri, null, null); | ||
} | ||
exports.newURI = newURI; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* 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/. */ | ||
|
||
const { Cc, Ci, Cu } = require('chrome'); | ||
const { Loader } = require('sdk/test/loader'); | ||
const loader = Loader(module); | ||
const file = require('sdk/io/file'); | ||
const httpd = loader.require('sdk/test/httpd'); | ||
const { pathFor } = require('sdk/system'); | ||
const { startServerAsync } = httpd; | ||
const basePath = pathFor('ProfD'); | ||
const { atob } = Cu.import("resource://gre/modules/Services.jsm", {}); | ||
const historyService = Cc["@mozilla.org/browser/nav-history-service;1"] | ||
.getService(Ci.nsINavHistoryService); | ||
Cu.import('resource://gre/modules/XPCOMUtils.jsm'); | ||
const ObserverShimMethods = ['onBeginUpdateBatch', 'onEndUpdateBatch', | ||
'onVisit', 'onTitleChanged', 'onDeleteURI', 'onClearHistory', | ||
'onPageChanged', 'onDeleteVisits']; | ||
|
||
/* | ||
* Shims NavHistoryObserver | ||
*/ | ||
|
||
let noop = function () {} | ||
let NavHistoryObserver = function () {}; | ||
ObserverShimMethods.forEach(function (method) { | ||
NavHistoryObserver.prototype[method] = noop; | ||
}); | ||
NavHistoryObserver.prototype.QueryInterface = XPCOMUtils.generateQI([ | ||
Ci.nsINavHistoryObserver | ||
]); | ||
|
||
/* | ||
* Uses history observer to watch for an onPageChanged event, | ||
* which detects when a favicon is updated in the registry. | ||
*/ | ||
function onFaviconChange (uri, callback) { | ||
let observer = Object.create(NavHistoryObserver.prototype, { | ||
onPageChanged: { | ||
value: function onPageChanged(aURI, aWhat, aValue, aGUID) { | ||
if (aWhat !== Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) | ||
return; | ||
if (aURI.spec !== uri) | ||
return; | ||
historyService.removeObserver(this); | ||
callback(aValue); | ||
} | ||
} | ||
}); | ||
historyService.addObserver(observer, false); | ||
} | ||
exports.onFaviconChange = onFaviconChange; | ||
|
||
/* | ||
* Takes page content, a page path, and favicon binary data | ||
*/ | ||
function serve ({name, favicon, port, host}) { | ||
let faviconTag = '<link rel="icon" type="image/x-icon" href="/'+ name +'.ico"/>'; | ||
let content = '<html><head>' + faviconTag + '<title>'+name+'</title></head><body></body></html>'; | ||
let srv = startServerAsync(port, basePath); | ||
let pagePath = file.join(basePath, name + '.html'); | ||
let iconPath = file.join(basePath, name + '.ico'); | ||
let pageStream = file.open(pagePath, 'w'); | ||
let iconStream = file.open(iconPath, 'wb'); | ||
iconStream.write(favicon); | ||
iconStream.close(); | ||
pageStream.write(content); | ||
pageStream.close(); | ||
return srv; | ||
} | ||
exports.serve = serve; | ||
|
||
let binFavicon = exports.binFavicon = atob('AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAMDcwADwyqYABAQEAAgICAAMDAwAERERABYWFgAcHBwAIiIiACkpKQBVVVUATU1NAEJCQgA5OTkAgHz/AFBQ/wCTANYA/+zMAMbW7wDW5+cAkKmtAAAAMwAAAGYAAACZAAAAzAAAMwAAADMzAAAzZgAAM5kAADPMAAAz/wAAZgAAAGYzAABmZgAAZpkAAGbMAABm/wAAmQAAAJkzAACZZgAAmZkAAJnMAACZ/wAAzAAAAMwzAADMZgAAzJkAAMzMAADM/wAA/2YAAP+ZAAD/zAAzAAAAMwAzADMAZgAzAJkAMwDMADMA/wAzMwAAMzMzADMzZgAzM5kAMzPMADMz/wAzZgAAM2YzADNmZgAzZpkAM2bMADNm/wAzmQAAM5kzADOZZgAzmZkAM5nMADOZ/wAzzAAAM8wzADPMZgAzzJkAM8zMADPM/wAz/zMAM/9mADP/mQAz/8wAM///AGYAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYzAABmMzMAZjNmAGYzmQBmM8wAZjP/AGZmAABmZjMAZmZmAGZmmQBmZswAZpkAAGaZMwBmmWYAZpmZAGaZzABmmf8AZswAAGbMMwBmzJkAZszMAGbM/wBm/wAAZv8zAGb/mQBm/8wAzAD/AP8AzACZmQAAmTOZAJkAmQCZAMwAmQAAAJkzMwCZAGYAmTPMAJkA/wCZZgAAmWYzAJkzZgCZZpkAmWbMAJkz/wCZmTMAmZlmAJmZmQCZmcwAmZn/AJnMAACZzDMAZsxmAJnMmQCZzMwAmcz/AJn/AACZ/zMAmcxmAJn/mQCZ/8wAmf//AMwAAACZADMAzABmAMwAmQDMAMwAmTMAAMwzMwDMM2YAzDOZAMwzzADMM/8AzGYAAMxmMwCZZmYAzGaZAMxmzACZZv8AzJkAAMyZMwDMmWYAzJmZAMyZzADMmf8AzMwAAMzMMwDMzGYAzMyZAMzMzADMzP8AzP8AAMz/MwCZ/2YAzP+ZAMz/zADM//8AzAAzAP8AZgD/AJkAzDMAAP8zMwD/M2YA/zOZAP8zzAD/M/8A/2YAAP9mMwDMZmYA/2aZAP9mzADMZv8A/5kAAP+ZMwD/mWYA/5mZAP+ZzAD/mf8A/8wAAP/MMwD/zGYA/8yZAP/MzAD/zP8A//8zAMz/ZgD//5kA///MAGZm/wBm/2YAZv//AP9mZgD/Zv8A//9mACEApQBfX18Ad3d3AIaGhgCWlpYAy8vLALKysgDX19cA3d3dAOPj4wDq6uoA8fHxAPj4+ADw+/8ApKCgAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8ACgoKCgoKCgoKCgoKCgoKCgoKCgoHAQEMbQoKCgoKCgoAAAdDH/kgHRIAAAAAAAAAAADrHfn5ASQQAAAAAAAAAArsBx0B+fkgHesAAAAAAAD/Cgwf+fn5IA4dEus/IvcACgcMAfkg+QEB+SABHushbf8QHR/5HQH5+QEdHetEHx4K7B/5+QH5+fkdDBL5+SBE/wwdJfkf+fn5AR8g+fkfEArsCh/5+QEeJR/5+SAeBwAACgoe+SAlHwFAEhAfAAAAAPcKHh8eASYBHhAMAAAAAAAA9EMdIB8gHh0dBwAAAAAAAAAA7BAdQ+wHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AADwfwAAwH8AAMB/AAAAPwAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAgAcAAIAPAADADwAA8D8AAP//AAA'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* 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/. */ | ||
|
||
const { Cc, Ci, Cu } = require('chrome'); | ||
const { getFavicon, getFaviconURIForLocation } = require('sdk/io/data'); | ||
const tabs = require('sdk/tabs'); | ||
const open = tabs.open; | ||
const port = 8099; | ||
const host = 'http://localhost:' + port; | ||
const { onFaviconChange, serve, binFavicon } = require('./favicon-helpers'); | ||
const { once } = require('sdk/system/events'); | ||
const faviconService = Cc["@mozilla.org/browser/favicon-service;1"]. | ||
getService(Ci.nsIFaviconService); | ||
|
||
exports.testGetFaviconCallbackSuccess = function (assert, done) { | ||
let name = 'callbacksuccess' | ||
let srv = serve({name: name, favicon: binFavicon, port: port, host: host}); | ||
let url = host + '/' + name + '.html'; | ||
let favicon = host + '/' + name + '.ico'; | ||
let tab; | ||
|
||
onFaviconChange(url, function (faviconUrl) { | ||
getFavicon(url, function (url) { | ||
assert.equal(favicon, url, 'Callback returns correct favicon url'); | ||
complete(tab, srv, done); | ||
}); | ||
}); | ||
|
||
open({ | ||
url: url, | ||
onOpen: function (newTab) tab = newTab, | ||
inBackground: true | ||
}); | ||
}; | ||
|
||
exports.testGetFaviconCallbackFailure = function (assert, done) { | ||
let name = 'callbackfailure'; | ||
let srv = serve({name: name, favicon: binFavicon, port: port, host: host}); | ||
let url = host + '/' + name + '.html'; | ||
let tab; | ||
|
||
onFaviconChange(url, function (faviconUrl) { | ||
once('places-favicons-expired', function () { | ||
getFavicon(url, function (url) { | ||
assert.equal(url, null, 'Callback returns null'); | ||
complete(tab, srv, done); | ||
}); | ||
}); | ||
faviconService.expireAllFavicons(); | ||
}); | ||
|
||
open({ | ||
url: url, | ||
onOpen: function (newTab) tab = newTab, | ||
inBackground: true | ||
}); | ||
}; | ||
|
||
exports.testGetFaviconPromiseSuccess = function (assert, done) { | ||
let name = 'promisesuccess' | ||
let srv = serve({name: name, favicon: binFavicon, port: port, host: host}); | ||
let url = host + '/' + name + '.html'; | ||
let favicon = host + '/' + name + '.ico'; | ||
let tab; | ||
|
||
onFaviconChange(url, function (faviconUrl) { | ||
getFavicon(url).then(function (url) { | ||
assert.equal(url, favicon, 'Callback returns null'); | ||
}, function (err) { | ||
assert.fail('Reject should not be called'); | ||
}).then(complete.bind(null, tab, srv, done)); | ||
}); | ||
|
||
open({ | ||
url: url, | ||
onOpen: function (newTab) tab = newTab, | ||
inBackground: true | ||
}); | ||
}; | ||
|
||
exports.testGetFaviconPromiseFailure = function (assert, done) { | ||
let name = 'promisefailure' | ||
let srv = serve({name: name, favicon: binFavicon, port: port, host: host}); | ||
let url = host + '/' + name + '.html'; | ||
let tab; | ||
|
||
onFaviconChange(url, function (faviconUrl) { | ||
once('places-favicons-expired', function () { | ||
getFavicon(url).then(function (url) { | ||
assert.fail('success should not be called'); | ||
}, function (err) { | ||
assert.equal(err, null, 'should call reject'); | ||
}).then(complete.bind(null, tab, srv, done)); | ||
}); | ||
faviconService.expireAllFavicons(); | ||
}); | ||
|
||
open({ | ||
url: url, | ||
onOpen: function (newTab) tab = newTab, | ||
inBackground: true | ||
}); | ||
}; | ||
|
||
function complete(tab, srv, done) { | ||
tab.close(function () { | ||
srv.stop(done); | ||
}) | ||
} | ||
|
||
require("test").run(exports); |