This commit is contained in:
Ryan VanderMeulen 2015-12-05 15:09:41 -05:00
Родитель 4dd525a926 eed11fe644
Коммит 289a16635a
169 изменённых файлов: 2921 добавлений и 1700 удалений

Просмотреть файл

@ -42,31 +42,7 @@ rdf/**
security/**
services/**
startupcache/**
storage/**
testing/**
toolkit/components/**
toolkit/content/**
toolkit/crashreporter/**
toolkit/forgetaboutsite/**
toolkit/identity/**
toolkit/library/**
toolkit/locales/**
toolkit/modules/**
# This file contains preprocessor statements.
toolkit/mozapps/extensions/internal/AddonConstants.jsm
toolkit/mozapps/downloads/**
toolkit/mozapps/handling/**
toolkit/mozapps/installer/**
toolkit/mozapps/preferences/**
toolkit/mozapps/update/**
toolkit/obsolete/**
toolkit/pluginproblem/**
toolkit/profile/**
toolkit/system/**
toolkit/themes/**
toolkit/toolkit.mozbuild/**
toolkit/webapps/**
toolkit/xre/**
tools/**
uriloader/**
view/**
@ -196,3 +172,34 @@ mobile/android/components/Snippets.js
# Bug 1178739: Ignore this file as a quick fix for "Illegal yield expression"
mobile/android/modules/HomeProvider.jsm
# toolkit/ exclusions
# Not part of the default build
toolkit/components/help/**
# Intentionally invalid JS
toolkit/components/workerloader/tests/moduleF-syntax-error.js
# Tests old non-star function generators
toolkit/modules/tests/xpcshell/test_task.js
# Not yet updated
toolkit/components/osfile/**
toolkit/components/passwordmgr/**
toolkit/components/places/**
toolkit/mozapps/extensions/**
# Uses preprocessing
toolkit/content/contentAreaUtils.js
toolkit/components/jsdownloads/src/DownloadIntegration.jsm
toolkit/components/search/nsSearchService.js
toolkit/components/url-classifier/**
toolkit/components/urlformatter/nsURLFormatter.js
toolkit/identity/FirefoxAccounts.jsm
toolkit/modules/AppConstants.jsm
toolkit/modules/SessionRecorder.jsm
toolkit/mozapps/downloads/nsHelperAppDlg.js
toolkit/mozapps/extensions/internal/AddonConstants.jsm
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
toolkit/webapps/**

Просмотреть файл

@ -285,7 +285,6 @@
// almost certainly useless.
document.getElementById("errorTryAgain").style.display = "none";
document.getElementById("errorPageContainer").setAttribute("class", "certerror");
addDomainErrorLink();
}
else {
// Remove the override block for non-certificate errors. CSS-hiding
@ -293,6 +292,7 @@
var secOverride = document.getElementById("securityOverrideDiv");
secOverride.parentNode.removeChild(secOverride);
}
addDomainErrorLinks();
}
function showSecuritySection() {
@ -301,13 +301,16 @@
document.getElementById('securityOverrideLink').style.display = 'none';
}
/* In the case of SSL error pages about domain mismatch, see if
/* Try to preserve the links contained in the error description, like
the error code.
Also, in the case of SSL error pages about domain mismatch, see if
we can hyperlink the user to the correct site. We don't want
to do this generically since it allows MitM attacks to redirect
users to a site under attacker control, but in certain cases
it is safe (and helpful!) to do so. Bug 402210
*/
function addDomainErrorLink() {
function addDomainErrorLinks() {
// Rather than textContent, we need to treat description as HTML
var sd = document.getElementById("errorShortDescText");
if (sd) {
@ -315,30 +318,39 @@
// sanitize description text - see bug 441169
// First, find the index of the <a> tag we care about, being careful not to
// use an over-greedy regex
var re = /<a id="cert_domain_link" title="([^"]+)">/;
var result = re.exec(desc);
if(!result)
return;
// First, find the index of the <a> tags we care about, being
// careful not to use an over-greedy regex.
var codeRe = /<a id="errorCode" title="([^"]+)">/;
var codeResult = codeRe.exec(desc);
var domainRe = /<a id="cert_domain_link" title="([^"]+)">/;
var domainResult = domainRe.exec(desc);
// The order of these links in the description is fixed in
// TransportSecurityInfo.cpp:formatOverridableCertErrorMessage.
var firstResult = domainResult;
if(!domainResult)
firstResult = codeResult;
if (!firstResult)
return;
// Remove sd's existing children
sd.textContent = "";
// Everything up to the link should be text content
sd.appendChild(document.createTextNode(desc.slice(0, result.index)));
// Everything up to the first link should be text content.
sd.appendChild(document.createTextNode(desc.slice(0, firstResult.index)));
// Now create the link itself
var anchorEl = document.createElement("a");
anchorEl.setAttribute("id", "cert_domain_link");
anchorEl.setAttribute("title", result[1]);
anchorEl.appendChild(document.createTextNode(result[1]));
sd.appendChild(anchorEl);
// Now create the actual links.
if (domainResult) {
createLink(sd, "cert_domain_link", domainResult[1])
// Append text for anything between the two links.
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length, codeResult.index)));
}
createLink(sd, "errorCode", codeResult[1])
// Finally, append text for anything after the closing </a>
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length)));
// Finally, append text for anything after the last closing </a>.
sd.appendChild(document.createTextNode(desc.slice(desc.lastIndexOf("</a>") + "</a>".length)));
}
// Initialize the cert domain link.
var link = document.getElementById('cert_domain_link');
if (!link)
return;
@ -365,7 +377,7 @@
* domain names are famous for having '.' characters in them,
* which would allow spurious and possibly hostile matches.
*/
if (endsWith(okHost, "." + thisHost))
if (okHost.endsWith("." + thisHost))
link.href = proto + okHost;
/* case #2:
@ -373,12 +385,21 @@
*
* The certificate is only valid for garage.maemo.org
*/
if (endsWith(thisHost, "." + okHost))
if (thisHost.endsWith("." + okHost))
link.href = proto + okHost;
// If we set a link, meaning there's something helpful for
// the user here, expand the section by default
if (link.href && getCSSClass() != "expertBadCert")
toggleVisibility("advancedPanel");
}
function endsWith(haystack, needle) {
return haystack.slice(-needle.length) == needle;
function createLink(el, id, text) {
var anchorEl = document.createElement("a");
anchorEl.setAttribute("id", id);
anchorEl.setAttribute("title", text);
anchorEl.appendChild(document.createTextNode(text));
el.appendChild(anchorEl);
}
]]></script>
</head>
@ -444,8 +465,8 @@
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
<div id="ed_sslv3Used">&sslv3Used.longDesc;</div>
<div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc;</div>
<div id="ed_sslv3Used">&sslv3Used.longDesc2;</div>
<div id="ed_weakCryptoUsed">&weakCryptoUsed.longDesc2;</div>
</div>
</div>

Просмотреть файл

@ -55,6 +55,13 @@
{
var node = document.getElementById(id);
node.style.visibility = node.style.visibility == "" ? "hidden" : "";
// Toggling the advanced panel must ensure that the debugging
// information panel is hidden as well, since it's opened by the
// error code link in the advanced panel.
if (id == "advancedPanel") {
var div = document.getElementById("certificateErrorDebugInformation");
div.style.display = "none";
}
}
function getDescription()
@ -95,16 +102,22 @@
if (tech)
tech.textContent = getDescription();
addDomainErrorLink();
var event = new CustomEvent("AboutCertErrorLoad", {bubbles:true});
document.getElementById("advancedButton").dispatchEvent(event);
addDomainErrorLinks();
}
/* In the case of SSL error pages about domain mismatch, see if
/* Try to preserve the links contained in the error description, like
the error code.
Also, in the case of SSL error pages about domain mismatch, see if
we can hyperlink the user to the correct site. We don't want
to do this generically since it allows MitM attacks to redirect
users to a site under attacker control, but in certain cases
it is safe (and helpful!) to do so. Bug 402210
*/
function addDomainErrorLink() {
function addDomainErrorLinks() {
// Rather than textContent, we need to treat description as HTML
var sd = document.getElementById("technicalContentText");
if (sd) {
@ -112,30 +125,56 @@
// sanitize description text - see bug 441169
// First, find the index of the <a> tag we care about, being careful not to
// use an over-greedy regex
var re = /<a id="cert_domain_link" title="([^"]+)">/;
var result = re.exec(desc);
if(!result)
// First, find the index of the <a> tags we care about, being
// careful not to use an over-greedy regex.
var codeRe = /<a id="errorCode" title="([^"]+)">/;
var codeResult = codeRe.exec(desc);
var domainRe = /<a id="cert_domain_link" title="([^"]+)">/;
var domainResult = domainRe.exec(desc);
// The order of these links in the description is fixed in
// TransportSecurityInfo.cpp:formatOverridableCertErrorMessage.
var firstResult = domainResult;
if(!domainResult)
firstResult = codeResult;
if (!firstResult)
return;
// Remove sd's existing children
sd.textContent = "";
// Everything up to the link should be text content
sd.appendChild(document.createTextNode(desc.slice(0, result.index)));
// Everything up to the first link should be text content.
sd.appendChild(document.createTextNode(desc.slice(0, firstResult.index)));
// Now create the link itself
var anchorEl = document.createElement("a");
anchorEl.setAttribute("id", "cert_domain_link");
anchorEl.setAttribute("title", result[1]);
anchorEl.appendChild(document.createTextNode(result[1]));
sd.appendChild(anchorEl);
// Now create the actual links.
if (domainResult) {
createLink(sd, "cert_domain_link", domainResult[1])
// Append text for anything between the two links.
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length, codeResult.index)));
}
createLink(sd, "errorCode", codeResult[1])
// Finally, append text for anything after the closing </a>
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length)));
// Finally, append text for anything after the last closing </a>.
sd.appendChild(document.createTextNode(desc.slice(desc.lastIndexOf("</a>") + "</a>".length)));
}
// Initialize the error code link embedded in the error message to
// display debug information about the cert error.
var errorCode = document.getElementById("errorCode");
if (errorCode) {
errorCode.href = "#technicalInformation";
errorCode.addEventListener("click", () => {
var div = document.getElementById("certificateErrorDebugInformation");
if (div.style.display == "block") {
div.style.display = "none";
} else {
div.style.display = "block";
div.scrollIntoView(true);
}
}, false);
}
// Then initialize the cert domain link.
var link = document.getElementById('cert_domain_link');
if (!link)
return;
@ -178,6 +217,14 @@
if (link.href && getCSSClass() != "expertBadCert")
toggleVisibility("advancedPanel");
}
function createLink(el, id, text) {
var anchorEl = document.createElement("a");
anchorEl.setAttribute("id", id);
anchorEl.setAttribute("title", text);
anchorEl.appendChild(document.createTextNode(text));
el.appendChild(anchorEl);
}
]]></script>
</head>
@ -210,11 +257,18 @@
<!-- Advanced panel, which is hidden by default -->
<div id="advancedPanel" style="visibility: hidden;">
<p id="technicalContentText"/>
<button id='exceptionDialogButton'>&certerror.addException.label;</button>
<button id="exceptionDialogButton">&certerror.addException.label;</button>
</div>
</div>
</div>
<div id="certificateErrorDebugInformation">
<a name="technicalInformation"></a>
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
<div id="certificateErrorText"/>
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
</div>
<!--
- Note: It is important to run the script this way, instead of using
- an onload handler. This is because error pages are loaded as

Просмотреть файл

@ -2701,7 +2701,7 @@ var BrowserOnClick = {
case "Browser:CertExceptionError":
this.onAboutCertError(msg.target, msg.data.elementId,
msg.data.isTopFrame, msg.data.location,
msg.data.sslStatusAsString);
msg.data.securityInfoAsString);
break;
case "Browser:SiteBlockedError":
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
@ -2787,19 +2787,6 @@ var BrowserOnClick = {
* The request data should be added to the report by the receiving server.
*/
// TODO: can we pull this in from pippki.js isntead of duplicating it
// here?
function getDERString(cert)
{
var length = {};
var derArray = cert.getRawDER(length);
var derString = '';
for (var i = 0; i < derArray.length; i++) {
derString += String.fromCharCode(derArray[i]);
}
return derString;
}
// Convert the nsIX509CertList into a format that can be parsed into
// JSON
let asciiCertChain = [];
@ -2856,7 +2843,7 @@ var BrowserOnClick = {
xhr.send(JSON.stringify(report));
},
onAboutCertError: function (browser, elementId, isTopFrame, location, sslStatusAsString) {
onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
switch (elementId) {
@ -2867,8 +2854,9 @@ var BrowserOnClick = {
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let sslStatus = serhelper.deserializeObject(sslStatusAsString);
sslStatus.QueryInterface(Components.interfaces.nsISSLStatus);
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
.SSLStatus;
let params = { exceptionAdded : false,
sslStatus : sslStatus };
@ -2903,6 +2891,19 @@ var BrowserOnClick = {
if (isTopFrame) {
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
}
let errorInfo = getDetailedCertErrorInfo(location,
securityInfoAsString);
browser.messageManager.sendAsyncMessage("AboutCertErrorDetails",
{ info: errorInfo });
break;
case "copyToClipboard":
const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper);
let detailedInfo = getDetailedCertErrorInfo(location,
securityInfoAsString);
gClipboardHelper.copyString(detailedInfo);
break;
}
@ -3157,6 +3158,76 @@ function BrowserReloadWithFlags(reloadFlags) {
handlingUserInput: windowUtils.isHandlingUserInput });
}
/**
* Returns a string with detailed information about the certificate validation
* failure from the specified URI that can be used to send a report.
*/
function getDetailedCertErrorInfo(location, securityInfoAsString) {
if (!securityInfoAsString)
return "";
let details = [];
details.push(location);
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
let errors = Cc["@mozilla.org/nss_errors_service;1"]
.getService(Ci.nsINSSErrorsService);
let code = securityInfo.errorCode;
details.push(errors.getErrorMessage(errors.getXPCOMFromNSSError(code)));
const sss = Cc["@mozilla.org/ssservice;1"]
.getService(Ci.nsISiteSecurityService);
// SiteSecurityService uses different storage if the channel is
// private. Thus we must give isSecureHost correct flags or we
// might get incorrect results.
let flags = PrivateBrowsingUtils.isWindowPrivate(window) ?
Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
let uri = Services.io.newURI(location, null, null);
details.push(sss.isSecureHost(sss.HEADER_HSTS, uri.host, flags));
details.push(sss.isSecureHost(sss.HEADER_HPKP, uri.host, flags));
let certChain = "";
if (securityInfo.failedCertChain) {
let certs = securityInfo.failedCertChain.getEnumerator();
while (certs.hasMoreElements()) {
let cert = certs.getNext();
cert.QueryInterface(Ci.nsIX509Cert);
certChain += getPEMString(cert);
}
}
details.push(certChain);
return gNavigatorBundle.getFormattedString("certErrorDetails.label", details, 5);
}
// TODO: can we pull getDERString and getPEMString in from pippki.js instead of
// duplicating them here?
function getDERString(cert)
{
var length = {};
var derArray = cert.getRawDER(length);
var derString = '';
for (var i = 0; i < derArray.length; i++) {
derString += String.fromCharCode(derArray[i]);
}
return derString;
}
function getPEMString(cert)
{
var derb64 = btoa(getDERString(cert));
// Wrap the Base64 string into lines of 64 characters,
// with CRLF line breaks (as specified in RFC 1421).
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
return "-----BEGIN CERTIFICATE-----\r\n"
+ wrapped
+ "\r\n-----END CERTIFICATE-----\r\n";
}
var PrintPreviewListener = {
_printPreviewTab: null,
_tabBeforePrintPreview: null,
@ -5323,10 +5394,14 @@ function hrefAndLinkNodeForClickEvent(event)
let href, baseURI;
node = event.target;
while (node && !href) {
if (node.nodeType == Node.ELEMENT_NODE) {
if (node.nodeType == Node.ELEMENT_NODE &&
(node.localName == "a" ||
node.namespaceURI == "http://www.w3.org/1998/Math/MathML")) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href)
if (href) {
baseURI = node.baseURI;
break;
}
}
node = node.parentNode;
}
@ -7941,4 +8016,3 @@ TabModalPromptBox.prototype = {
return browser;
},
};

Просмотреть файл

@ -316,7 +316,6 @@ var AboutNetErrorListener = {
}
});
let failedChannel = docShell.failedChannel;
let location = contentDoc.location.href;
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
@ -436,21 +435,21 @@ var ClickEventHandler = {
.QueryInterface(Ci.nsIDocShell);
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializedSSLStatus = "";
let serializedSecurityInfo = "";
try {
let serializable = docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsISSLStatusProvider)
.SSLStatus
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
serializedSSLStatus = serhelper.serializeToString(serializable);
serializedSecurityInfo = serhelper.serializeToString(serializable);
} catch (e) { }
sendAsyncMessage("Browser:CertExceptionError", {
location: ownerDoc.location.href,
elementId: targetElement.getAttribute("id"),
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
sslStatusAsString: serializedSSLStatus
securityInfoAsString: serializedSecurityInfo
});
},
@ -520,7 +519,9 @@ var ClickEventHandler = {
let href, baseURI;
node = event.target;
while (node && !href) {
if (node.nodeType == content.Node.ELEMENT_NODE) {
if (node.nodeType == content.Node.ELEMENT_NODE &&
(node.localName == "a" ||
node.namespaceURI == "http://www.w3.org/1998/Math/MathML")) {
href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href");
if (href) {
baseURI = node.ownerDocument.baseURIObject;
@ -552,6 +553,17 @@ addEventListener("DOMServiceWorkerFocusClient", function(event) {
sendAsyncMessage("DOMServiceWorkerFocusClient", {});
}, false);
addEventListener("AboutCertErrorLoad", function(event) {
let originalTarget = event.originalTarget;
let ownerDoc = originalTarget.ownerDocument;
ClickEventHandler.onAboutCertError(originalTarget, ownerDoc);
}, false, true);
addMessageListener("AboutCertErrorDetails", function(message) {
let div = content.document.getElementById("certificateErrorText");
div.textContent = message.data.info;
});
ContentWebRTC.init();
addMessageListener("rtcpeer:Allow", ContentWebRTC);
addMessageListener("rtcpeer:Deny", ContentWebRTC);

Просмотреть файл

@ -1,8 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// This is testing the aboutCertError page (Bug 1207107). It's a start,
// but should be expanded to include cert_domain_link
// This is testing the aboutCertError page (Bug 1207107).
const GOOD_PAGE = "https://example.com/";
const BAD_CERT = "https://expired.example.com/";
@ -103,6 +102,138 @@ add_task(function* checkBadStsCert() {
gBrowser.removeCurrentTab();
});
add_task(function* checkAdvancedDetails() {
info("Loading a bad cert page and verifying the advanced details section");
let browser;
let certErrorLoaded;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
browser = gBrowser.selectedBrowser;
certErrorLoaded = waitForCertErrorLoad(browser);
}, false);
info("Loading and waiting for the cert error");
yield certErrorLoaded;
let message = yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let el = doc.getElementById("errorCode");
return { textContent: el.textContent, tagName: el.tagName };
});
is(message.textContent, "SEC_ERROR_EXPIRED_CERTIFICATE",
"Correct error message found");
is(message.tagName, "a", "Error message is a link");
message = yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: div.style.display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
is(message.divDisplay, "block", "Debug information is visible");
ok(message.text.contains(BAD_CERT), "Correct URL found");
ok(message.text.contains("Certificate has expired"),
"Correct error message found");
ok(message.text.contains("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.contains("HTTP Public Key Pinning: false"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.contains(certChain), "Found certificate chain");
gBrowser.removeCurrentTab();
});
add_task(function* checkAdvancedDetailsForHSTS() {
info("Loading a bad STS cert page and verifying the advanced details section");
let browser;
let certErrorLoaded;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = gBrowser.addTab(BAD_STS_CERT);
browser = gBrowser.selectedBrowser;
certErrorLoaded = waitForCertErrorLoad(browser);
}, false);
info("Loading and waiting for the cert error");
yield certErrorLoaded;
let message = yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let ec = doc.getElementById("errorCode");
let cdl = doc.getElementById("cert_domain_link");
return {
ecTextContent: ec.textContent,
ecTagName: ec.tagName,
cdlTextContent: cdl.textContent,
cdlTagName: cdl.tagName
};
});
const badStsUri = Services.io.newURI(BAD_STS_CERT, null, null);
is(message.ecTextContent, "SSL_ERROR_BAD_CERT_DOMAIN",
"Correct error message found");
is(message.ecTagName, "a", "Error message is a link");
const url = badStsUri.prePath.slice(badStsUri.prePath.indexOf(".") + 1);
is(message.cdlTextContent, url,
"Correct cert_domain_link contents found");
is(message.cdlTagName, "a", "cert_domain_link is a link");
message = yield ContentTask.spawn(browser, null, function* () {
let doc = content.document;
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: div.style.display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
is(message.divDisplay, "block", "Debug information is visible");
ok(message.text.contains(badStsUri.spec), "Correct URL found");
ok(message.text.contains("requested domain name does not match the server's certificate"),
"Correct error message found");
ok(message.text.contains("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.contains("HTTP Public Key Pinning: true"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.contains(certChain), "Found certificate chain");
gBrowser.removeCurrentTab();
});
function waitForCertErrorLoad(browser) {
return new Promise(resolve => {
info("Waiting for DOMContentLoaded event");
@ -112,3 +243,40 @@ function waitForCertErrorLoad(browser) {
}, false, true);
});
}
function getCertChain(securityInfoAsString) {
let certChain = "";
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
let certs = securityInfo.failedCertChain.getEnumerator();
while (certs.hasMoreElements()) {
let cert = certs.getNext();
cert.QueryInterface(Ci.nsIX509Cert);
certChain += getPEMString(cert);
}
return certChain;
}
function getDERString(cert)
{
var length = {};
var derArray = cert.getRawDER(length);
var derString = '';
for (var i = 0; i < derArray.length; i++) {
derString += String.fromCharCode(derArray[i]);
}
return derString;
}
function getPEMString(cert)
{
var derb64 = btoa(getDERString(cert));
// Wrap the Base64 string into lines of 64 characters,
// with CRLF line breaks (as specified in RFC 1421).
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
return "-----BEGIN CERTIFICATE-----\r\n"
+ wrapped
+ "\r\n-----END CERTIFICATE-----\r\n";
}

Просмотреть файл

@ -73,7 +73,7 @@ var certErrorProgressListener = {
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
let textElement = content.document.getElementById("errorShortDescText");
let text = textElement.innerHTML;
ok(text.indexOf("mozilla_pkix_error_key_pinning_failure") > 0,
ok(text.indexOf("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE") > 0,
"Got a pinning error page");
gBrowser.removeProgressListener(this);
gBrowser.selectedBrowser.addEventListener("load",

Просмотреть файл

@ -39,6 +39,9 @@ const kPrefCustomizationDebug = "browser.uiCustomization.debug";
const kPrefDrawInTitlebar = "browser.tabs.drawInTitlebar";
const kPrefWebIDEInNavbar = "devtools.webide.widget.inNavbarByDefault";
const kExpectedWindowURL = "chrome://browser/content/browser.xul";
/**
* The keys are the handlers that are fired when the event type (the value)
* is fired on the subview. A widget that provides a subview has the option
@ -1300,6 +1303,9 @@ var CustomizableUIInternal = {
},
buildWidget: function(aDocument, aWidget) {
if (aDocument.documentURI != kExpectedWindowURL) {
throw new Error("buildWidget was called for a non-browser window!");
}
if (typeof aWidget == "string") {
aWidget = gPalette.get(aWidget);
}

Просмотреть файл

@ -0,0 +1,16 @@
{
"extends": "../../../toolkit/components/extensions/.eslintrc",
"globals": {
"currentWindow": true,
"EventEmitter": true,
"IconDetails": true,
"openPanel": true,
"makeWidgetId": true,
"TabContext": true,
"AllWindowEvents": true,
"WindowEventManager": true,
"WindowListManager": true,
"WindowManager": true,
},
}

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/PlacesUtils.jsm");
@ -5,7 +9,6 @@ var Bookmarks = PlacesUtils.bookmarks;
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
EventManager,
runSafe,
} = ExtensionUtils;
@ -40,11 +43,12 @@ function getTree(rootGuid, onlyChildren) {
}
return PlacesUtils.promiseBookmarksTree(rootGuid, {
excludeItemsCallback: aItem => {
if (aItem.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR)
excludeItemsCallback: item => {
if (item.type == PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR) {
return true;
return aItem.annos &&
aItem.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
}
return item.annos &&
item.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
},
}).then(root => {
if (onlyChildren) {
@ -168,14 +172,14 @@ extensions.registerPrivilegedAPI("bookmarks", (extension, context) => {
runSafe(context, callback, convert(result));
}
}, failure);
} catch(e) {
} catch (e) {
failure(e);
}
},
move: function(id, destination, callback) {
let info = {
guid: id
guid: id,
};
if ("parentId" in destination) {
@ -204,7 +208,7 @@ extensions.registerPrivilegedAPI("bookmarks", (extension, context) => {
update: function(id, changes, callback) {
let info = {
guid: id
guid: id,
};
if ("title" in changes) {
@ -233,7 +237,7 @@ extensions.registerPrivilegedAPI("bookmarks", (extension, context) => {
remove: function(id, callback) {
let info = {
guid: id
guid: id,
};
let failure = reason => {
@ -252,8 +256,8 @@ extensions.registerPrivilegedAPI("bookmarks", (extension, context) => {
} catch (e) {
failure(e);
}
}
}
},
},
};
});

Просмотреть файл

@ -10,24 +10,19 @@ Cu.import("resource://devtools/shared/event-emitter.js");
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
EventManager,
DefaultWeakMap,
runSafe,
} = ExtensionUtils;
// WeakMap[Extension -> BrowserAction]
var browserActionMap = new WeakMap();
function browserActionOf(extension)
{
function browserActionOf(extension) {
return browserActionMap.get(extension);
}
var nextActionId = 0;
// Responsible for the browser_action section of the manifest as well
// as the associated popup.
function BrowserAction(options, extension)
{
function BrowserAction(options, extension) {
this.extension = extension;
this.id = makeWidgetId(extension.id) + "-browser-action";
this.widget = null;
@ -73,7 +68,7 @@ BrowserAction.prototype = {
let tabbrowser = document.defaultView.gBrowser;
node.addEventListener("command", event => {
node.addEventListener("command", event => { // eslint-disable-line mozilla/balanced-listeners
let tab = tabbrowser.selectedTab;
let popup = this.getProperty(tab, "popup");
this.tabManager.addActiveTabPermission(tab);
@ -88,8 +83,8 @@ BrowserAction.prototype = {
},
});
this.tabContext.on("tab-select",
(evt, tab) => { this.updateWindow(tab.ownerDocument.defaultView); })
this.tabContext.on("tab-select", // eslint-disable-line mozilla/balanced-listeners
(evt, tab) => { this.updateWindow(tab.ownerDocument.defaultView); });
this.widget = widget;
},
@ -124,7 +119,7 @@ BrowserAction.prototype = {
}
let badgeNode = node.ownerDocument.getAnonymousElementByAttribute(node,
'class', 'toolbarbutton-badge');
"class", "toolbarbutton-badge");
if (badgeNode) {
let color = tabData.badgeBackgroundColor;
if (Array.isArray(color)) {
@ -190,6 +185,7 @@ BrowserAction.prototype = {
},
};
/* eslint-disable mozilla/balanced-listeners */
extensions.on("manifest_browser_action", (type, directive, extension, manifest) => {
let browserAction = new BrowserAction(manifest.browser_action, extension);
browserAction.build();
@ -202,6 +198,7 @@ extensions.on("shutdown", (type, extension) => {
browserActionMap.delete(extension);
}
});
/* eslint-enable mozilla/balanced-listeners */
extensions.registerAPI((extension, context) => {
return {
@ -273,7 +270,6 @@ extensions.registerAPI((extension, context) => {
},
setBadgeBackgroundColor: function(details) {
let color = details.color;
let tab = details.tabId ? TabManager.getTab(details.tabId) : null;
browserActionOf(extension).setProperty(tab, "badgeBackgroundColor", details.color);
},
@ -283,6 +279,6 @@ extensions.registerAPI((extension, context) => {
let color = browserActionOf(extension).getProperty(tab, "badgeBackgroundColor");
runSafe(context, callback, color);
},
}
},
};
});

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
Cu.import("resource://gre/modules/MatchPattern.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -5,8 +9,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var {
EventManager,
contextMenuItems,
runSafe
runSafe,
} = ExtensionUtils;
@ -21,11 +24,6 @@ var onClickedCallbacksMap = new WeakMap();
// If id is not specified for an item we use an integer.
var nextID = 0;
function contextMenuObserver(subject, topic, data) {
subject = subject.wrappedJSObject;
menuBuilder.build(subject);
}
// When a new contextMenu is opened, this function is called and
// we populate the |xulMenu| with all the items from extensions
// to be displayed. We always clear all the items again when
@ -82,7 +80,7 @@ var menuBuilder = {
topLevelItems.add(element);
}
element.addEventListener("command", event => {
element.addEventListener("command", event => { // eslint-disable-line mozilla/balanced-listeners
item.tabManager.addActiveTabPermission();
if (item.onclick) {
let clickData = item.getClickData(contextData, event);
@ -124,6 +122,11 @@ var menuBuilder = {
},
_itemsToCleanUp: new Set(),
};
function contextMenuObserver(subject, topic, data) {
subject = subject.wrappedJSObject;
menuBuilder.build(subject);
}
function getContexts(contextData) {
@ -132,38 +135,37 @@ function getContexts(contextData) {
contexts.add("page");
if (contextData.inFrame) {
contexts.add("frame")
contexts.add("frame");
}
if (contextData.isTextSelected) {
contexts.add("selection")
contexts.add("selection");
}
if (contextData.onLink) {
contexts.add("link")
contexts.add("link");
}
if (contextData.onEditableArea) {
contexts.add("editable")
contexts.add("editable");
}
if (contextData.onImage) {
contexts.add("image")
contexts.add("image");
}
if (contextData.onVideo) {
contexts.add("video")
contexts.add("video");
}
if (contextData.onAudio) {
contexts.add("audio")
contexts.add("audio");
}
return contexts;
}
function MenuItem(extension, extContext, createProperties)
{
function MenuItem(extension, extContext, createProperties) {
this.extension = extension;
this.extContext = extContext;
@ -175,7 +177,7 @@ function MenuItem(extension, extContext, createProperties)
MenuItem.prototype = {
// init is called from the MenuItem ctor and from update. The |update|
// flag is for the later case.
init(createProperties, update=false) {
init(createProperties, update = false) {
let item = this;
// return true if the prop was set on |this|
function parseProp(propName, defaultValue = null) {
@ -214,8 +216,8 @@ MenuItem.prototype = {
let found = false;
let menuMap = contextMenuMap.get(this.extension);
if (menuMap.has(this.parentId)) {
found = true;
menuMap.get(this.parentId).isMenu = true;
found = true;
menuMap.get(this.parentId).isMenu = true;
}
if (!found) {
throw new Error("MenuItem with this parentId not found");
@ -265,7 +267,7 @@ MenuItem.prototype = {
let toRemove = new Set();
toRemove.add(this.id);
for (let [id, item] of menuMap) {
for (let [, item] of menuMap) {
if (hasAncestorWithId(item, this.id)) {
toRemove.add(item.id);
}
@ -288,7 +290,7 @@ MenuItem.prototype = {
}
let clickData = {
menuItemId: this.id
menuItemId: this.id,
};
function setIfDefined(argName, value) {
@ -318,7 +320,7 @@ MenuItem.prototype = {
for (let c of this.contexts) {
if (contexts.has(c)) {
enabled = true;
break
break;
}
}
if (!enabled) {
@ -342,6 +344,7 @@ MenuItem.prototype = {
};
var extCount = 0;
/* eslint-disable mozilla/balanced-listeners */
extensions.on("startup", (type, extension) => {
contextMenuMap.set(extension, new Map());
if (++extCount == 1) {
@ -358,6 +361,7 @@ extensions.on("shutdown", (type, extension) => {
"on-build-contextmenu");
}
});
/* eslint-enable mozilla/balanced-listeners */
extensions.registerPrivilegedAPI("contextMenus", (extension, context) => {
return {
@ -392,7 +396,7 @@ extensions.registerPrivilegedAPI("contextMenus", (extension, context) => {
},
removeAll: function(callback) {
for (let [id, menuItem] of contextMenuMap.get(extension)) {
for (let [, menuItem] of contextMenuMap.get(extension)) {
menuItem.remove();
}
if (callback) {

Просмотреть файл

@ -5,7 +5,6 @@
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
EventManager,
DefaultWeakMap,
runSafe,
} = ExtensionUtils;
@ -15,8 +14,7 @@ var pageActionMap = new WeakMap();
// Handles URL bar icons, including the |page_action| manifest entry
// and associated API.
function PageAction(options, extension)
{
function PageAction(options, extension) {
this.extension = extension;
this.id = makeWidgetId(extension.id) + "-page-action";
@ -39,7 +37,7 @@ function PageAction(options, extension)
this.tabContext = new TabContext(tab => Object.create(this.defaults),
extension);
this.tabContext.on("location-change", this.handleLocationChange.bind(this));
this.tabContext.on("location-change", this.handleLocationChange.bind(this)); // eslint-disable-line mozilla/balanced-listeners
// WeakMap[ChromeWindow -> <xul:image>]
this.buttons = new WeakMap();
@ -110,7 +108,7 @@ PageAction.prototype = {
button.id = this.id;
button.setAttribute("class", "urlbar-icon");
button.addEventListener("click", event => {
button.addEventListener("click", event => { // eslint-disable-line mozilla/balanced-listeners
if (event.button == 0) {
this.handleClick(window);
}
@ -173,6 +171,7 @@ PageAction.for = extension => {
};
/* eslint-disable mozilla/balanced-listeners */
extensions.on("manifest_page_action", (type, directive, extension, manifest) => {
let pageAction = new PageAction(manifest.page_action, extension);
pageActionMap.set(extension, pageAction);
@ -184,6 +183,7 @@ extensions.on("shutdown", (type, extension) => {
pageActionMap.delete(extension);
}
});
/* eslint-enable mozilla/balanced-listeners */
extensions.registerAPI((extension, context) => {
@ -244,6 +244,6 @@ extensions.registerAPI((extension, context) => {
let popup = PageAction.for(extension).getProperty(tab, "popup");
runSafe(context, callback, popup);
},
}
},
};
});

Просмотреть файл

@ -1,3 +1,5 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
@ -10,6 +12,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "MatchPattern",
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
/* globals aboutNewTabService */
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
@ -20,8 +24,7 @@ var {
// This function is pretty tightly tied to Extension.jsm.
// Its job is to fill in the |tab| property of the sender.
function getSender(context, target, sender)
{
function getSender(context, target, sender) {
// The message was sent from a content script to a <browser> element.
// We can just get the |tab| from |target|.
if (target instanceof Ci.nsIDOMXULElement) {
@ -33,20 +36,19 @@ function getSender(context, target, sender)
let tab = tabbrowser.getTabForBrowser(target);
sender.tab = TabManager.convert(context.extension, tab);
} else {
} else if ("tabId" in sender) {
// The message came from an ExtensionPage. In that case, it should
// include a tabId property (which is filled in by the page-open
// listener below).
if ("tabId" in sender) {
sender.tab = TabManager.convert(context.extension, TabManager.getTab(sender.tabId));
delete sender.tabId;
}
sender.tab = TabManager.convert(context.extension, TabManager.getTab(sender.tabId));
delete sender.tabId;
}
}
// WeakMap[ExtensionPage -> {tab, parentWindow}]
var pageDataMap = new WeakMap();
/* eslint-disable mozilla/balanced-listeners */
// This listener fires whenever an extension page opens in a tab
// (either initiated by the extension or the user). Its job is to fill
// in some tab-specific details and keep data around about the
@ -95,15 +97,15 @@ extensions.on("fill-browser-data", (type, browser, data, result) => {
data.tabId = tabId;
});
/* eslint-enable mozilla/balanced-listeners */
global.currentWindow = function(context)
{
global.currentWindow = function(context) {
let pageData = pageDataMap.get(context);
if (pageData) {
return pageData.parentWindow;
}
return WindowManager.topWindow;
}
};
// TODO: activeTab permission
@ -211,7 +213,7 @@ extensions.registerAPI((extension, context) => {
let tabId = TabManager.getId(tab);
let [needed, changeInfo] = sanitize(extension, {
status: webProgress.isLoadingDocument ? "loading" : "complete",
url: locationURI.spec
url: locationURI.spec,
});
if (needed) {
fire(tabId, changeInfo, TabManager.convert(extension, tab));
@ -389,7 +391,7 @@ extensions.registerAPI((extension, context) => {
getAllInWindow: function(...args) {
let window, callback;
if (args.length == 1) {
callbacks = args[0];
callback = args[0];
} else {
window = WindowManager.getWindow(args[0]);
callback = args[1];
@ -435,10 +437,8 @@ extensions.registerAPI((extension, context) => {
if (currentWindow(context) != window) {
return false;
}
} else {
if (queryInfo.windowId != tab.windowId) {
return false;
}
} else if (queryInfo.windowId != tab.windowId) {
return false;
}
}
@ -495,7 +495,7 @@ extensions.registerAPI((extension, context) => {
}
if (details.code) {
options[kind + 'Code'] = details.code;
options[kind + "Code"] = details.code;
}
if (details.file) {
let url = context.uri.resolve(details.file);
@ -522,17 +522,17 @@ extensions.registerAPI((extension, context) => {
executeScript: function(...args) {
if (args.length == 1) {
self.tabs._execute(undefined, args[0], 'js', undefined);
self.tabs._execute(undefined, args[0], "js", undefined);
} else {
self.tabs._execute(args[0], args[1], 'js', args[2]);
self.tabs._execute(args[0], args[1], "js", args[2]);
}
},
insertCss: function(tabId, details, callback) {
insertCss: function(...args) {
if (args.length == 1) {
self.tabs._execute(undefined, args[0], 'css', undefined);
self.tabs._execute(undefined, args[0], "css", undefined);
} else {
self.tabs._execute(args[0], args[1], 'css', args[2]);
self.tabs._execute(args[0], args[1], "css", args[2]);
}
},

Просмотреть файл

@ -31,7 +31,7 @@ global.IconDetails = {
//
// If no context is specified, instead of throwing an error, this
// function simply logs a warning message.
normalize(details, extension, context=null, localize=false) {
normalize(details, extension, context = null, localize = false) {
let result = {};
try {
@ -112,14 +112,14 @@ global.IconDetails = {
canvas.getContext("2d").putImageData(imageData, 0, 0);
return canvas.toDataURL("image/png");
}
},
};
global.makeWidgetId = id => {
id = id.toLowerCase();
// FIXME: This allows for collisions.
return id.replace(/[^a-z0-9_-]/g, "_");
}
};
// Open a panel anchored to the given node, containing a browser opened
// to the given URL, owned by the given extension. If |popupURL| is not
@ -161,14 +161,16 @@ global.openPanel = (node, popupURL, extension) => {
let titleChangedListener = () => {
panel.setAttribute("aria-label", browser.contentTitle);
}
};
let context;
panel.addEventListener("popuphidden", () => {
let popuphidden = () => {
panel.removeEventListener("popuphidden", popuphidden);
browser.removeEventListener("DOMTitleChanged", titleChangedListener, true);
context.unload();
panel.remove();
});
};
panel.addEventListener("popuphidden", popuphidden);
let loadListener = () => {
panel.removeEventListener("load", loadListener);
@ -216,7 +218,7 @@ global.openPanel = (node, popupURL, extension) => {
panel.addEventListener("load", loadListener);
return panel;
}
};
// Manages tab-specific context data, and dispatching tab select events
// across all windows.
@ -230,7 +232,7 @@ global.TabContext = function TabContext(getDefaults, extension) {
AllWindowEvents.addListener("TabSelect", this);
EventEmitter.decorate(this);
}
};
TabContext.prototype = {
get(tab) {
@ -311,7 +313,6 @@ ExtensionTabManager.prototype = {
convert(tab) {
let window = tab.ownerDocument.defaultView;
let windowActive = window == WindowManager.topWindow;
let result = {
id: TabManager.getId(tab),
@ -411,16 +412,18 @@ let tabManagers = new WeakMap();
// Returns the extension-specific tab manager for the given extension, or
// creates one if it doesn't already exist.
TabManager.for = function (extension) {
TabManager.for = function(extension) {
if (!tabManagers.has(extension)) {
tabManagers.set(extension, new ExtensionTabManager(extension));
}
return tabManagers.get(extension);
};
/* eslint-disable mozilla/balanced-listeners */
extensions.on("shutdown", (type, extension) => {
tabManagers.delete(extension);
});
/* eslint-enable mozilla/balanced-listeners */
// Manages mapping between XUL windows and extension window IDs.
global.WindowManager = {
@ -489,7 +492,7 @@ global.WindowListManager = {
// Returns an iterator for all browser windows. Unless |includeIncomplete| is
// true, only fully-loaded windows are returned.
*browserWindows(includeIncomplete = false) {
* browserWindows(includeIncomplete = false) {
// The window type parameter is only available once the window's document
// element has been created. This means that, when looking for incomplete
// browser windows, we need to ignore the type entirely for windows which
@ -654,15 +657,14 @@ AllWindowEvents.openListener = AllWindowEvents.openListener.bind(AllWindowEvents
// Subclass of EventManager where we just need to call
// add/removeEventListener on each XUL window.
global.WindowEventManager = function(context, name, event, listener)
{
global.WindowEventManager = function(context, name, event, listener) {
EventManager.call(this, context, name, fire => {
let listener2 = (...args) => listener(fire, ...args);
AllWindowEvents.addListener(event, listener2);
return () => {
AllWindowEvents.removeListener(event, listener2);
}
};
});
}
};
WindowEventManager.prototype = Object.create(EventManager.prototype);

Просмотреть файл

@ -1,7 +1,13 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
/* globals aboutNewTabService */
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
EventManager,

Просмотреть файл

@ -0,0 +1,43 @@
{
"extends": "../../.eslintrc",
"globals": {
// DOM window globals
"CustomEvent": false,
"document": false,
"ImageData": false,
"MouseEvent": false,
"window": false,
"XMLHttpRequest": false,
"gBrowser": false,
"sendAsyncMessage": false,
"NetUtil": true,
"XPCOMUtils": true,
"Task": true,
"browser": false,
// Test harness globals
"add_task": false,
"BrowserTestUtils": false,
"ContentTask": false,
"EventUtils": false,
"ExtensionTestUtils": false,
"info": false,
"is": false,
"ok": false,
"registerCleanupFunction": false,
"SimpleTest": false,
"SpecialPowers": false,
"waitForFocus": false,
"clickBrowserAction": true,
"clickPageAction": true,
"CustomizableUI": true,
"focusWindow": true,
"makeWidgetId": true,
}
}

Просмотреть файл

@ -3,7 +3,6 @@
"use strict";
add_task(function* testTabSwitchContext() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {
@ -14,8 +13,8 @@ add_task(function* testTabSwitchContext() {
"permissions": ["tabs"],
},
background: function () {
var details = [
background: function() {
let details = [
{ "icon": browser.runtime.getURL("default.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title",
@ -51,9 +50,10 @@ add_task(function* testTabSwitchContext() {
"badgeBackgroundColor": [0, 0xff, 0] },
];
var tabs = [];
let tabs = [];
var tests = [
let expectDefaults;
let tests = [
expect => {
browser.test.log("Initial state, expect default properties.");
expectDefaults(details[0]).then(() => {
@ -78,7 +78,7 @@ add_task(function* testTabSwitchContext() {
},
expect => {
browser.test.log("Change properties. Expect new properties.");
var tabId = tabs[1];
let tabId = tabs[1];
browser.browserAction.setIcon({ tabId, path: "2.png" });
browser.browserAction.setPopup({ tabId, popup: "2.html" });
browser.browserAction.setTitle({ tabId, title: "Title 2" });
@ -191,14 +191,14 @@ add_task(function* testTabSwitchContext() {
});
}
function expectDefaults(expecting) {
expectDefaults = expecting => {
return checkDetails(expecting);
}
};
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
var test = tests.shift();
let test = tests.shift();
test(expecting => {
// Check that the API returns the expected values, and then
@ -247,11 +247,11 @@ add_task(function* testTabSwitchContext() {
if (details.badge && details.badgeBackgroundColor) {
let badge = button.ownerDocument.getAnonymousElementByAttribute(
button, 'class', 'toolbarbutton-badge');
button, "class", "toolbarbutton-badge");
let badgeColor = window.getComputedStyle(badge).backgroundColor;
let color = details.badgeBackgroundColor;
let expectedColor = `rgb(${color[0]}, ${color[1]}, ${color[2]})`
let expectedColor = `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
is(badgeColor, expectedColor, "badge color is correct");
}
@ -265,7 +265,7 @@ add_task(function* testTabSwitchContext() {
checkDetails(expecting);
if (testsRemaining) {
extension.sendMessage("runNextTest")
extension.sendMessage("runNextTest");
} else {
resolve();
}

Просмотреть файл

@ -3,14 +3,13 @@
"use strict";
add_task(function* testDisabled() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {}
"browser_action": {},
},
background: function () {
var clicked = false;
background: function() {
let clicked = false;
browser.browserAction.onClicked.addListener(() => {
browser.test.log("Got click event");

Просмотреть файл

@ -8,10 +8,10 @@
add_task(function* testDetailsObjects() {
function background() {
function getImageData(color) {
var canvas = document.createElement("canvas");
let canvas = document.createElement("canvas");
canvas.width = 2;
canvas.height = 2;
var canvasContext = canvas.getContext("2d");
let canvasContext = canvas.getContext("2d");
canvasContext.clearRect(0, 0, canvas.width, canvas.height);
canvasContext.fillStyle = color;
@ -23,12 +23,13 @@ add_task(function* testDetailsObjects() {
};
}
var imageData = {
let imageData = {
red: getImageData("red"),
green: getImageData("green"),
};
var iconDetails = [
/* eslint-disable comma-dangle, indent */
let iconDetails = [
// Only paths.
{ details: { "path": "a.png" },
resolutions: {
@ -129,18 +130,18 @@ add_task(function* testDetailsObjects() {
// Allow serializing ImageData objects for logging.
ImageData.prototype.toJSON = () => "<ImageData>";
var tabId;
let tabId;
browser.test.onMessage.addListener((msg, test) => {
if (msg != "setIcon") {
browser.test.fail("expecting 'setIcon' message");
}
var details = iconDetails[test.index];
var expectedURL = details.resolutions[test.resolution];
let details = iconDetails[test.index];
let expectedURL = details.resolutions[test.resolution];
var detailString = JSON.stringify(details);
browser.test.log(`Setting browerAction/pageAction to ${detailString} expecting URL ${expectedURL}`)
let detailString = JSON.stringify(details);
browser.test.log(`Setting browerAction/pageAction to ${detailString} expecting URL ${expectedURL}`);
browser.browserAction.setIcon(Object.assign({tabId}, details.details));
browser.pageAction.setIcon(Object.assign({tabId}, details.details));
@ -158,9 +159,9 @@ add_task(function* testDetailsObjects() {
// objects without issue. Unfortunately, |cloneInto| implements a slightly
// different algorithm than we use in web APIs, and does not handle them
// correctly.
var tests = [];
for (var [idx, icon] of iconDetails.entries()) {
for (var res of Object.keys(icon.resolutions)) {
let tests = [];
for (let [idx, icon] of iconDetails.entries()) {
for (let res of Object.keys(icon.resolutions)) {
tests.push({ index: idx, resolution: Number(res) });
}
}
@ -221,19 +222,18 @@ add_task(function* testDetailsObjects() {
});
// Test that an error is thrown when providing invalid icon sizes
add_task(function *testInvalidIconSizes() {
add_task(function* testInvalidIconSizes() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {},
"page_action": {},
},
background: function () {
background: function() {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
var tabId = tabs[0].id;
let tabId = tabs[0].id;
for (var api of ["pageAction", "browserAction"]) {
for (let api of ["pageAction", "browserAction"]) {
// helper function to run setIcon and check if it fails
let assertSetIconThrows = function(detail, error, message) {
try {
@ -246,10 +246,10 @@ add_task(function *testInvalidIconSizes() {
} catch (e) {
browser.test.succeed("setIcon with invalid icon size");
}
}
};
// test invalid icon size inputs
for (var type of ["path", "imageData"]) {
for (let type of ["path", "imageData"]) {
assertSetIconThrows({ [type]: { "abcdef": "test.png" } });
assertSetIconThrows({ [type]: { "48px": "test.png" } });
assertSetIconThrows({ [type]: { "20.5": "test.png" } });
@ -278,7 +278,7 @@ add_task(function *testInvalidIconSizes() {
// Test that default icon details in the manifest.json file are handled
// correctly.
add_task(function *testDefaultDetails() {
add_task(function* testDefaultDetails() {
// TODO: Test localized variants.
let icons = [
"foo/bar.png",
@ -297,9 +297,9 @@ add_task(function *testDefaultDetails() {
"page_action": { "default_icon": icon },
},
background: function () {
background: function() {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
var tabId = tabs[0].id;
let tabId = tabs[0].id;
browser.pageAction.show(tabId);
browser.test.sendMessage("ready");
@ -332,7 +332,6 @@ add_task(function *testDefaultDetails() {
// Check that attempts to load a privileged URL as an icon image fail.
add_task(function* testSecureURLsDenied() {
// Test URLs passed to setIcon.
let extension = ExtensionTestUtils.loadExtension({
@ -341,15 +340,15 @@ add_task(function* testSecureURLsDenied() {
"page_action": {},
},
background: function () {
background: function() {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
var tabId = tabs[0].id;
let tabId = tabs[0].id;
var urls = ["chrome://browser/content/browser.xul",
let urls = ["chrome://browser/content/browser.xul",
"javascript:true"];
for (var url of urls) {
for (var api of ["pageAction", "browserAction"]) {
for (let url of urls) {
for (let api of ["pageAction", "browserAction"]) {
try {
browser[api].setIcon({tabId, path: url});

Просмотреть файл

@ -20,11 +20,11 @@ add_task(function* testPageActionPopup() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"background": {
"page": "data/background.html"
"page": "data/background.html",
},
"browser_action": {
"default_popup": "popup-a.html"
}
"default_popup": "popup-a.html",
},
},
files: {
@ -41,7 +41,8 @@ add_task(function* testPageActionPopup() {
"data/background.html": `<script src="background.js"></script>`,
"data/background.js": function() {
var tests = [
let sendClick;
let tests = [
() => {
sendClick({ expectEvent: false, expectPopup: "a" });
},
@ -68,11 +69,11 @@ add_task(function* testPageActionPopup() {
},
];
var expect = {};
function sendClick({ expectEvent, expectPopup }) {
let expect = {};
sendClick = ({ expectEvent, expectPopup }) => {
expect = { event: expectEvent, popup: expectPopup };
browser.test.sendMessage("send-click");
}
};
browser.runtime.onMessage.addListener(msg => {
if (expect.popup) {
@ -103,7 +104,7 @@ add_task(function* testPageActionPopup() {
}
if (tests.length) {
var test = tests.shift();
let test = tests.shift();
test();
} else {
browser.test.notifyPass("browseraction-tests-done");

Просмотреть файл

@ -1,9 +1,13 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"browser_action": {
"default_popup": "popup.html"
}
"default_popup": "popup.html",
},
},
files: {
@ -16,7 +20,7 @@ add_task(function* () {
"popup.js": function() {
browser.runtime.sendMessage("from-popup");
}
},
},
background: function() {
@ -36,7 +40,7 @@ add_task(function* () {
for (let i = 0; i < 3; i++) {
let evt = new CustomEvent("command", {
bubbles: true,
cancelable: true
cancelable: true,
});
node.dispatchEvent(evt);

Просмотреть файл

@ -1,14 +1,18 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["http://mochi.test/"]
"permissions": ["http://mochi.test/"],
},
background: function() {
var ports_received = 0;
var port_messages_received = 0;
let ports_received = 0;
let port_messages_received = 0;
browser.runtime.onConnect.addListener((port) => {
browser.test.assertTrue(!!port, "port1 received");
@ -19,9 +23,9 @@ add_task(function* () {
port.onMessage.addListener((msg, sender) => {
browser.test.assertEq("port message", msg, "listener1 port message received");
port_messages_received++
port_messages_received++;
browser.test.assertEq(1, port_messages_received, "1 port message received");
})
});
});
browser.runtime.onConnect.addListener((port) => {
browser.test.assertTrue(!!port, "port2 received");
@ -32,7 +36,7 @@ add_task(function* () {
port.onMessage.addListener((msg, sender) => {
browser.test.assertEq("port message", msg, "listener2 port message received");
port_messages_received++
port_messages_received++;
browser.test.assertEq(2, port_messages_received, "2 port messages received");
browser.test.notifyPass("contentscript_connect.pass");
@ -44,10 +48,10 @@ add_task(function* () {
files: {
"script.js": function() {
var port = browser.runtime.connect();
let port = browser.runtime.connect();
port.postMessage("port message");
}
}
},
},
});
yield extension.startup();

Просмотреть файл

@ -1,3 +1,10 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
/* globals content */
/* eslint-disable mozilla/no-cpows-in-tests */
add_task(function* () {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
"http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
@ -6,7 +13,7 @@ add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["contextMenus"]
"permissions": ["contextMenus"],
},
background: function() {
@ -17,27 +24,27 @@ add_task(function* () {
browser.contextMenus.create({ "contexts": ["all"], "type": "separator" });
var contexts = ["page", "selection", "image"];
for (var i = 0; i < contexts.length; i++) {
var context = contexts[i];
var title = context;
var id = browser.contextMenus.create({ "title": title, "contexts": [context], "id": "ext-" + context,
"onclick": genericOnClick });
let contexts = ["page", "selection", "image"];
for (let i = 0; i < contexts.length; i++) {
let context = contexts[i];
let title = context;
browser.contextMenus.create({ "title": title, "contexts": [context], "id": "ext-" + context,
"onclick": genericOnClick });
if (context == "selection") {
browser.contextMenus.update("ext-selection", { "title": "selection-edited" });
}
}
var parent = browser.contextMenus.create({ "title": "parent" });
var child1 = browser.contextMenus.create(
let parent = browser.contextMenus.create({ "title": "parent" });
browser.contextMenus.create(
{ "title": "child1", "parentId": parent, "onclick": genericOnClick });
var child2 = browser.contextMenus.create(
browser.contextMenus.create(
{ "title": "child2", "parentId": parent, "onclick": genericOnClick });
var parentToDel = browser.contextMenus.create({ "title": "parentToDel" });
var child1ToDel = browser.contextMenus.create(
let parentToDel = browser.contextMenus.create({ "title": "parentToDel" });
browser.contextMenus.create(
{ "title": "child1", "parentId": parentToDel, "onclick": genericOnClick });
var child2ToDel = browser.contextMenus.create(
browser.contextMenus.create(
{ "title": "child2", "parentId": parentToDel, "onclick": genericOnClick });
browser.contextMenus.remove(parentToDel);
@ -84,7 +91,7 @@ add_task(function* () {
items = top.getElementsByAttribute("label", "parent");
is(items.length, 1, "contextMenu item for parent was found (context=image)");
is(items.item(0).childNodes[0].childNodes.length, 2, "child items for parent were found (context=image)")
is(items.item(0).childNodes[0].childNodes.length, 2, "child items for parent were found (context=image)");
// Click on ext-image item and check the results
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");

Просмотреть файл

@ -1,7 +1,10 @@
function genericChecker()
{
var kind = "background";
var path = window.location.pathname;
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function genericChecker() {
let kind = "background";
let path = window.location.pathname;
if (path.indexOf("popup") != -1) {
kind = "popup";
} else if (path.indexOf("page") != -1) {
@ -11,13 +14,13 @@ function genericChecker()
browser.test.onMessage.addListener((msg, ...args) => {
if (msg == kind + "-check-current1") {
browser.tabs.query({
currentWindow: true
currentWindow: true,
}, function(tabs) {
browser.test.sendMessage("result", tabs[0].windowId);
});
} else if (msg == kind + "-check-current2") {
browser.tabs.query({
windowId: browser.windows.WINDOW_ID_CURRENT
windowId: browser.windows.WINDOW_ID_CURRENT,
}, function(tabs) {
browser.test.sendMessage("result", tabs[0].windowId);
});
@ -26,12 +29,12 @@ function genericChecker()
browser.test.sendMessage("result", window.id);
});
} else if (msg == kind + "-open-page") {
browser.tabs.create({windowId: args[0], url: chrome.runtime.getURL("page.html")});
browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("page.html")});
} else if (msg == kind + "-close-page") {
browser.tabs.query({
windowId: args[0],
}, tabs => {
var tab = tabs.find(tab => tab.url.indexOf("page.html") != -1);
let tab = tabs.find(tab => tab.url.indexOf("page.html") != -1);
browser.tabs.remove(tab.id, () => {
browser.test.sendMessage("closed");
});
@ -58,7 +61,7 @@ add_task(function* () {
"permissions": ["tabs"],
"browser_action": {
"default_popup": "popup.html"
"default_popup": "popup.html",
},
},
@ -87,7 +90,7 @@ add_task(function* () {
yield Promise.all([extension.startup(), extension.awaitMessage("background-ready")]);
let {TabManager, WindowManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
let {WindowManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
let winId1 = WindowManager.getId(win1);
let winId2 = WindowManager.getId(win2);
@ -112,7 +115,7 @@ add_task(function* () {
let evt = new CustomEvent("command", {
bubbles: true,
cancelable: true
cancelable: true,
});
node.dispatchEvent(evt);

Просмотреть файл

@ -1,7 +1,10 @@
function genericChecker()
{
var kind = "background";
var path = window.location.pathname;
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function genericChecker() {
let kind = "background";
let path = window.location.pathname;
if (path.indexOf("popup") != -1) {
kind = "popup";
} else if (path.indexOf("tab") != -1) {
@ -11,14 +14,14 @@ function genericChecker()
browser.test.onMessage.addListener((msg, ...args) => {
if (msg == kind + "-check-views") {
var views = browser.extension.getViews();
var counts = {
let views = browser.extension.getViews();
let counts = {
"background": 0,
"tab": 0,
"popup": 0
"popup": 0,
};
for (var i = 0; i < views.length; i++) {
var view = views[i];
for (let i = 0; i < views.length; i++) {
let view = views[i];
browser.test.assertTrue(view.kind in counts, "view type is valid");
counts[view.kind]++;
if (view.kind == "background") {
@ -28,12 +31,12 @@ function genericChecker()
}
browser.test.sendMessage("counts", counts);
} else if (msg == kind + "-open-tab") {
browser.tabs.create({windowId: args[0], url: chrome.runtime.getURL("tab.html")});
browser.tabs.create({windowId: args[0], url: browser.runtime.getURL("tab.html")});
} else if (msg == kind + "-close-tab") {
browser.tabs.query({
windowId: args[0],
}, tabs => {
var tab = tabs.find(tab => tab.url.indexOf("tab.html") != -1);
let tab = tabs.find(tab => tab.url.indexOf("tab.html") != -1);
browser.tabs.remove(tab.id, () => {
browser.test.sendMessage("closed");
});
@ -52,7 +55,7 @@ add_task(function* () {
"permissions": ["tabs"],
"browser_action": {
"default_popup": "popup.html"
"default_popup": "popup.html",
},
},
@ -83,7 +86,7 @@ add_task(function* () {
info("started");
let {TabManager, WindowManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
let {WindowManager} = Cu.import("resource://gre/modules/Extension.jsm", {});
let winId1 = WindowManager.getId(win1);
let winId2 = WindowManager.getId(win2);
@ -118,7 +121,7 @@ add_task(function* () {
let evt = new CustomEvent("command", {
bubbles: true,
cancelable: true
cancelable: true,
});
node.dispatchEvent(evt);

Просмотреть файл

@ -3,7 +3,6 @@
"use strict";
add_task(function* testTabSwitchContext() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"page_action": {
@ -14,8 +13,8 @@ add_task(function* testTabSwitchContext() {
"permissions": ["tabs"],
},
background: function () {
var details = [
background: function() {
let details = [
{ "icon": browser.runtime.getURL("default.png"),
"popup": browser.runtime.getURL("default.html"),
"title": "Default Title" },
@ -27,9 +26,9 @@ add_task(function* testTabSwitchContext() {
"title": "Title 2" },
];
var tabs;
var tests;
var allTests = [
let tabs;
let tests;
let allTests = [
expect => {
browser.test.log("Initial state. No icon visible.");
expect(null);
@ -53,7 +52,7 @@ add_task(function* testTabSwitchContext() {
},
expect => {
browser.test.log("Change properties. Expect new properties.");
var tabId = tabs[1];
let tabId = tabs[1];
browser.pageAction.show(tabId);
browser.pageAction.setIcon({ tabId, path: "2.png" });
browser.pageAction.setPopup({ tabId, popup: "2.html" });
@ -112,10 +111,10 @@ add_task(function* testTabSwitchContext() {
return new Promise(resolve => {
return browser.tabs.query({ active: true, currentWindow: true }, resolve);
}).then(tabs => {
var tabId = tabs[0].id;
let tabId = tabs[0].id;
return Promise.all([
new Promise(resolve => browser.pageAction.getTitle({tabId}, resolve)),
new Promise(resolve => browser.pageAction.getPopup({tabId}, resolve))])
new Promise(resolve => browser.pageAction.getPopup({tabId}, resolve))]);
}).then(details => {
return Promise.resolve({ title: details[0],
popup: details[1] });
@ -126,7 +125,7 @@ add_task(function* testTabSwitchContext() {
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
var test = tests.shift();
let test = tests.shift();
test(expecting => {
function finish() {
@ -153,16 +152,6 @@ add_task(function* testTabSwitchContext() {
});
}
browser.test.onMessage.addListener((msg) => {
if (msg == "runTests") {
runTests();
} else if (msg == "runNextTest") {
nextTest();
} else {
browser.test.fail(`Unexpected message: ${msg}`);
}
});
function runTests() {
tabs = [];
tests = allTests.slice();
@ -174,6 +163,16 @@ add_task(function* testTabSwitchContext() {
});
}
browser.test.onMessage.addListener((msg) => {
if (msg == "runTests") {
runTests();
} else if (msg == "runNextTest") {
nextTest();
} else {
browser.test.fail(`Unexpected message: ${msg}`);
}
});
runTests();
},
});
@ -203,7 +202,7 @@ add_task(function* testTabSwitchContext() {
checkDetails(expecting);
if (testsRemaining) {
extension.sendMessage("runNextTest")
extension.sendMessage("runNextTest");
} else if (testNewWindows) {
testNewWindows--;
@ -212,7 +211,7 @@ add_task(function* testTabSwitchContext() {
currentWindow = window;
return focusWindow(window);
}).then(() => {
extension.sendMessage("runTests")
extension.sendMessage("runTests");
});
} else {
resolve();

Просмотреть файл

@ -20,11 +20,11 @@ add_task(function* testPageActionPopup() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"background": {
"page": "data/background.html"
"page": "data/background.html",
},
"page_action": {
"default_popup": "popup-a.html"
}
"default_popup": "popup-a.html",
},
},
files: {
@ -41,9 +41,10 @@ add_task(function* testPageActionPopup() {
"data/background.html": `<script src="background.js"></script>`,
"data/background.js": function() {
var tabId;
let tabId;
var tests = [
let sendClick;
let tests = [
() => {
sendClick({ expectEvent: false, expectPopup: "a" });
},
@ -70,11 +71,11 @@ add_task(function* testPageActionPopup() {
},
];
var expect = {};
function sendClick({ expectEvent, expectPopup }) {
let expect = {};
sendClick = ({ expectEvent, expectPopup }) => {
expect = { event: expectEvent, popup: expectPopup };
browser.test.sendMessage("send-click");
}
};
browser.runtime.onMessage.addListener(msg => {
if (expect.popup) {
@ -105,7 +106,7 @@ add_task(function* testPageActionPopup() {
}
if (tests.length) {
var test = tests.shift();
let test = tests.shift();
test();
} else {
browser.test.notifyPass("pageaction-tests-done");
@ -159,10 +160,6 @@ add_task(function* testPageActionPopup() {
add_task(function* testPageActionSecurity() {
const URL = "chrome://browser/content/browser.xul";
let matchURLForbidden = url => ({
message: new RegExp(`Loading extension.*Access to.*'${URL}' denied`),
});
let messages = [/Access to restricted URI denied/,
/Access to restricted URI denied/];
@ -180,9 +177,9 @@ add_task(function* testPageActionSecurity() {
"page_action": { "default_popup": URL },
},
background: function () {
background: function() {
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
var tabId = tabs[0].id;
let tabId = tabs[0].id;
browser.pageAction.show(tabId);
browser.test.sendMessage("ready");

Просмотреть файл

@ -26,7 +26,7 @@ add_task(function* testPageActionPopup() {
},
background: function() {
let tabId
let tabId;
browser.tabs.query({ active: true, currentWindow: true }, tabs => {
tabId = tabs[0].id;
browser.pageAction.show(tabId);
@ -53,7 +53,7 @@ add_task(function* testPageActionPopup() {
} else {
EventUtils.synthesizeMouseAtCenter(button, {}, window);
}
};
}
let promiseConsoleMessage = pattern => new Promise(resolve => {
Services.console.registerListener(function listener(msg) {

Просмотреть файл

@ -1,11 +1,15 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_simple() {
let extensionData = {
manifest: {
"name": "Simple extension test",
"version": "1.0",
"manifest_version": 2,
"description": ""
}
"description": "",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
@ -36,8 +40,8 @@ add_task(function* test_background() {
"name": "Simple extension test",
"version": "1.0",
"manifest_version": 2,
"description": ""
}
"description": "",
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);

Просмотреть файл

@ -1,19 +1,23 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
var messages_received = [];
let messages_received = [];
var tabId;
let tabId;
browser.runtime.onConnect.addListener((port) => {
browser.test.assertTrue(!!port, "tab to background port received");
browser.test.assertEq("tab-connection-name", port.name, "port name should be defined and equal to connectInfo.name")
browser.test.assertEq("tab-connection-name", port.name, "port name should be defined and equal to connectInfo.name");
browser.test.assertTrue(!!port.sender.tab, "port.sender.tab should be defined");
browser.test.assertEq(tabId, port.sender.tab.id, "port.sender.tab.id should be equal to the expected tabId");
@ -31,17 +35,16 @@ add_task(function* () {
browser.test.notifyPass("tabRuntimeConnect.pass");
}
})
});
});
browser.tabs.create({
url: "tab.html"
}, (tab) => { tabId = tab.id });
browser.tabs.create({ url: "tab.html" },
(tab) => { tabId = tab.id; });
},
files: {
"tab.js": function() {
var port = browser.runtime.connect({ name: "tab-connection-name"});
let port = browser.runtime.connect({ name: "tab-connection-name"});
port.postMessage("tab to background port message");
port.onMessage.addListener((msg) => {
port.postMessage({ tabReceived: msg });
@ -59,8 +62,8 @@ add_task(function* () {
<h1>test tab extension page</h1>
</body>
</html>
`
}
`,
},
});
yield extension.startup();

Просмотреть файл

@ -5,38 +5,40 @@
function* testHasNoPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
function background(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "second script ran", "second script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.query({ activeWindow: true }, tabs => {
browser.tabs.executeScript({
file: "script.js",
});
// Execute a script we know we have permissions for in the
// second tab, in the hopes that it will execute after the
// first one. This has intermittent failure written all over
// it, but it's just about the best we can do until we
// support callbacks for executeScript.
browser.tabs.executeScript(tabs[1].id, {
file: "second-script.js",
});
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${function(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "second script ran", "second script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.query({ activeWindow: true }, tabs => {
browser.tabs.executeScript({
file: "script.js"
});
// Execute a script we know we have permissions for in the
// second tab, in the hopes that it will execute after the
// first one. This has intermittent failure written all over
// it, but it's just about the best we can do until we
// support callbacks for executeScript.
browser.tabs.executeScript(tabs[1].id, {
file: "second-script.js"
});
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}})(${contentSetup})`,
background: `(${background})(${contentSetup})`,
files: {
"script.js": function() {
@ -45,8 +47,8 @@ function* testHasNoPermission(params) {
"second-script.js": function() {
browser.runtime.sendMessage("second script ran");
}
}
},
},
});
yield extension.startup();
@ -68,12 +70,12 @@ add_task(function* testBadPermissions() {
info("Test no special permissions");
yield testHasNoPermission({
manifest: { "permissions": ["http://example.com/"] }
manifest: { "permissions": ["http://example.com/"] },
});
info("Test tabs permissions");
yield testHasNoPermission({
manifest: { "permissions": ["http://example.com/", "tabs"] }
manifest: { "permissions": ["http://example.com/", "tabs"] },
});
info("Test active tab, browser action, no click");
@ -97,7 +99,7 @@ add_task(function* testBadPermissions() {
resolve();
});
});
}
},
});
yield BrowserTestUtils.removeTab(tab2);

Просмотреть файл

@ -1,35 +1,39 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function* testHasPermission(params) {
let contentSetup = params.contentSetup || (() => Promise.resolve());
function background(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "script ran", "script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.executeScript({
file: "script.js",
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}
let extension = ExtensionTestUtils.loadExtension({
manifest: params.manifest,
background: `(${function(contentSetup) {
browser.runtime.onMessage.addListener((msg, sender) => {
browser.test.assertEq(msg, "script ran", "script ran");
browser.test.notifyPass("executeScript");
});
browser.test.onMessage.addListener(msg => {
browser.test.assertEq(msg, "execute-script");
browser.tabs.executeScript({
file: "script.js"
});
});
contentSetup().then(() => {
browser.test.sendMessage("ready");
});
}})(${contentSetup})`,
background: `(${background})(${contentSetup})`,
files: {
"script.js": function() {
browser.runtime.sendMessage("script ran");
}
}
},
},
});
yield extension.startup();
@ -50,17 +54,17 @@ add_task(function* testGoodPermissions() {
info("Test explicit host permission");
yield testHasPermission({
manifest: { "permissions": ["http://mochi.test/"] }
manifest: { "permissions": ["http://mochi.test/"] },
});
info("Test explicit host subdomain permission");
yield testHasPermission({
manifest: { "permissions": ["http://*.mochi.test/"] }
manifest: { "permissions": ["http://*.mochi.test/"] },
});
info("Test explicit <all_urls> permission");
yield testHasPermission({
manifest: { "permissions": ["<all_urls>"] }
manifest: { "permissions": ["<all_urls>"] },
});
info("Test activeTab permission with a browser action click");

Просмотреть файл

@ -1,3 +1,5 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
@ -9,49 +13,49 @@ add_task(function* () {
"content_scripts": [{
"matches": ["http://mochi.test/*/context_tabs_onUpdated_page.html"],
"js": ["content-script.js"],
"run_at": "document_start"
},],
"run_at": "document_start",
}],
},
background: function() {
var pageURL = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context_tabs_onUpdated_page.html";
let pageURL = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context_tabs_onUpdated_page.html";
var expectedSequence = [
let expectedSequence = [
{ status: "loading" },
{ status: "loading", url: pageURL },
{ status: "complete" }
{ status: "complete" },
];
var collectedSequence = [];
let collectedSequence = [];
browser.tabs.onUpdated.addListener(function (tabId, updatedInfo) {
browser.tabs.onUpdated.addListener(function(tabId, updatedInfo) {
collectedSequence.push(updatedInfo);
});
browser.runtime.onMessage.addListener(function () {
if (collectedSequence.length !== expectedSequence.length) {
browser.runtime.onMessage.addListener(function() {
if (collectedSequence.length !== expectedSequence.length) {
browser.test.assertEq(
JSON.stringify(expectedSequence),
JSON.stringify(collectedSequence),
"got unexpected number of updateInfo data"
);
} else {
for (let i = 0; i < expectedSequence.length; i++) {
browser.test.assertEq(
JSON.stringify(expectedSequence),
JSON.stringify(collectedSequence),
"got unexpected number of updateInfo data"
expectedSequence[i].status,
collectedSequence[i].status,
"check updatedInfo status"
);
} else {
for (var i = 0; i < expectedSequence.length; i++) {
if (expectedSequence[i].url || collectedSequence[i].url) {
browser.test.assertEq(
expectedSequence[i].status,
collectedSequence[i].status,
"check updatedInfo status"
expectedSequence[i].url,
collectedSequence[i].url,
"check updatedInfo url"
);
if (expectedSequence[i].url || collectedSequence[i].url) {
browser.test.assertEq(
expectedSequence[i].url,
collectedSequence[i].url,
"check updatedInfo url"
);
}
}
}
}
browser.test.notifyPass("tabs.onUpdated");
browser.test.notifyPass("tabs.onUpdated");
});
browser.tabs.create({ url: pageURL });
@ -64,12 +68,12 @@ add_task(function* () {
}
}, true);
`,
}
},
});
yield Promise.all([
extension.startup(),
extension.awaitFinish("tabs.onUpdated")
extension.awaitFinish("tabs.onUpdated"),
]);
yield extension.unload();
@ -84,7 +88,7 @@ function* do_test_update(background) {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: background,
@ -92,7 +96,7 @@ function* do_test_update(background) {
yield Promise.all([
yield extension.startup(),
yield extension.awaitFinish("finish")
yield extension.awaitFinish("finish"),
]);
yield extension.unload();

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config");
@ -6,16 +10,16 @@ add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
browser.tabs.query({
lastFocusedWindow: true
lastFocusedWindow: true,
}, function(tabs) {
browser.test.assertEq(tabs.length, 3, "should have three tabs");
tabs.sort(function (tab1, tab2) { return tab1.index - tab2.index; });
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
browser.test.assertEq(tabs[0].url, "about:blank", "first tab blank");
tabs.shift();
@ -53,16 +57,16 @@ add_task(function* () {
// test simple queries
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
browser.tabs.query({
url: "<all_urls>"
url: "<all_urls>",
}, function(tabs) {
browser.test.assertEq(tabs.length, 3, "should have three tabs");
tabs.sort(function (tab1, tab2) { return tab1.index - tab2.index; });
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
browser.test.assertEq(tabs[0].url, "http://example.com/", "tab 0 url correct");
browser.test.assertEq(tabs[1].url, "http://example.net/", "tab 1 url correct");
@ -80,12 +84,12 @@ add_task(function* () {
// match pattern
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
browser.tabs.query({
url: "http://*/MochiKit*"
url: "http://*/MochiKit*",
}, function(tabs) {
browser.test.assertEq(tabs.length, 1, "should have one tab");
@ -103,16 +107,16 @@ add_task(function* () {
// match array of patterns
extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
browser.tabs.query({
url: ["http://*/MochiKit*", "http://*.com/*"]
url: ["http://*/MochiKit*", "http://*.com/*"],
}, function(tabs) {
browser.test.assertEq(tabs.length, 2, "should have two tabs");
tabs.sort(function (tab1, tab2) { return tab1.index - tab2.index; });
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
browser.test.assertEq(tabs[0].url, "http://example.com/", "tab 0 url correct");
browser.test.assertEq(tabs[1].url, "http://test1.example.org/MochiKit/", "tab 1 url correct");

Просмотреть файл

@ -1,30 +1,34 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* tabsSendMessageNoExceptionOnNonExistentTab() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
chrome.tabs.create({ url: "about:robots"}, function (tab) {
var exception;
browser.tabs.create({ url: "about:robots"}, tab => {
let exception;
try {
browser.tabs.sendMessage(tab.id, "message");
browser.tabs.sendMessage(tab.id + 100, "message");
} catch(e) {
} catch (e) {
exception = e;
}
browser.test.assertEq(undefined, exception, "no exception should be raised on tabs.sendMessage to unexistent tabs");
chrome.tabs.remove(tab.id, function() {
browser.tabs.remove(tab.id, function() {
browser.test.notifyPass("tabs.sendMessage");
})
})
});
});
},
});
yield Promise.all([
extension.startup(),
extension.awaitFinish("tabs.sendMessage")
extension.awaitFinish("tabs.sendMessage"),
]);
yield extension.unload();

Просмотреть файл

@ -1,3 +1,7 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:config");
@ -6,7 +10,7 @@ add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs"]
"permissions": ["tabs"],
},
background: function() {
@ -15,7 +19,7 @@ add_task(function* () {
}, function(tabs) {
browser.test.assertEq(tabs.length, 3, "should have three tabs");
tabs.sort(function (tab1, tab2) { return tab1.index - tab2.index; });
tabs.sort((tab1, tab2) => tab1.index - tab2.index);
browser.test.assertEq(tabs[0].url, "about:blank", "first tab blank");
tabs.shift();

Просмотреть файл

@ -1,10 +1,14 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* () {
function promiseWaitForFocus(aWindow) {
return new Promise(function(aResolve, aReject) {
function promiseWaitForFocus(window) {
return new Promise(resolve => {
waitForFocus(function() {
ok(Services.focus.activeWindow === aWindow, "correct window focused");
aResolve();
}, aWindow);
ok(Services.focus.activeWindow === window, "correct window focused");
resolve();
}, window);
});
}
@ -16,7 +20,7 @@ add_task(function* () {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["windows"]
"permissions": ["windows"],
},
background: function() {
@ -35,7 +39,6 @@ add_task(function* () {
browser.windows.update(wins[0].id, {focused: true}, function() {
browser.test.sendMessage("check");
});
});
},
});

Просмотреть файл

@ -1,13 +1,17 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
/* exported CustomizableUI makeWidgetId focusWindow clickBrowserAction clickPageAction */
var {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm");
function makeWidgetId(id)
{
function makeWidgetId(id) {
id = id.toLowerCase();
return id.replace(/[^a-z0-9_-]/g, "_");
}
var focusWindow = Task.async(function* focusWindow(win)
{
var focusWindow = Task.async(function* focusWindow(win) {
let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
if (fm.activeWindow == win) {
return;
@ -39,6 +43,7 @@ function clickPageAction(extension, win = window) {
//
// Unfortunately, that doesn't happen automatically in browser chrome
// tests.
/* globals SetPageProxyState */
SetPageProxyState("valid");
let pageActionId = makeWidgetId(extension.id) + "-page-action";

Просмотреть файл

@ -1293,8 +1293,7 @@ PlacesController.prototype = {
let itemsToSelect = [];
if (PlacesUIUtils.useAsyncTransactions) {
if (ip.isTag) {
let uris = [for (item of items) if ("uri" in item)
NetUtil.newURI(item.uri)];
let uris = items.filter(item => "uri" in item).map(item => NetUtil.newURI(item.uri));
yield PlacesTransactions.Tag({ uris: uris, tag: ip.tagName }).transact();
}
else {

Просмотреть файл

@ -673,7 +673,7 @@ var PlacesOrganizer = {
}
else if (!selectedNode && aNodeList[0]) {
if (aNodeList.every(PlacesUtils.nodeIsURI)) {
let uris = [for (node of aNodeList) PlacesUtils._uri(node.uri)];
let uris = aNodeList.map(node => PlacesUtils._uri(node.uri));
detailsDeck.selectedIndex = 1;
gEditItemOverlay.initPanel({ uris
, hiddenRows: ["folderPicker",

Просмотреть файл

@ -154,7 +154,7 @@ PlacesTreeView.prototype = {
// A node is removed form the view either if it has no parent or if its
// root-ancestor is not the root node (in which case that's the node
// for which nodeRemoved was called).
let ancestors = [x for (x of PlacesUtils.nodeAncestors(aNode))];
let ancestors = Array.from(PlacesUtils.nodeAncestors(aNode));
if (ancestors.length == 0 ||
ancestors[ancestors.length - 1] != this._rootNode) {
throw new Error("Removed node passed to _getRowForNode");

Просмотреть файл

@ -401,6 +401,20 @@ var SessionStoreInternal = {
// that is being stored in _closedWindows for that tab.
_closedWindowTabs: new WeakMap(),
// A set of window data that has the potential to be saved in the _closedWindows
// array for the session. We will remove window data from this set whenever
// forgetClosedWindow is called for the window, or when session history is
// purged, so that we don't accidentally save that data after the flush has
// completed. Closed tabs use a more complicated mechanism for this particular
// problem. When forgetClosedTab is called, the browser is removed from the
// _closedTabs map, so its data is not recorded. In the purge history case,
// the closedTabs array per window is overwritten so that once the flush is
// complete, the tab would only ever add itself to an array that SessionStore
// no longer cares about. Bug 1230636 has been filed to make the tab case
// work more like the window case, which is more explicit, and easier to
// reason about.
_saveableClosedWindowData: new WeakSet(),
// A map (xul:browser -> object) that maps a browser that is switching
// remoteness via navigateAndRestore, to the loadArguments that were
// most recently passed when calling navigateAndRestore.
@ -1270,6 +1284,10 @@ var SessionStoreInternal = {
// clear this window from the list, since it has definitely been closed.
delete this._windows[aWindow.__SSi];
// This window has the potential to be saved in the _closedWindows
// array (maybeSaveClosedWindows gets the final call on that).
this._saveableClosedWindowData.add(winData);
// Now we have to figure out if this window is worth saving in the _closedWindows
// Object.
//
@ -1352,6 +1370,7 @@ var SessionStoreInternal = {
let mm = aWindow.getGroupMessageManager("browsers");
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
this._saveableClosedWindowData.delete(winData);
delete aWindow.__SSi;
},
@ -1373,7 +1392,9 @@ var SessionStoreInternal = {
* a window flush).
*/
maybeSaveClosedWindow(winData, isLastWindow) {
if (RunState.isRunning) {
// Make sure SessionStore is still running, and make sure that we
// haven't chosen to forget this window.
if (RunState.isRunning && this._saveableClosedWindowData.has(winData)) {
// Determine whether the window has any tabs worth saving.
let hasSaveableTabs = winData.tabs.some(this._shouldSaveTabState);
@ -1546,6 +1567,7 @@ var SessionStoreInternal = {
}
this._clearRestoringWindows();
this._saveableClosedWindowData.clear();
},
/**
@ -2190,7 +2212,9 @@ var SessionStoreInternal = {
}
// remove closed window from the array
let winData = this._closedWindows[aIndex];
this._closedWindows.splice(aIndex, 1);
this._saveableClosedWindowData.delete(winData);
},
getWindowValue: function ssi_getWindowValue(aWindow, aKey) {

Просмотреть файл

@ -218,3 +218,4 @@ skip-if = os == "mac"
[browser_multiple_navigateAndRestore.js]
run-if = e10s
[browser_async_window_flushing.js]
[browser_forget_async_closings.js]

Просмотреть файл

@ -0,0 +1,144 @@
"use strict";
const PAGE = "http://example.com/";
/**
* Creates a tab in the current window worth storing in the
* closedTabs array, and then closes it. Runs a synchronous
* forgetFn passed in that should cause us to forget the tab,
* and then ensures that after the tab has sent its final
* update message that we didn't accidentally store it in
* the closedTabs array.
*
* @param forgetFn (function)
* A synchronous function that should cause the tab
* to be forgotten.
* @returns Promise
*/
let forgetTabHelper = Task.async(function*(forgetFn) {
// We want to suppress all non-final updates from the browser tabs
// so as to eliminate any racy-ness with this test.
yield pushPrefs(["browser.sessionstore.debug.no_auto_updates", true]);
// Forget any previous closed tabs from other tests that may have
// run in the same session.
Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
is(ss.getClosedTabCount(window), 0,
"We should have 0 closed tabs being stored.");
// Create a tab worth remembering.
let tab = gBrowser.addTab(PAGE);
let browser = tab.linkedBrowser;
yield BrowserTestUtils.browserLoaded(browser, false, PAGE);
yield TabStateFlusher.flush(browser);
// Now close the tab, and immediately choose to forget it.
let promise = BrowserTestUtils.removeTab(tab);
// At this point, the tab will have closed, but the final update
// to SessionStore hasn't come up yet. Now do the operation that
// should cause us to forget the tab.
forgetFn();
is(ss.getClosedTabCount(window), 0, "Should have forgotten the closed tab");
// Now wait for the final update to come up.
yield promise;
is(ss.getClosedTabCount(window), 0,
"Should not have stored the forgotten closed tab");
});
/**
* Creates a new window worth storing in the closeWIndows array,
* and then closes it. Runs a synchronous forgetFn passed in that
* should cause us to forget the window, and then ensures that after
* the window has sent its final update message that we didn't
* accidentally store it in the closedWindows array.
*
* @param forgetFn (function)
* A synchronous function that should cause the window
* to be forgotten.
* @returns Promise
*/
let forgetWinHelper = Task.async(function*(forgetFn) {
// We want to suppress all non-final updates from the browser tabs
// so as to eliminate any racy-ness with this test.
yield pushPrefs(["browser.sessionstore.debug.no_auto_updates", true]);
// Forget any previous closed windows from other tests that may have
// run in the same session.
Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
is(ss.getClosedWindowCount(), 0, "We should have 0 closed windows being stored.");
let newWin = yield BrowserTestUtils.openNewBrowserWindow();
// Create a tab worth remembering.
let tab = newWin.gBrowser.selectedTab;
let browser = tab.linkedBrowser;
browser.loadURI(PAGE);
yield BrowserTestUtils.browserLoaded(browser, false, PAGE);
yield TabStateFlusher.flush(browser);
// Now close the window and immediately choose to forget it.
let windowClosed = BrowserTestUtils.windowClosed(newWin);
let domWindowClosed = BrowserTestUtils.domWindowClosed(newWin);
newWin.close();
yield domWindowClosed;
// At this point, the window will have closed and the onClose handler
// has run, but the final update to SessionStore hasn't come up yet.
// Now do the oepration that should cause us to forget the window.
forgetFn();
is(ss.getClosedWindowCount(), 0, "Should have forgotten the closed window");
// Now wait for the final update to come up.
yield windowClosed;
is(ss.getClosedWindowCount(), 0, "Should not have stored the closed window");
});
/**
* Tests that if we choose to forget a tab while waiting for its
* final flush to complete, we don't accidentally store it.
*/
add_task(function* test_forget_closed_tab() {
yield forgetTabHelper(() => {
ss.forgetClosedTab(window, 0);
});
});
/**
* Tests that if we choose to forget a tab while waiting for its
* final flush to complete, we don't accidentally store it.
*/
add_task(function* test_forget_closed_window() {
yield forgetWinHelper(() => {
ss.forgetClosedWindow(0);
});
});
/**
* Tests that if we choose to purge history while waiting for a
* final flush of a tab to complete, we don't accidentally store it.
*/
add_task(function* test_forget_purged_tab() {
yield forgetTabHelper(() => {
Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
});
});
/**
* Tests that if we choose to purge history while waiting for a
* final flush of a window to complete, we don't accidentally
* store it.
*/
add_task(function* test_forget_purged_window() {
yield forgetWinHelper(() => {
Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
});
});

Просмотреть файл

@ -29,6 +29,7 @@ describe("loop.conversation", function() {
GetLoopPref: function(prefName) {
switch (prefName) {
case "debug.sdk":
case "debug.dispatcher":
return false;
default:
return "http://fake";

Просмотреть файл

@ -56,7 +56,11 @@ describe("loop.panel", function() {
GetPluralRule: sinon.stub(),
SetLoopPref: sinon.stub(),
GetLoopPref: function(prefName) {
return "unseen";
if (prefName === "gettingStarted.seen") {
return "unseen";
}
return false;
},
GetPluralForm: function() {
return "fakeText";

Просмотреть файл

@ -50,8 +50,10 @@ describe("loop.store.RoomStore", function() {
};
},
CopyString: sinon.stub(),
GetLoopPref: function(pref) {
return pref;
GetLoopPref: function(prefName) {
if (prefName === "debug.dispatcher") {
return false;
}
},
NotifyUITour: function() {},
"Rooms:Create": sinon.stub().returns({ roomToken: "fakeToken" }),

Просмотреть файл

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.3.42
Current extension version is: 1.3.56

Просмотреть файл

@ -20,8 +20,8 @@ if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
PDFJS.version = '1.3.42';
PDFJS.build = '84a47f8';
PDFJS.version = '1.3.56';
PDFJS.build = 'e2aca38';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@ -248,7 +248,6 @@ function error(msg) {
console.log('Error: ' + msg);
console.log(backtrace());
}
UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
throw new Error(msg);
}
@ -275,22 +274,6 @@ var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
font: 'font'
};
var UnsupportedManager = PDFJS.UnsupportedManager =
(function UnsupportedManagerClosure() {
var listeners = [];
return {
listen: function (cb) {
listeners.push(cb);
},
notify: function (featureId) {
warn('Unsupported feature "' + featureId + '"');
for (var i = 0, ii = listeners.length; i < ii; i++) {
listeners[i](featureId);
}
}
};
})();
// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
// absolute URL, it will be returned as is.
function combineUrl(baseUrl, url) {
@ -1772,6 +1755,12 @@ var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
* an {Object} with the properties: {number} loaded and {number} total.
*/
this.onProgress = null;
/**
* Callback to when unsupported feature is used. The callback receives
* an {PDFJS.UNSUPPORTED_FEATURES} argument.
*/
this.onUnsupportedFeature = null;
}
PDFDocumentLoadingTask.prototype =
@ -2530,9 +2519,6 @@ var PDFWorker = (function PDFWorkerClosure() {
messageHandler.on('console_error', function (data) {
console.error.apply(console, data);
});
messageHandler.on('_unsupported_feature', function (data) {
UnsupportedManager.notify(data);
});
var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
@ -2899,6 +2885,19 @@ var WorkerTransport = (function WorkerTransportClosure() {
}
}, this);
messageHandler.on('UnsupportedFeature',
function transportUnsupportedFeature(data) {
if (this.destroyed) {
return; // Ignore any pending requests if the worker was terminated.
}
var featureId = data.featureId;
var loadingTask = this.loadingTask;
if (loadingTask.onUnsupportedFeature) {
loadingTask.onUnsupportedFeature(featureId);
}
PDFJS.UnsupportedManager.notify(featureId);
}, this);
messageHandler.on('JpegDecode', function(data) {
if (this.destroyed) {
return Promise.reject('Worker was terminated');
@ -3316,6 +3315,26 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
return InternalRenderTask;
})();
/**
* (Deprecated) Global observer of unsupported feature usages. Use
* onUnsupportedFeature callback of the {PDFDocumentLoadingTask} instance.
*/
PDFJS.UnsupportedManager = (function UnsupportedManagerClosure() {
var listeners = [];
return {
listen: function (cb) {
deprecated('Global UnsupportedManager.listen is used: ' +
' use PDFDocumentLoadingTask.onUnsupportedFeature instead');
listeners.push(cb);
},
notify: function (featureId) {
for (var i = 0, ii = listeners.length; i < ii; i++) {
listeners[i](featureId);
}
}
};
})();
var Metadata = PDFJS.Metadata = (function MetadataClosure() {
function fixMetadata(meta) {
@ -4352,6 +4371,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
composeSMask(this.ctx, this.current.activeSMask, groupCtx);
this.ctx.restore();
copyCtxState(groupCtx, this.ctx);
},
save: function CanvasGraphics_save() {
this.ctx.save();
@ -5471,7 +5491,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
paintXObject: function CanvasGraphics_paintXObject() {
UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
warn('Unsupported \'paintXObject\' command.');
},

Просмотреть файл

@ -20,8 +20,8 @@ if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
PDFJS.version = '1.3.42';
PDFJS.build = '84a47f8';
PDFJS.version = '1.3.56';
PDFJS.build = 'e2aca38';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@ -248,7 +248,6 @@ function error(msg) {
console.log('Error: ' + msg);
console.log(backtrace());
}
UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
throw new Error(msg);
}
@ -275,22 +274,6 @@ var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
font: 'font'
};
var UnsupportedManager = PDFJS.UnsupportedManager =
(function UnsupportedManagerClosure() {
var listeners = [];
return {
listen: function (cb) {
listeners.push(cb);
},
notify: function (featureId) {
warn('Unsupported feature "' + featureId + '"');
for (var i = 0, ii = listeners.length; i < ii; i++) {
listeners[i](featureId);
}
}
};
})();
// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
// absolute URL, it will be returned as is.
function combineUrl(baseUrl, url) {
@ -1876,7 +1859,6 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
})();
// TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
var BasePdfManager = (function BasePdfManagerClosure() {
function BasePdfManager() {
throw new Error('Cannot initialize BaseManagerManager');
@ -1903,7 +1885,7 @@ var BasePdfManager = (function BasePdfManagerClosure() {
return this.ensure(this.pdfDocument.catalog, prop, args);
},
getPage: function BasePdfManager_pagePage(pageIndex) {
getPage: function BasePdfManager_getPage(pageIndex) {
return this.pdfDocument.getPage(pageIndex);
},
@ -1915,7 +1897,7 @@ var BasePdfManager = (function BasePdfManagerClosure() {
return new NotImplementedException();
},
requestRange: function BasePdfManager_ensure(begin, end) {
requestRange: function BasePdfManager_requestRange(begin, end) {
return new NotImplementedException();
},
@ -1956,45 +1938,40 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
this._loadedStreamCapability.resolve(stream);
}
LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
LocalPdfManager.prototype.constructor = LocalPdfManager;
LocalPdfManager.prototype.ensure =
function LocalPdfManager_ensure(obj, prop, args) {
return new Promise(function (resolve, reject) {
try {
var value = obj[prop];
var result;
if (typeof value === 'function') {
result = value.apply(obj, args);
} else {
result = value;
Util.inherit(LocalPdfManager, BasePdfManager, {
ensure: function LocalPdfManager_ensure(obj, prop, args) {
return new Promise(function (resolve, reject) {
try {
var value = obj[prop];
var result;
if (typeof value === 'function') {
result = value.apply(obj, args);
} else {
result = value;
}
resolve(result);
} catch (e) {
reject(e);
}
resolve(result);
} catch (e) {
reject(e);
}
});
};
});
},
LocalPdfManager.prototype.requestRange =
function LocalPdfManager_requestRange(begin, end) {
return Promise.resolve();
};
requestRange: function LocalPdfManager_requestRange(begin, end) {
return Promise.resolve();
},
LocalPdfManager.prototype.requestLoadedStream =
function LocalPdfManager_requestLoadedStream() {
};
requestLoadedStream: function LocalPdfManager_requestLoadedStream() {
return;
},
LocalPdfManager.prototype.onLoadedStream =
function LocalPdfManager_getLoadedStream() {
return this._loadedStreamCapability.promise;
};
onLoadedStream: function LocalPdfManager_onLoadedStream() {
return this._loadedStreamCapability.promise;
},
LocalPdfManager.prototype.terminate =
function LocalPdfManager_terminate() {
return;
};
terminate: function LocalPdfManager_terminate() {
return;
}
});
return LocalPdfManager;
})();
@ -2015,67 +1992,60 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
this.streamManager = new ChunkedStreamManager(args.length,
args.rangeChunkSize,
args.url, params);
this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
args.password);
args.password);
}
NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
NetworkPdfManager.prototype.constructor = NetworkPdfManager;
Util.inherit(NetworkPdfManager, BasePdfManager, {
ensure: function NetworkPdfManager_ensure(obj, prop, args) {
var pdfManager = this;
NetworkPdfManager.prototype.ensure =
function NetworkPdfManager_ensure(obj, prop, args) {
var pdfManager = this;
return new Promise(function (resolve, reject) {
function ensureHelper() {
try {
var result;
var value = obj[prop];
if (typeof value === 'function') {
result = value.apply(obj, args);
} else {
result = value;
return new Promise(function (resolve, reject) {
function ensureHelper() {
try {
var result;
var value = obj[prop];
if (typeof value === 'function') {
result = value.apply(obj, args);
} else {
result = value;
}
resolve(result);
} catch(e) {
if (!(e instanceof MissingDataException)) {
reject(e);
return;
}
pdfManager.streamManager.requestRange(e.begin, e.end).
then(ensureHelper, reject);
}
resolve(result);
} catch(e) {
if (!(e instanceof MissingDataException)) {
reject(e);
return;
}
pdfManager.streamManager.requestRange(e.begin, e.end).
then(ensureHelper, reject);
}
}
ensureHelper();
});
};
ensureHelper();
});
},
NetworkPdfManager.prototype.requestRange =
function NetworkPdfManager_requestRange(begin, end) {
return this.streamManager.requestRange(begin, end);
};
requestRange: function NetworkPdfManager_requestRange(begin, end) {
return this.streamManager.requestRange(begin, end);
},
NetworkPdfManager.prototype.requestLoadedStream =
function NetworkPdfManager_requestLoadedStream() {
this.streamManager.requestAllChunks();
};
requestLoadedStream: function NetworkPdfManager_requestLoadedStream() {
this.streamManager.requestAllChunks();
},
NetworkPdfManager.prototype.sendProgressiveData =
function NetworkPdfManager_sendProgressiveData(chunk) {
this.streamManager.onReceiveData({ chunk: chunk });
};
sendProgressiveData:
function NetworkPdfManager_sendProgressiveData(chunk) {
this.streamManager.onReceiveData({ chunk: chunk });
},
NetworkPdfManager.prototype.onLoadedStream =
function NetworkPdfManager_getLoadedStream() {
return this.streamManager.onLoadedStream();
};
onLoadedStream: function NetworkPdfManager_onLoadedStream() {
return this.streamManager.onLoadedStream();
},
NetworkPdfManager.prototype.terminate =
function NetworkPdfManager_terminate() {
this.streamManager.abort();
};
terminate: function NetworkPdfManager_terminate() {
this.streamManager.abort();
}
});
return NetworkPdfManager;
})();
@ -2270,7 +2240,7 @@ var Page = (function PageClosure() {
}
var annotationsReadyPromise = Annotation.appendToOperatorList(
annotations, pageOpList, pdfManager, partialEvaluator, task, intent);
annotations, pageOpList, partialEvaluator, task, intent);
return annotationsReadyPromise.then(function () {
pageOpList.flush(true);
return pageOpList;
@ -4543,25 +4513,22 @@ var Annotation = (function AnnotationClosure() {
function Annotation(params) {
var dict = params.dict;
var data = this.data = {};
data.subtype = dict.get('Subtype').name;
this.setFlags(dict.get('F'));
data.annotationFlags = this.flags;
this.setRectangle(dict.get('Rect'));
data.rect = this.rectangle;
this.setColor(dict.get('C'));
data.color = this.color;
this.borderStyle = data.borderStyle = new AnnotationBorderStyle();
this.setBorderStyle(dict);
this.appearance = getDefaultAppearance(dict);
data.hasAppearance = !!this.appearance;
data.id = params.ref.num;
// Expose public properties using a data object.
this.data = {};
this.data.id = params.ref.num;
this.data.subtype = dict.get('Subtype').name;
this.data.annotationFlags = this.flags;
this.data.rect = this.rectangle;
this.data.color = this.color;
this.data.borderStyle = this.borderStyle;
this.data.hasAppearance = !!this.appearance;
}
Annotation.prototype = {
@ -4688,6 +4655,7 @@ var Annotation = (function AnnotationClosure() {
* @param {Dict} borderStyle - The border style dictionary
*/
setBorderStyle: function Annotation_setBorderStyle(borderStyle) {
this.borderStyle = new AnnotationBorderStyle();
if (!isDict(borderStyle)) {
return;
}
@ -4740,13 +4708,11 @@ var Annotation = (function AnnotationClosure() {
},
getOperatorList: function Annotation_getOperatorList(evaluator, task) {
if (!this.appearance) {
return Promise.resolve(new OperatorList());
}
var data = this.data;
var appearanceDict = this.appearance.dict;
var resourcesPromise = this.loadResources([
'ExtGState',
@ -4778,33 +4744,22 @@ var Annotation = (function AnnotationClosure() {
};
Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
annotations, opList, pdfManager, partialEvaluator, task, intent) {
function reject(e) {
annotationsReadyCapability.reject(e);
}
var annotationsReadyCapability = createPromiseCapability();
annotations, opList, partialEvaluator, task, intent) {
var annotationPromises = [];
for (var i = 0, n = annotations.length; i < n; ++i) {
if (intent === 'display' && annotations[i].viewable ||
intent === 'print' && annotations[i].printable) {
if ((intent === 'display' && annotations[i].viewable) ||
(intent === 'print' && annotations[i].printable)) {
annotationPromises.push(
annotations[i].getOperatorList(partialEvaluator, task));
}
}
Promise.all(annotationPromises).then(function(datas) {
return Promise.all(annotationPromises).then(function(operatorLists) {
opList.addOp(OPS.beginAnnotations, []);
for (var i = 0, n = datas.length; i < n; ++i) {
var annotOpList = datas[i];
opList.addOpList(annotOpList);
for (var i = 0, n = operatorLists.length; i < n; ++i) {
opList.addOpList(operatorLists[i]);
}
opList.addOp(OPS.endAnnotations, []);
annotationsReadyCapability.resolve();
}, reject);
return annotationsReadyCapability.promise;
});
};
return Annotation;
@ -4949,7 +4904,6 @@ var AnnotationBorderStyle = (function AnnotationBorderStyleClosure() {
})();
var WidgetAnnotation = (function WidgetAnnotationClosure() {
function WidgetAnnotation(params) {
Annotation.call(this, params);
@ -5073,7 +5027,7 @@ var TextAnnotation = (function TextAnnotationClosure() {
}
}
Util.inherit(TextAnnotation, Annotation, { });
Util.inherit(TextAnnotation, Annotation, {});
return TextAnnotation;
})();
@ -5149,7 +5103,7 @@ var LinkAnnotation = (function LinkAnnotationClosure() {
return url;
}
Util.inherit(LinkAnnotation, Annotation, { });
Util.inherit(LinkAnnotation, Annotation, {});
return LinkAnnotation;
})();
@ -9567,7 +9521,7 @@ var Pattern = (function PatternClosure() {
};
Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
res) {
res, handler) {
var dict = isStream(shading) ? shading.dict : shading;
var type = dict.get('ShadingType');
@ -9590,7 +9544,8 @@ var Pattern = (function PatternClosure() {
if (ex instanceof MissingDataException) {
throw ex;
}
UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
handler.send('UnsupportedFeature',
{featureId: UNSUPPORTED_FEATURES.shadingPattern});
warn(ex);
return new Shadings.Dummy();
}
@ -10628,6 +10583,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
then(function () {
return translated;
}, function (reason) {
// Error in the font data -- sending unsupported feature notification.
self.handler.send('UnsupportedFeature',
{featureId: UNSUPPORTED_FEATURES.font});
return new TranslatedFont('g_font_error',
new ErrorFont('Type3 font load error: ' + reason), translated.font);
});
@ -10852,6 +10810,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
translatedPromise = Promise.reject(e);
}
var self = this;
translatedPromise.then(function (translatedFont) {
if (translatedFont.fontType !== undefined) {
var xrefFontStats = xref.stats.fontTypes;
@ -10862,7 +10821,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
translatedFont, font));
}, function (reason) {
// TODO fontCapability.reject?
UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
// Error in the font data -- sending unsupported feature notification.
self.handler.send('UnsupportedFeature',
{featureId: UNSUPPORTED_FEATURES.font});
try {
// error, but it's still nice to have font type reported
@ -10915,7 +10876,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} else if (typeNum === SHADING_PATTERN) {
var shading = dict.get('Shading');
var matrix = dict.get('Matrix');
pattern = Pattern.parseShading(shading, matrix, xref, resources);
pattern = Pattern.parseShading(shading, matrix, xref, resources,
this.handler);
operatorList.addOp(fn, pattern.getIR());
return Promise.resolve();
} else {
@ -11152,7 +11114,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var shadingFill = Pattern.parseShading(shading, null, xref,
resources);
resources, self.handler);
var patternIR = shadingFill.getIR();
args = [patternIR];
fn = OPS.shadingFill;
@ -16929,11 +16891,15 @@ var Font = (function FontClosure() {
};
}
function getRanges(glyphs) {
function getRanges(glyphs, numGlyphs) {
// Array.sort() sorts by characters, not numerically, so convert to an
// array of characters.
var codes = [];
for (var charCode in glyphs) {
// Remove an invalid glyph ID mappings to make OTS happy.
if (glyphs[charCode] >= numGlyphs) {
continue;
}
codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode] });
}
codes.sort(function fontGetRangesSort(a, b) {
@ -16962,8 +16928,8 @@ var Font = (function FontClosure() {
return ranges;
}
function createCmapTable(glyphs) {
var ranges = getRanges(glyphs);
function createCmapTable(glyphs, numGlyphs) {
var ranges = getRanges(glyphs, numGlyphs);
var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
var cmap = '\x00\x00' + // version
string16(numTables) + // numTables
@ -18466,7 +18432,7 @@ var Font = (function FontClosure() {
this.toFontChar = newMapping.toFontChar;
tables.cmap = {
tag: 'cmap',
data: createCmapTable(newMapping.charCodeToGlyphId)
data: createCmapTable(newMapping.charCodeToGlyphId, numGlyphs)
};
if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
@ -18604,7 +18570,8 @@ var Font = (function FontClosure() {
builder.addTable('OS/2', createOS2Table(properties,
newMapping.charCodeToGlyphId));
// Character to glyphs mapping
builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId));
builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId,
numGlyphs));
// Font header
builder.addTable('head',
'\x00\x01\x00\x00' + // Version number
@ -31007,17 +30974,32 @@ var Lexer = (function LexerClosure() {
return strBuf.join('');
},
getName: function Lexer_getName() {
var ch;
var ch, previousCh;
var strBuf = this.strBuf;
strBuf.length = 0;
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
if (ch === 0x23) { // '#'
ch = this.nextChar();
if (specialChars[ch]) {
warn('Lexer_getName: ' +
'NUMBER SIGN (#) should be followed by a hexadecimal number.');
strBuf.push('#');
break;
}
var x = toHexDigit(ch);
if (x !== -1) {
var x2 = toHexDigit(this.nextChar());
previousCh = ch;
ch = this.nextChar();
var x2 = toHexDigit(ch);
if (x2 === -1) {
error('Illegal digit in hex char in name: ' + x2);
warn('Lexer_getName: Illegal digit (' +
String.fromCharCode(ch) +') in hexadecimal number.');
strBuf.push('#', String.fromCharCode(previousCh));
if (specialChars[ch]) {
break;
}
strBuf.push(String.fromCharCode(ch));
continue;
}
strBuf.push(String.fromCharCode((x << 4) | x2));
} else {
@ -34351,6 +34333,11 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
return; // ignoring errors from the terminated thread
}
// For compatibility with older behavior, generating unknown
// unsupported feature notification on errors.
handler.send('UnsupportedFeature',
{featureId: UNSUPPORTED_FEATURES.unknown});
var minimumStackMessage =
'worker.js: while trying to getPage() and getOperatorList()';
@ -34485,15 +34472,6 @@ if (typeof window === 'undefined') {
globalScope.console = workerConsole;
}
// Listen for unsupported features so we can pass them on to the main thread.
PDFJS.UnsupportedManager.listen(function (msg) {
globalScope.postMessage({
targetName: 'main',
action: '_unsupported_feature',
data: msg
});
});
var handler = new MessageHandler('worker', 'main', this);
WorkerMessageHandler.setup(handler, this);
}

Просмотреть файл

@ -21,6 +21,7 @@
bottom: 0;
overflow: hidden;
opacity: 0.2;
line-height: 1.0;
}
.textLayer > div {

Просмотреть файл

@ -6513,6 +6513,9 @@ var PDFViewerApplication = {
self.progress(progressData.loaded / progressData.total);
};
// Listen for unsupported features to trigger the fallback UI.
loadingTask.onUnsupportedFeature = this.fallback.bind(this);
var result = loadingTask.promise.then(
function getDocumentCallback(pdfDocument) {
self.load(pdfDocument, scale);
@ -7248,10 +7251,6 @@ function webViewerInitialized() {
document.getElementById('viewFind').classList.add('hidden');
}
// Listen for unsupported features to trigger the fallback UI.
PDFJS.UnsupportedManager.listen(
PDFViewerApplication.fallback.bind(PDFViewerApplication));
// Suppress context menus for some controls
document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler;

Просмотреть файл

@ -33,3 +33,4 @@ tampering with your connection.</b>">
<!ENTITY certerror.expert.contentPara2 "Don't add an exception unless
you know there's a good reason why this site doesn't use trusted identification.">
<!ENTITY certerror.addException.label "Add Exception…">
<!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">

Просмотреть файл

@ -801,6 +801,13 @@ unmuteTab.accesskey = M
weakCryptoOverriding.message = %S recommends that you don't enter your password, credit card and other personal information on this website.
revokeOverride.label = Don't Trust This Website
revokeOverride.accesskey = D
# LOCALIZATION NOTE (certErrorDetails.label): This is a text string that
# appears in the about:certerror page, so that the user can copy and send it to
# the server administrators for troubleshooting. %1$S is the visited URL, %2$S
# is the error message, %3$S is true or false, depending on whether the server
# supports HSTS, %4$S is true or false, depending on whether the server
# supports HPKP, %5$S is the certificate chain in PEM format.
certErrorDetails.label = %1$S\r\n\r\n%2$S\r\n\r\nHTTP Strict Transport Security: %3$S\r\nHTTP Public Key Pinning: %4$S\r\n\r\nCertificate chain:\r\n\r\n%5$S
# LOCALIZATION NOTE (tabgroups.migration.anonGroup):
# %S is the group number/ID

Просмотреть файл

@ -215,14 +215,14 @@ functionality specific to firefox. -->
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
<!ENTITY sslv3Used.title "Unable to Connect Securely">
<!-- LOCALIZATION NOTE (sslv3Used.longDesc) - Do not translate
"ssl_error_unsupported_version". -->
<!ENTITY sslv3Used.longDesc "Advanced info: ssl_error_unsupported_version">
<!-- LOCALIZATION NOTE (sslv3Used.longDesc2) - Do not translate
"SSL_ERROR_UNSUPPORTED_VERSION". -->
<!ENTITY sslv3Used.longDesc2 "Advanced info: SSL_ERROR_UNSUPPORTED_VERSION">
<!ENTITY weakCryptoUsed.title "Your connection is not secure">
<!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc) - Do not translate
"ssl_error_no_cypher_overlap". -->
<!ENTITY weakCryptoUsed.longDesc "Advanced info: ssl_error_no_cypher_overlap">
<!-- LOCALIZATION NOTE (weakCryptoUsed.longDesc2) - Do not translate
"SSL_ERROR_NO_CYPHER_OVERLAP". -->
<!ENTITY weakCryptoUsed.longDesc2 "Advanced info: SSL_ERROR_NO_CYPHER_OVERLAP">
<!ENTITY weakCryptoAdvanced.title "Advanced">
<!ENTITY weakCryptoAdvanced.longDesc "<span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe.">
<!ENTITY weakCryptoAdvanced.override "(Not secure) Try loading <span class='hostname'></span> using outdated security">

Просмотреть файл

@ -53,6 +53,27 @@ body {
flex: 1;
}
#certificateErrorDebugInformation {
display: none;
background-color: var(--in-content-box-background-hover) !important;
border-top: 1px solid var(--in-content-border-color);
position: absolute;
left: 0%;
top: 100%;
width: 65%;
padding: 1em 17.5%;
}
#certificateErrorText {
font-family: monospace;
white-space: pre-wrap;
padding: 1em 0;
}
#errorCode {
white-space: nowrap;
}
#returnButton {
background-color: var(--in-content-primary-button-background);
border: none;

Просмотреть файл

@ -173,3 +173,9 @@ span#hostname {
#automaticallyReportInFuture {
cursor: pointer;
}
#errorCode {
color: var(--in-content-page-color);
cursor: text;
text-decoration: none;
}

Просмотреть файл

@ -16,6 +16,7 @@
<item name="android:windowContentOverlay">@null</item>
<item name="android:actionBarStyle">@style/GeckoActionBar</item>
<!-- TODO (bug 1220863): Once we extend AppCompatActivity, set actionBarStyle. -->
<item name="android:alertDialogTheme">@style/GeckoAlertDialog</item>
</style>
<style name="GeckoPreferencesBase" parent="Gecko">
@ -25,6 +26,10 @@
<item name="android:actionBarTheme">@style/ActionBarThemeGeckoPreferences</item>
</style>
<style name="GeckoAlertDialog" parent="@android:style/Theme.Material.Light.Dialog.Alert">
<item name="android:colorAccent">@color/fennec_ui_orange</item>
</style>
<style name="ActionBar.FxAccountStatusActivity" parent="@android:style/Widget.Material.ActionBar.Solid">
<item name="android:displayOptions">homeAsUp|showTitle</item>
<item name="android:titleTextStyle">@style/ActionBarTitleTextStyle</item>

Просмотреть файл

@ -292,7 +292,8 @@ certErrorExpiredNow=The certificate expired on %1$S. The current time is %2$S.
# LOCALIZATION NOTE (certErrorNotYetValidNow): Do not translate %1$S (date+time certificate will become valid) or %2$S (current date+time)
certErrorNotYetValidNow=The certificate will not be valid until %1$S. The current time is %2$S.
certErrorCodePrefix=(Error code: %S)
# LOCALIZATION NOTE (certErrorCodePrefix2): Do not translate <a id="errorCode" title="%1$S">%1$S</a>
certErrorCodePrefix2=Error code: <a id="errorCode" title="%1$S">%1$S</a>
CertInfoIssuedFor=Issued to:
CertInfoIssuedBy=Issued by:

Просмотреть файл

@ -882,7 +882,6 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport,
if (codeName)
{
nsCString error_id(codeName);
ToLowerCase(error_id);
NS_ConvertASCIItoUTF16 idU(error_id);
const char16_t *params[1];
@ -890,7 +889,7 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport,
nsString formattedString;
nsresult rv;
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2",
params, 1,
formattedString);
if (NS_SUCCEEDED(rv)) {

Просмотреть файл

@ -78,14 +78,13 @@ nsNSSErrors::getErrorMessageFromCode(PRErrorCode err,
{
nsresult rv;
nsCString error_id(nss_error_id_str);
ToLowerCase(error_id);
NS_ConvertASCIItoUTF16 idU(error_id);
const char16_t *params[1];
params[0] = idU.get();
nsString formattedString;
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2",
params, 1,
formattedString);
if (NS_SUCCEEDED(rv)) {

5
storage/.eslintrc Normal file
Просмотреть файл

@ -0,0 +1,5 @@
{
"extends": [
"../toolkit/.eslintrc"
]
}

Просмотреть файл

@ -16,6 +16,8 @@ do_get_profile();
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var gDBConn = null;
function getTestDB()
{
var db = dirSvc.get("ProfD", Ci.nsIFile);
@ -53,7 +55,7 @@ function cleanup()
print("*** Storage Tests: Trying to remove file!");
var dbFile = getTestDB();
if (dbFile.exists())
try { dbFile.remove(false); } catch(e) { /* stupid windows box */ }
try { dbFile.remove(false); } catch (e) { /* stupid windows box */ }
}
/**
@ -66,7 +68,7 @@ function asyncCleanup()
// close the connection
print("*** Storage Tests: Trying to asyncClose!");
getOpenedDatabase().asyncClose(function() { closed = true; });
getOpenedDatabase().asyncClose(function () { closed = true; });
let curThread = Components.classes["@mozilla.org/thread-manager;1"]
.getService().currentThread;
@ -81,7 +83,7 @@ function asyncCleanup()
print("*** Storage Tests: Trying to remove file!");
var dbFile = getTestDB();
if (dbFile.exists())
try { dbFile.remove(false); } catch(e) { /* stupid windows box */ }
try { dbFile.remove(false); } catch (e) { /* stupid windows box */ }
}
function getService()
@ -89,8 +91,6 @@ function getService()
return Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
}
var gDBConn = null;
/**
* Get a connection to the test database. Creates and caches the connection
* if necessary, otherwise reuses the existing cached connection. This
@ -169,7 +169,7 @@ function expectError(aErrorCode, aFunction)
try {
aFunction();
}
catch(e) {
catch (e) {
if (e.result != aErrorCode) {
do_throw("Got an exception, but the result code was not the expected " +
"one. Expected " + aErrorCode + ", got " + e.result);
@ -208,7 +208,7 @@ function verifyQuery(aSQLString, aBind, aResults)
do_check_eq(stmt.VALUE_TYPE_NULL, valType);
do_check_true(stmt.getIsNull(iCol));
}
else if (typeof(expectedVal) == "number") {
else if (typeof expectedVal == "number") {
if (Math.floor(expectedVal) == expectedVal) {
do_check_eq(stmt.VALUE_TYPE_INTEGER, valType);
do_check_eq(expectedVal, stmt.getInt32(iCol));
@ -218,7 +218,7 @@ function verifyQuery(aSQLString, aBind, aResults)
do_check_eq(expectedVal, stmt.getDouble(iCol));
}
}
else if (typeof(expectedVal) == "string") {
else if (typeof expectedVal == "string") {
do_check_eq(stmt.VALUE_TYPE_TEXT, valType);
do_check_eq(expectedVal, stmt.getUTF8String(iCol));
}

Просмотреть файл

@ -1,6 +1,3 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// Testcase for bug 365166 - crash [@ strlen] calling
// mozIStorageStatement::getColumnName of a statement created with
// "PRAGMA user_version" or "PRAGMA schema_version"
@ -16,7 +13,7 @@ function run_test() {
var file = getTestDB();
var storageService = Components.classes["@mozilla.org/storage/service;1"].
getService(Components.interfaces.mozIStorageService);
var conn = storageService.openDatabase(file);
var conn = storageService.openDatabase(file);
var statement = conn.createStatement(sql);
try {
// This shouldn't crash:

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Testcase for bug 393952: crash when I try to VACUUM and one of the tables
// has a UNIQUE text column. StorageUnicodeFunctions::likeFunction()
// has a UNIQUE text column. StorageUnicodeFunctions::likeFunction()
// needs to handle null aArgv[0] and aArgv[1]
function setup()
@ -32,7 +32,7 @@ function run_test()
for (var i = 0; i < tests.length; i++)
tests[i]();
cleanup();
}

Просмотреть файл

@ -2,48 +2,45 @@
* 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/. */
function setup()
{
getOpenedDatabase().createTable("t1", "x TEXT");
function setup() {
getOpenedDatabase().createTable("t1", "x TEXT");
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('/mozilla.org/20070129_1/Europe/Berlin')");
stmt.execute();
stmt.finalize();
var stmt = createStatement("INSERT INTO t1 (x) VALUES ('/mozilla.org/20070129_1/Europe/Berlin')");
stmt.execute();
stmt.finalize();
}
function test_bug429521()
{
var stmt = createStatement(
"SELECT DISTINCT(zone) FROM ("+
"SELECT x AS zone FROM t1 WHERE x LIKE '/mozilla.org%'" +
");");
function test_bug429521() {
var stmt = createStatement(
"SELECT DISTINCT(zone) FROM (" +
"SELECT x AS zone FROM t1 WHERE x LIKE '/mozilla.org%'" +
");");
print("*** test_bug429521: started");
print("*** test_bug429521: started");
try {
while (stmt.executeStep()) {
print("*** test_bug429521: step() Read wrapper.row.zone");
try {
while (stmt.executeStep()) {
print("*** test_bug429521: step() Read wrapper.row.zone");
// BUG: the print commands after the following statement
// are never executed. Script stops immediately.
var tzId = stmt.row.zone;
// BUG: the print commands after the following statement
// are never executed. Script stops immediately.
var tzId = stmt.row.zone;
print("*** test_bug429521: step() Read wrapper.row.zone finished");
}
} catch (e) {
print("*** test_bug429521: " + e);
print("*** test_bug429521: step() Read wrapper.row.zone finished");
}
} catch (e) {
print("*** test_bug429521: " + e);
}
print("*** test_bug429521: finished");
print("*** test_bug429521: finished");
stmt.finalize();
stmt.finalize();
}
function run_test()
{
function run_test() {
setup();
test_bug429521();
cleanup();
}

Просмотреть файл

@ -3,49 +3,49 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function setup() {
// Create the table
getOpenedDatabase().createTable("test_bug444233",
"id INTEGER PRIMARY KEY, value TEXT");
// Create the table
getOpenedDatabase().createTable("test_bug444233",
"id INTEGER PRIMARY KEY, value TEXT");
// Insert dummy data, using wrapper methods
var stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
stmt.params.value = "value1"
stmt.execute();
stmt.finalize();
stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
stmt.params.value = "value2"
stmt.execute();
stmt.finalize();
// Insert dummy data, using wrapper methods
var stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
stmt.params.value = "value1";
stmt.execute();
stmt.finalize();
stmt = createStatement("INSERT INTO test_bug444233 (value) VALUES (:value)");
stmt.params.value = "value2";
stmt.execute();
stmt.finalize();
}
function test_bug444233() {
print("*** test_bug444233: started");
// Check that there are 2 results
var stmt = createStatement("SELECT COUNT(*) AS number FROM test_bug444233");
do_check_true(stmt.executeStep());
do_check_eq(2, stmt.row.number);
stmt.reset();
stmt.finalize();
print("*** test_bug444233: started");
print("*** test_bug444233: doing delete");
// Now try to delete using IN
// Cheating since we know ids are 1,2
try {
var ids = [1, 2];
stmt = createStatement("DELETE FROM test_bug444233 WHERE id IN (:ids)");
stmt.params.ids = ids;
} catch (e) {
print("*** test_bug444233: successfully caught exception");
}
stmt.finalize();
// Check that there are 2 results
var stmt = createStatement("SELECT COUNT(*) AS number FROM test_bug444233");
do_check_true(stmt.executeStep());
do_check_eq(2, stmt.row.number);
stmt.reset();
stmt.finalize();
print("*** test_bug444233: doing delete");
// Now try to delete using IN
// Cheating since we know ids are 1,2
try {
var ids = [1, 2];
stmt = createStatement("DELETE FROM test_bug444233 WHERE id IN (:ids)");
stmt.params.ids = ids;
} catch (e) {
print("*** test_bug444233: successfully caught exception");
}
stmt.finalize();
}
function run_test() {
setup();
test_bug444233();
cleanup();
setup();
test_bug444233();
cleanup();
}

Просмотреть файл

@ -1,34 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This file tests SQLITE_FCNTL_CHUNK_SIZE behaves as expected
function run_sql(d, sql) {
var stmt = d.createStatement(sql)
stmt.execute()
var stmt = d.createStatement(sql);
stmt.execute();
stmt.finalize();
}
function new_file(name)
{
function new_file(name) {
var file = dirSvc.get("ProfD", Ci.nsIFile);
file.append(name);
return file;
}
function get_size(name) {
return new_file(name).fileSize
return new_file(name).fileSize;
}
function run_test()
{
function run_test() {
const filename = "chunked.sqlite";
const CHUNK_SIZE = 512 * 1024;
var d = getDatabase(new_file(filename));
try {
d.setGrowthIncrement(CHUNK_SIZE, "");
} catch (e if e.result == Cr.NS_ERROR_FILE_TOO_BIG) {
} catch (e) {
if (e.result != Cr.NS_ERROR_FILE_TOO_BIG) {
throw e;
}
print("Too little free space to set CHUNK_SIZE!");
return;
}
@ -39,17 +36,17 @@ function run_test()
* While writing ensure that the file size growth in chunksize set above.
*/
const str1024 = new Array(1024).join("T");
for(var i = 0; i < 32; i++) {
for (var i = 0; i < 32; i++) {
run_sql(d, "INSERT INTO bloat VALUES('" + str1024 + "')");
var size = get_size(filename)
var size = get_size(filename);
// Must not grow in small increments.
do_check_true(size == orig_size || size >= CHUNK_SIZE);
}
/* In addition to growing in chunk-size increments, the db
* should shrink in chunk-size increments too.
*/
run_sql(d, "DELETE FROM bloat")
run_sql(d, "VACUUM")
do_check_true(get_size(filename) >= CHUNK_SIZE)
run_sql(d, "DELETE FROM bloat");
run_sql(d, "VACUUM");
do_check_true(get_size(filename) >= CHUNK_SIZE);
}

Просмотреть файл

@ -12,8 +12,7 @@ const TEXT = "this is test text";
const REAL = 3.23;
const BLOB = [1, 2];
function test_create_and_add()
{
add_test(function test_create_and_add() {
getOpenedDatabase().executeSimpleSQL(
"CREATE TABLE test (" +
"id INTEGER, " +
@ -42,19 +41,17 @@ function test_create_and_add()
stmts[1].bindBlobByIndex(3, BLOB, BLOB.length);
getOpenedDatabase().executeAsync(stmts, stmts.length, {
handleResult: function(aResultSet)
{
dump("handleResult("+aResultSet+")\n");
handleResult: function (aResultSet) {
dump("handleResult(" + aResultSet + ")\n");
do_throw("unexpected results obtained!");
},
handleError: function(aError)
handleError: function (aError)
{
dump("handleError("+aError.result+")\n");
dump("handleError(" + aError.result + ")\n");
do_throw("unexpected error!");
},
handleCompletion: function(aReason)
{
dump("handleCompletion("+aReason+")\n");
handleCompletion: function (aReason) {
dump("handleCompletion(" + aReason + ")\n");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
// Check that the result is in the table
@ -96,10 +93,9 @@ function test_create_and_add()
});
stmts[0].finalize();
stmts[1].finalize();
}
});
function test_multiple_bindings_on_statements()
{
add_test(function test_multiple_bindings_on_statements() {
// This tests to make sure that we pass all the statements multiply bound
// parameters when we call executeAsync.
const AMOUNT_TO_ADD = 5;
@ -145,18 +141,15 @@ function test_multiple_bindings_on_statements()
// Execute asynchronously.
getOpenedDatabase().executeAsync(stmts, stmts.length, {
handleResult: function(aResultSet)
{
handleResult: function (aResultSet) {
do_throw("Unexpected call to handleResult!");
},
handleError: function(aError)
{
handleError: function (aError) {
print("Error code " + aError.result + " with message '" +
aError.message + "' returned.");
do_throw("Unexpected error!");
},
handleCompletion: function(aReason)
{
handleCompletion: function (aReason) {
print("handleCompletion(" + aReason +
") for test_multiple_bindings_on_statements");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
@ -176,24 +169,19 @@ function test_multiple_bindings_on_statements()
}
});
stmts.forEach(stmt => stmt.finalize());
}
});
function test_asyncClose_does_not_complete_before_statements()
{
add_test(function test_asyncClose_does_not_complete_before_statements() {
let stmt = createStatement("SELECT * FROM sqlite_master");
let executed = false;
stmt.executeAsync({
handleResult: function(aResultSet)
{
},
handleError: function(aError)
{
handleResult(aResultSet) {},
handleError(aError) {
print("Error code " + aError.result + " with message '" +
aError.message + "' returned.");
do_throw("Unexpected error!");
},
handleCompletion: function(aReason)
{
handleCompletion(aReason) {
print("handleCompletion(" + aReason +
") for test_asyncClose_does_not_complete_before_statements");
do_check_eq(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason);
@ -202,7 +190,7 @@ function test_asyncClose_does_not_complete_before_statements()
});
stmt.finalize();
getOpenedDatabase().asyncClose(function() {
getOpenedDatabase().asyncClose(function () {
// Ensure that the statement executed to completion.
do_check_true(executed);
@ -210,19 +198,17 @@ function test_asyncClose_does_not_complete_before_statements()
gDBConn = null;
run_next_test();
});
}
});
function test_asyncClose_does_not_throw_no_callback()
{
add_test(function test_asyncClose_does_not_throw_no_callback() {
getOpenedDatabase().asyncClose();
// Reset gDBConn so that later tests will get a new connection object.
gDBConn = null;
run_next_test();
}
});
function test_double_asyncClose_throws()
{
add_test(function test_double_asyncClose_throws() {
let conn = getOpenedDatabase();
conn.asyncClose();
try {
@ -230,31 +216,20 @@ function test_double_asyncClose_throws()
do_throw("should have thrown");
// There is a small race condition here, which can cause either of
// Cr.NS_ERROR_NOT_INITIALIZED or Cr.NS_ERROR_UNEXPECTED to be thrown.
} catch (e if "result" in e && e.result == Cr.NS_ERROR_NOT_INITIALIZED) {
do_print("NS_ERROR_NOT_INITIALIZED");
} catch (e if "result" in e && e.result == Cr.NS_ERROR_UNEXPECTED) {
do_print("NS_ERROR_UNEXPECTED");
} catch (e) {
if ("result" in e && e.result == Cr.NS_ERROR_NOT_INITIALIZED) {
do_print("NS_ERROR_NOT_INITIALIZED");
} else if ("result" in e && e.result == Cr.NS_ERROR_UNEXPECTED) {
do_print("NS_ERROR_UNEXPECTED");
}
}
// Reset gDBConn so that later tests will get a new connection object.
gDBConn = null;
run_next_test();
}
});
////////////////////////////////////////////////////////////////////////////////
//// Test Runner
[
test_create_and_add,
test_multiple_bindings_on_statements,
test_asyncClose_does_not_complete_before_statements,
test_asyncClose_does_not_throw_no_callback,
test_double_asyncClose_throws,
].forEach(add_test);
function run_test()
{
function run_test() {
cleanup();
run_next_test();
}

Просмотреть файл

@ -13,7 +13,7 @@ const REAL = 3.23;
function asyncClose(db) {
let deferred = Promise.defer();
db.asyncClose(function(status) {
db.asyncClose(function (status) {
if (Components.isSuccessCode(status)) {
deferred.resolve();
} else {
@ -25,7 +25,7 @@ function asyncClose(db) {
function openAsyncDatabase(file) {
let deferred = Promise.defer();
getService().openAsyncDatabase(file, null, function(status, db) {
getService().openAsyncDatabase(file, null, function (status, db) {
if (Components.isSuccessCode(status)) {
deferred.resolve(db.QueryInterface(Ci.mozIStorageAsyncConnection));
} else {
@ -38,24 +38,24 @@ function openAsyncDatabase(file) {
function executeSimpleSQLAsync(db, query, onResult) {
let deferred = Promise.defer();
db.executeSimpleSQLAsync(query, {
handleError: function(error) {
handleError(error) {
deferred.reject(error);
},
handleResult: function(result) {
handleResult(result) {
if (onResult) {
onResult(result);
} else {
do_throw("No results were expected");
}
},
handleCompletion: function(result) {
handleCompletion(result) {
deferred.resolve(result);
}
});
return deferred.promise;
}
add_task(function test_create_and_add() {
add_task(function* test_create_and_add() {
let adb = yield openAsyncDatabase(getTestDB());
let completion = yield executeSimpleSQLAsync(adb,
@ -73,7 +73,7 @@ add_task(function test_create_and_add() {
completion = yield executeSimpleSQLAsync(adb,
"SELECT string, number FROM test WHERE id = 1",
function(aResultSet) {
function (aResultSet) {
result = aResultSet.getNextRow();
do_check_eq(2, result.numEntries);
do_check_eq(TEXT, result.getString(0));
@ -86,7 +86,7 @@ add_task(function test_create_and_add() {
result = null;
yield executeSimpleSQLAsync(adb, "SELECT COUNT(0) FROM test",
function(aResultSet) {
function (aResultSet) {
result = aResultSet.getNextRow();
do_check_eq(1, result.getInt32(0));
});
@ -97,12 +97,12 @@ add_task(function test_create_and_add() {
});
add_task(function test_asyncClose_does_not_complete_before_statement() {
add_task(function* test_asyncClose_does_not_complete_before_statement() {
let adb = yield openAsyncDatabase(getTestDB());
let executed = false;
let reason = yield executeSimpleSQLAsync(adb, "SELECT * FROM test",
function(aResultSet) {
function (aResultSet) {
let result = aResultSet.getNextRow();
do_check_neq(result, null);
@ -121,11 +121,3 @@ add_task(function test_asyncClose_does_not_complete_before_statement() {
yield asyncClose(adb);
});
////////////////////////////////////////////////////////////////////////////////
//// Test Runner
function run_test()
{
run_next_test();
}

Просмотреть файл

@ -23,7 +23,7 @@ function test_params_enumerate()
let index = 0;
for (let name in stmt.params) {
if (name == "QueryInterface")
continue;
continue;
do_check_eq(name, expected[index++]);
}
}

Просмотреть файл

@ -30,8 +30,7 @@ function check_levenshtein(db, s, t, expectedDistance)
try {
do_check_true(stmt.executeStep());
do_check_eq(expectedDistance, stmt.row.result);
}
finally {
} finally {
stmt.reset();
stmt.finalize();
}
@ -56,7 +55,7 @@ function testLevenshtein(db)
check_levenshtein(db, "foo", null, null);
check_levenshtein(db, null, "bar", null);
check_levenshtein(db, null, null, null);
// The levenshteinDistance function allocates temporary memory on the stack
// if it can. Test some strings long enough to force a heap allocation.
var dots1000 = Array(1001).join(".");

Просмотреть файл

@ -93,7 +93,7 @@ function test_like_2()
stmt.reset();
stmt.finalize();
}
function test_like_3()
{
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
@ -107,7 +107,7 @@ function test_like_3()
stmt.reset();
stmt.finalize();
}
function test_like_4()
{
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
@ -153,7 +153,7 @@ function test_like_6()
stmt.reset();
stmt.finalize();
}
function test_like_7()
{
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?;");
@ -185,17 +185,18 @@ function test_like_8()
stmt.reset();
stmt.finalize();
}
var tests = [test_count, test_like_1, test_like_2, test_like_3, test_like_4,
var tests = [test_count, test_like_1, test_like_2, test_like_3, test_like_4,
test_like_5, test_like_6, test_like_7, test_like_8];
function run_test()
{
setup();
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const LATIN1_AE = "\xc6";
const LATIN1_ae = "\xe6";
const LATIN1_ae = "\xe6";
function setup()
{
@ -19,7 +19,7 @@ function setup()
stmt.execute();
stmt.finalize();
}
function test_escape_for_like_ascii()
{
var stmt = createStatement("SELECT x FROM t1 WHERE x LIKE ?1 ESCAPE '/'");
@ -27,7 +27,7 @@ function test_escape_for_like_ascii()
// verify that we escaped / _ and %
do_check_eq(paramForLike, "oo//bar/_baz/%20chees");
// prepend and append with % for "contains"
stmt.bindByIndex(0, "%" + paramForLike + "%");
stmt.bindByIndex(0, "%" + paramForLike + "%");
stmt.executeStep();
do_check_eq("foo/bar_baz%20cheese", stmt.getString(0));
stmt.finalize();
@ -52,8 +52,9 @@ function run_test()
{
setup();
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -140,21 +140,21 @@ function localeCompare(aCollation)
var strength;
switch (aCollation) {
case "locale":
strength = Ci.nsICollation.kCollationCaseInSensitive;
break;
case "locale_case_sensitive":
strength = Ci.nsICollation.kCollationAccentInsenstive;
break;
case "locale_accent_sensitive":
strength = Ci.nsICollation.kCollationCaseInsensitiveAscii;
break;
case "locale_case_accent_sensitive":
strength = Ci.nsICollation.kCollationCaseSensitive;
break;
default:
do_throw("Error in test: unknown collation '" + aCollation + "'");
break;
case "locale":
strength = Ci.nsICollation.kCollationCaseInSensitive;
break;
case "locale_case_sensitive":
strength = Ci.nsICollation.kCollationAccentInsenstive;
break;
case "locale_accent_sensitive":
strength = Ci.nsICollation.kCollationCaseInsensitiveAscii;
break;
case "locale_case_accent_sensitive":
strength = Ci.nsICollation.kCollationCaseSensitive;
break;
default:
do_throw("Error in test: unknown collation '" + aCollation + "'");
break;
}
return function (aStr1, aStr2) {
return gLocaleCollation.compareString(strength, aStr1, aStr2);
@ -180,8 +180,9 @@ function readTestData()
let line = {};
let lines = [];
while (istream.readLine(line))
lines.push(line.value);
while (istream.readLine(line)) {
lines.push(line.value);
}
istream.close();
return lines;

Просмотреть файл

@ -34,8 +34,7 @@ function getFileContents(aFile)
////////////////////////////////////////////////////////////////////////////////
//// Tests
function test_delete_removes_data()
{
add_test(function test_delete_removes_data() {
const TEST_STRING = "SomeRandomStringToFind";
let file = getTestDB();
@ -74,14 +73,7 @@ function test_delete_removes_data()
do_check_eq(-1, contents.indexOf(TEST_STRING));
run_next_test();
}
////////////////////////////////////////////////////////////////////////////////
//// Test Runner
[
test_delete_removes_data,
].forEach(add_test);
});
function run_test()
{

Просмотреть файл

@ -53,15 +53,15 @@ function execAsync(aStmt, aOptions, aResults)
if (aResults == null) {
resultsExpected = 0;
}
else if (typeof(aResults) == "number") {
else if (typeof aResults == "number") {
resultsExpected = aResults;
}
else if (typeof(aResults) == "function") {
else if (typeof aResults == "function") {
resultsChecker = aResults;
}
else { // array
resultsExpected = aResults.length;
resultsChecker = function(aResultNum, aTup, aCaller) {
resultsChecker = function (aResultNum, aTup, aCaller) {
aResults[aResultNum](aTup, aCaller);
};
}
@ -83,7 +83,7 @@ function execAsync(aStmt, aOptions, aResults)
let completed = false;
let listener = {
handleResult: function(aResultSet)
handleResult(aResultSet)
{
let row, resultsSeenThisCall = 0;
while ((row = aResultSet.getNextRow()) != null) {
@ -96,13 +96,13 @@ function execAsync(aStmt, aOptions, aResults)
if (!resultsSeenThisCall)
do_throw("handleResult invoked with 0 result rows!");
},
handleError: function(aError)
handleError(aError)
{
if (errorCodeSeen != false)
do_throw("handleError called when we already had an error!");
errorCodeSeen = aError.result;
},
handleCompletion: function(aReason)
handleCompletion(aReason)
{
if (completed) // paranoia check
do_throw("Received a second handleCompletion notification!", caller);
@ -226,8 +226,7 @@ function test_get_data()
);
stmt.bindByIndex(0, INTEGER);
execAsync(stmt, {}, [
function(tuple)
{
function (tuple) {
do_check_neq(null, tuple);
// Check that it's what we expect
@ -254,7 +253,7 @@ function test_get_data()
do_check_eq(BLOB.length, blobByName.length);
var blobByIndex = tuple.getResultByIndex(3);
do_check_eq(BLOB.length, blobByIndex.length);
for (var i = 0; i < BLOB.length; i++) {
for (let i = 0; i < BLOB.length; i++) {
do_check_eq(BLOB[i], blobByName[i]);
do_check_eq(BLOB[i], blobByIndex[i]);
}
@ -262,7 +261,7 @@ function test_get_data()
var blob = { value: null };
tuple.getBlob(3, count, blob);
do_check_eq(BLOB.length, count.value);
for (var i = 0; i < BLOB.length; i++)
for (let i = 0; i < BLOB.length; i++)
do_check_eq(BLOB[i], blob.value[i]);
do_check_eq(Ci.mozIStorageValueArray.VALUE_TYPE_BLOB,
tuple.getTypeOfIndex(3));
@ -283,7 +282,7 @@ function test_tuple_out_of_bounds()
"SELECT string FROM test"
);
execAsync(stmt, {}, [
function(tuple) {
function (tuple) {
do_check_neq(null, tuple);
// Check all out of bounds - should throw
@ -367,19 +366,13 @@ function test_partial_listener_works()
);
stmt.bindByIndex(0, 0);
stmt.executeAsync({
handleResult: function(aResultSet)
{
}
handleResult(aResultSet) {}
});
stmt.executeAsync({
handleError: function(aError)
{
}
handleError(aError) {}
});
stmt.executeAsync({
handleCompletion: function(aReason)
{
}
handleCompletion(aReason) {}
});
stmt.finalize();
@ -467,8 +460,9 @@ function test_finalized_statement_does_not_crash()
// we are concerned about a crash here; an error is fine.
try {
stmt.executeAsync();
} catch (ex) {
// Do nothing.
}
catch (ex) {}
// Run the next test.
run_next_test();
@ -905,14 +899,13 @@ var testPass = TEST_PASS_SYNC;
* @return a statement of the type under test per testPass.
*/
function makeTestStatement(aSQL) {
if (testPass == TEST_PASS_SYNC)
if (testPass == TEST_PASS_SYNC) {
return getOpenedDatabase().createStatement(aSQL);
else
return getOpenedDatabase().createAsyncStatement(aSQL);
}
return getOpenedDatabase().createAsyncStatement(aSQL);
}
var tests =
[
var tests = [
test_illegal_sql_async_deferred,
test_create_table,
test_add_data,

Просмотреть файл

@ -129,12 +129,9 @@ function insertAndCheckMultipleParams(aVal)
*/
function printValDesc(aVal)
{
try
{
try {
var toSource = aVal.toSource();
}
catch (exc)
{
} catch (ex) {
toSource = "";
}
print("Testing value: toString=" + aVal +
@ -163,7 +160,7 @@ function run_test()
print("Single parameter");
insertAndCheckSingleParam(val);
print("Multiple parameters");
insertAndCheckMultipleParams(val)
insertAndCheckMultipleParams(val);
});
cleanup();

Просмотреть файл

@ -11,7 +11,7 @@ function setup()
getOpenedDatabase().createTable("function_tests", "id INTEGER PRIMARY KEY");
var stmt = createStatement("INSERT INTO function_tests (id) VALUES(?1)");
for(var i = 0; i < testNums.length; ++i) {
for (let i = 0; i < testNums.length; ++i) {
stmt.bindByIndex(0, testNums[i]);
stmt.execute();
}
@ -23,17 +23,17 @@ var testSquareAndSumFunction = {
calls: 0,
_sas: 0,
reset: function() {
reset() {
this.calls = 0;
this._sas = 0;
this._sas = 0;
},
onStep: function(val) {
onStep(val) {
++this.calls;
this._sas += val.getInt32(0) * val.getInt32(0);
},
onFinal: function() {
onFinal() {
var retval = this._sas;
this._sas = 0; // Prepare for next group
return retval;
@ -79,7 +79,9 @@ function test_aggregate_no_aliases()
function test_aggregate_call()
{
var stmt = createStatement("SELECT test_sas_aggr(id) FROM function_tests");
while(stmt.executeStep());
while (stmt.executeStep()) {
// Do nothing.
}
do_check_eq(testNums.length, testSquareAndSumFunction.calls);
testSquareAndSumFunction.reset();
stmt.finalize();
@ -88,7 +90,7 @@ function test_aggregate_call()
function test_aggregate_result()
{
var sas = 0;
for(var i = 0; i < testNums.length; ++i) {
for (var i = 0; i < testNums.length; ++i) {
sas += testNums[i] * testNums[i];
}
var stmt = createStatement("SELECT test_sas_aggr(id) FROM function_tests");

Просмотреть файл

@ -9,7 +9,7 @@
function asyncClone(db, readOnly) {
let deferred = Promise.defer();
db.asyncClone(readOnly, function(status, db2) {
db.asyncClone(readOnly, function (status, db2) {
if (Components.isSuccessCode(status)) {
deferred.resolve(db2);
} else {
@ -21,7 +21,7 @@ function asyncClone(db, readOnly) {
function asyncClose(db) {
let deferred = Promise.defer();
db.asyncClose(function(status) {
db.asyncClose(function (status) {
if (Components.isSuccessCode(status)) {
deferred.resolve();
} else {
@ -41,7 +41,7 @@ function openAsyncDatabase(file, options) {
properties.setProperty(k, options[k]);
}
}
getService().openAsyncDatabase(file, properties, function(status, db) {
getService().openAsyncDatabase(file, properties, function (status, db) {
if (Components.isSuccessCode(status)) {
deferred.resolve(db.QueryInterface(Ci.mozIStorageAsyncConnection));
} else {
@ -54,23 +54,22 @@ function openAsyncDatabase(file, options) {
function executeAsync(statement, onResult) {
let deferred = Promise.defer();
statement.executeAsync({
handleError: function(error) {
handleError: function (error) {
deferred.reject(error);
},
handleResult: function(result) {
handleResult: function (result) {
if (onResult) {
onResult(result);
}
},
handleCompletion: function(result) {
handleCompletion: function (result) {
deferred.resolve(result);
}
});
return deferred.promise;
}
add_task(function test_connectionReady_open()
{
add_task(function* test_connectionReady_open() {
// there doesn't seem to be a way for the connection to not be ready (unless
// we close it with mozIStorageConnection::Close(), but we don't for this).
// It can only fail if GetPath fails on the database file, or if we run out
@ -80,8 +79,7 @@ add_task(function test_connectionReady_open()
do_check_true(msc.connectionReady);
});
add_task(function test_connectionReady_closed()
{
add_task(function* test_connectionReady_closed() {
// This also tests mozIStorageConnection::Close()
var msc = getOpenedDatabase();
@ -90,26 +88,22 @@ add_task(function test_connectionReady_closed()
gDBConn = null; // this is so later tests don't start to fail.
});
add_task(function test_databaseFile()
{
add_task(function* test_databaseFile() {
var msc = getOpenedDatabase();
do_check_true(getTestDB().equals(msc.databaseFile));
});
add_task(function test_tableExists_not_created()
{
add_task(function* test_tableExists_not_created() {
var msc = getOpenedDatabase();
do_check_false(msc.tableExists("foo"));
});
add_task(function test_indexExists_not_created()
{
add_task(function* test_indexExists_not_created() {
var msc = getOpenedDatabase();
do_check_false(msc.indexExists("foo"));
});
add_task(function test_temp_tableExists_and_indexExists()
{
add_task(function* test_temp_tableExists_and_indexExists() {
var msc = getOpenedDatabase();
msc.executeSimpleSQL("CREATE TEMP TABLE test_temp(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)");
do_check_true(msc.tableExists("test_temp"));
@ -121,22 +115,19 @@ add_task(function test_temp_tableExists_and_indexExists()
msc.executeSimpleSQL("DROP TABLE test_temp");
});
add_task(function test_createTable_not_created()
{
add_task(function* test_createTable_not_created() {
var msc = getOpenedDatabase();
msc.createTable("test", "id INTEGER PRIMARY KEY, name TEXT");
do_check_true(msc.tableExists("test"));
});
add_task(function test_indexExists_created()
{
add_task(function* test_indexExists_created() {
var msc = getOpenedDatabase();
msc.executeSimpleSQL("CREATE INDEX name_ind ON test (name)");
do_check_true(msc.indexExists("name_ind"));
});
add_task(function test_createTable_already_created()
{
add_task(function* test_createTable_already_created() {
var msc = getOpenedDatabase();
do_check_true(msc.tableExists("test"));
try {
@ -147,8 +138,7 @@ add_task(function test_createTable_already_created()
}
});
add_task(function test_attach_createTable_tableExists_indexExists()
{
add_task(function* test_attach_createTable_tableExists_indexExists() {
var msc = getOpenedDatabase();
var file = do_get_file("storage_attach.sqlite", true);
var msc2 = getDatabase(file);
@ -160,7 +150,10 @@ add_task(function test_attach_createTable_tableExists_indexExists()
try {
msc.createTable("sample.test", "id INTEGER PRIMARY KEY, name TEXT");
do_throw("We shouldn't get here!");
} catch (e if e.result == Components.results.NS_ERROR_FAILURE) {
} catch (e) {
if (e.result != Components.results.NS_ERROR_FAILURE) {
throw e;
}
// we expect to fail because this table should exist already.
}
@ -170,24 +163,25 @@ add_task(function test_attach_createTable_tableExists_indexExists()
msc.executeSimpleSQL("DETACH DATABASE sample");
msc2.close();
try { file.remove(false); } catch(e) { }
try {
file.remove(false);
} catch (e) {
// Do nothing.
}
});
add_task(function test_lastInsertRowID()
{
add_task(function* test_lastInsertRowID() {
var msc = getOpenedDatabase();
msc.executeSimpleSQL("INSERT INTO test (name) VALUES ('foo')");
do_check_eq(1, msc.lastInsertRowID);
});
add_task(function test_transactionInProgress_no()
{
add_task(function* test_transactionInProgress_no() {
var msc = getOpenedDatabase();
do_check_false(msc.transactionInProgress);
});
add_task(function test_transactionInProgress_yes()
{
add_task(function* test_transactionInProgress_yes() {
var msc = getOpenedDatabase();
msc.beginTransaction();
do_check_true(msc.transactionInProgress);
@ -200,8 +194,7 @@ add_task(function test_transactionInProgress_yes()
do_check_false(msc.transactionInProgress);
});
add_task(function test_commitTransaction_no_transaction()
{
add_task(function* test_commitTransaction_no_transaction() {
var msc = getOpenedDatabase();
do_check_false(msc.transactionInProgress);
try {
@ -212,8 +205,7 @@ add_task(function test_commitTransaction_no_transaction()
}
});
add_task(function test_rollbackTransaction_no_transaction()
{
add_task(function* test_rollbackTransaction_no_transaction() {
var msc = getOpenedDatabase();
do_check_false(msc.transactionInProgress);
try {
@ -224,47 +216,47 @@ add_task(function test_rollbackTransaction_no_transaction()
}
});
add_task(function test_get_schemaVersion_not_set()
{
add_task(function* test_get_schemaVersion_not_set() {
do_check_eq(0, getOpenedDatabase().schemaVersion);
});
add_task(function test_set_schemaVersion()
{
add_task(function* test_set_schemaVersion() {
var msc = getOpenedDatabase();
const version = 1;
msc.schemaVersion = version;
do_check_eq(version, msc.schemaVersion);
});
add_task(function test_set_schemaVersion_same()
{
add_task(function* test_set_schemaVersion_same() {
var msc = getOpenedDatabase();
const version = 1;
msc.schemaVersion = version; // should still work ok
do_check_eq(version, msc.schemaVersion);
});
add_task(function test_set_schemaVersion_negative()
{
add_task(function* test_set_schemaVersion_negative() {
var msc = getOpenedDatabase();
const version = -1;
msc.schemaVersion = version;
do_check_eq(version, msc.schemaVersion);
});
add_task(function test_createTable(){
add_task(function* test_createTable() {
var temp = getTestDB().parent;
temp.append("test_db_table");
try {
var con = getService().openDatabase(temp);
con.createTable("a","");
con.createTable("a", "");
} catch (e) {
if (temp.exists()) try {
temp.remove(false);
} catch (e2) {}
do_check_true(e.result==Cr.NS_ERROR_NOT_INITIALIZED ||
e.result==Cr.NS_ERROR_FAILURE);
if (temp.exists()) {
try {
temp.remove(false);
} catch (e2) {
// Do nothing.
}
}
do_check_true(e.result == Cr.NS_ERROR_NOT_INITIALIZED ||
e.result == Cr.NS_ERROR_FAILURE);
} finally {
if (con) {
con.close();
@ -272,8 +264,7 @@ add_task(function test_createTable(){
}
});
add_task(function test_defaultSynchronousAtNormal()
{
add_task(function* test_defaultSynchronousAtNormal() {
var msc = getOpenedDatabase();
var stmt = createStatement("PRAGMA synchronous;");
try {
@ -287,14 +278,12 @@ add_task(function test_defaultSynchronousAtNormal()
});
// must be ran before executeAsync tests
add_task(function test_close_does_not_spin_event_loop()
{
add_task(function* test_close_does_not_spin_event_loop() {
// We want to make sure that the event loop on the calling thread does not
// spin when close is called.
let event = {
ran: false,
run: function()
{
run() {
this.ran = true;
},
};
@ -315,8 +304,7 @@ add_task(function test_close_does_not_spin_event_loop()
gDBConn = null;
});
add_task(function test_asyncClose_succeeds_with_finalized_async_statement()
{
add_task(function* test_asyncClose_succeeds_with_finalized_async_statement() {
// XXX this test isn't perfect since we can't totally control when events will
// run. If this paticular function fails randomly, it means we have a
// real bug.
@ -333,7 +321,7 @@ add_task(function test_asyncClose_succeeds_with_finalized_async_statement()
gDBConn = null;
});
add_task(function test_close_then_release_statement() {
add_task(function* test_close_then_release_statement() {
// Testing the behavior in presence of a bad client that finalizes
// statements after the database has been closed (typically by
// letting the gc finalize the statement).
@ -346,7 +334,7 @@ add_task(function test_close_then_release_statement() {
gDBConn = null;
});
add_task(function test_asyncClose_then_release_statement() {
add_task(function* test_asyncClose_then_release_statement() {
// Testing the behavior in presence of a bad client that finalizes
// statements after the database has been async closed (typically by
// letting the gc finalize the statement).
@ -359,8 +347,7 @@ add_task(function test_asyncClose_then_release_statement() {
gDBConn = null;
});
add_task(function test_close_fails_with_async_statement_ran()
{
add_task(function* test_close_fails_with_async_statement_ran() {
let deferred = Promise.defer();
let stmt = createStatement("SELECT * FROM test");
stmt.executeAsync();
@ -376,7 +363,7 @@ add_task(function test_close_fails_with_async_statement_ran()
}
finally {
// Clean up after ourselves.
db.asyncClose(function() {
db.asyncClose(function () {
// Reset gDBConn so that later tests will get a new connection object.
gDBConn = null;
deferred.resolve();
@ -385,8 +372,7 @@ add_task(function test_close_fails_with_async_statement_ran()
yield deferred.promise;
});
add_task(function test_clone_optional_param()
{
add_task(function* test_clone_optional_param() {
let db1 = getService().openUnsharedDatabase(getTestDB());
let db2 = db1.clone();
do_check_true(db2.connectionReady);
@ -409,7 +395,7 @@ add_task(function test_clone_optional_param()
db2.close();
});
function standardAsyncTest(promisedDB, name, shouldInit = false) {
function* standardAsyncTest(promisedDB, name, shouldInit = false) {
do_print("Performing standard async test " + name);
let adb = yield promisedDB;
@ -434,13 +420,12 @@ function standardAsyncTest(promisedDB, name, shouldInit = false) {
do_print("Extracting data");
stmt = adb.createAsyncStatement("SELECT * FROM test");
let found = false;
yield executeAsync(stmt, function(result) {
yield executeAsync(stmt, function (results) {
do_print("Data has been extracted");
for (let row = result.getNextRow(); row != null; row = result.getNextRow()) {
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
if (row.getResultByName("name") == name) {
found = true;
break;
break;
}
}
});
@ -451,7 +436,7 @@ function standardAsyncTest(promisedDB, name, shouldInit = false) {
do_print("Standard async test " + name + " complete");
}
add_task(function test_open_async() {
add_task(function* test_open_async() {
yield standardAsyncTest(openAsyncDatabase(getTestDB(), null), "default");
yield standardAsyncTest(openAsyncDatabase(getTestDB()), "no optional arg");
yield standardAsyncTest(openAsyncDatabase(getTestDB(),
@ -492,7 +477,7 @@ add_task(function test_open_async() {
});
add_task(function test_async_open_with_shared_cache() {
add_task(function* test_async_open_with_shared_cache() {
do_print("Testing that opening with a shared cache doesn't break stuff");
let adb = yield openAsyncDatabase(getTestDB(), {shared: true});
@ -505,13 +490,12 @@ add_task(function test_async_open_with_shared_cache() {
do_print("Extracting data");
stmt = adb.createAsyncStatement("SELECT * FROM test");
let found = false;
yield executeAsync(stmt, function(result) {
yield executeAsync(stmt, function (results) {
do_print("Data has been extracted");
for (let row = result.getNextRow(); row != null; row = result.getNextRow()) {
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
if (row.getResultByName("name") == "clockworker") {
found = true;
break;
break;
}
}
});
@ -520,8 +504,7 @@ add_task(function test_async_open_with_shared_cache() {
yield asyncClose(adb);
});
add_task(function test_clone_trivial_async()
{
add_task(function* test_clone_trivial_async() {
let db1 = getService().openDatabase(getTestDB());
do_print("Opened adb1");
do_check_true(db1 instanceof Ci.mozIStorageAsyncConnection);
@ -533,8 +516,7 @@ add_task(function test_clone_trivial_async()
yield asyncClose(adb2);
});
add_task(function test_clone_no_optional_param_async()
{
add_task(function* test_clone_no_optional_param_async() {
"use strict";
do_print("Testing async cloning");
let adb1 = yield openAsyncDatabase(getTestDB(), null);
@ -560,13 +542,12 @@ add_task(function test_clone_no_optional_param_async()
do_print("Extracting data from clone db");
stmt = adb2.createAsyncStatement("SELECT * FROM test");
let found = false;
yield executeAsync(stmt, function(result) {
yield executeAsync(stmt, function (results) {
do_print("Data has been extracted");
for (let row = result.getNextRow(); row != null; row = result.getNextRow()) {
for (let row = results.getNextRow(); row != null; row = results.getNextRow()) {
if (row.getResultByName("name") == "yoric") {
found = true;
break;
break;
}
}
});
@ -580,8 +561,7 @@ add_task(function test_clone_no_optional_param_async()
do_print("Second db closed");
});
add_task(function test_clone_readonly()
{
add_task(function* test_clone_readonly() {
let db1 = getService().openUnsharedDatabase(getTestDB());
let db2 = db1.clone(true);
do_check_true(db2.connectionReady);
@ -601,8 +581,7 @@ add_task(function test_clone_readonly()
db2.close();
});
add_task(function test_clone_shared_readonly()
{
add_task(function* test_clone_shared_readonly() {
let db1 = getService().openDatabase(getTestDB());
let db2 = db1.clone(true);
do_check_true(db2.connectionReady);
@ -626,28 +605,25 @@ add_task(function test_clone_shared_readonly()
db2.close();
});
add_task(function test_close_clone_fails()
{
add_task(function* test_close_clone_fails() {
let calls = [
"openDatabase",
"openUnsharedDatabase",
];
calls.forEach(function(methodName) {
calls.forEach(function (methodName) {
let db = getService()[methodName](getTestDB());
db.close();
expectError(Cr.NS_ERROR_NOT_INITIALIZED, () => db.clone());
});
});
add_task(function test_memory_clone_fails()
{
add_task(function* test_memory_clone_fails() {
let db = getService().openSpecialDatabase("memory");
db.close();
expectError(Cr.NS_ERROR_NOT_INITIALIZED, () => db.clone());
});
add_task(function test_clone_copies_functions()
{
add_task(function* test_clone_copies_functions() {
const FUNC_NAME = "test_func";
let calls = [
"openDatabase",
@ -657,9 +633,9 @@ add_task(function test_clone_copies_functions()
"createFunction",
"createAggregateFunction",
];
calls.forEach(function(methodName) {
[true, false].forEach(function(readOnly) {
functionMethods.forEach(function(functionMethod) {
calls.forEach(function (methodName) {
[true, false].forEach(function (readOnly) {
functionMethods.forEach(function (functionMethod) {
let db1 = getService()[methodName](getTestDB());
// Create a function for db1.
db1[functionMethod](FUNC_NAME, 1, {
@ -680,17 +656,16 @@ add_task(function test_clone_copies_functions()
});
});
add_task(function test_clone_copies_overridden_functions()
{
add_task(function* test_clone_copies_overridden_functions() {
const FUNC_NAME = "lower";
function test_func() {
this.called = false;
}
test_func.prototype = {
onFunctionCall: function() {
onFunctionCall() {
this.called = true;
},
onStep: function() {
onStep() {
this.called = true;
},
onFinal: () => 0,
@ -704,9 +679,9 @@ add_task(function test_clone_copies_overridden_functions()
"createFunction",
"createAggregateFunction",
];
calls.forEach(function(methodName) {
[true, false].forEach(function(readOnly) {
functionMethods.forEach(function(functionMethod) {
calls.forEach(function (methodName) {
[true, false].forEach(function (readOnly) {
functionMethods.forEach(function (functionMethod) {
let db1 = getService()[methodName](getTestDB());
// Create a function for db1.
let func = new test_func();
@ -726,8 +701,7 @@ add_task(function test_clone_copies_overridden_functions()
});
});
add_task(function test_clone_copies_pragmas()
{
add_task(function* test_clone_copies_pragmas() {
const PRAGMAS = [
{ name: "cache_size", value: 500, copied: true },
{ name: "temp_store", value: 2, copied: true },
@ -769,8 +743,7 @@ add_task(function test_clone_copies_pragmas()
db2.close();
});
add_task(function test_readonly_clone_copies_pragmas()
{
add_task(function* test_readonly_clone_copies_pragmas() {
const PRAGMAS = [
{ name: "cache_size", value: 500, copied: true },
{ name: "temp_store", value: 2, copied: true },
@ -812,8 +785,7 @@ add_task(function test_readonly_clone_copies_pragmas()
db2.close();
});
add_task(function test_getInterface()
{
add_task(function* test_getInterface() {
let db = getOpenedDatabase();
let target = db.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIEventTarget);
@ -826,7 +798,6 @@ add_task(function test_getInterface()
});
function run_test()
{
function run_test() {
run_next_test();
}

Просмотреть файл

@ -11,7 +11,7 @@ function setup()
getOpenedDatabase().createTable("function_tests", "id INTEGER PRIMARY KEY");
var stmt = createStatement("INSERT INTO function_tests (id) VALUES(?1)");
for(var i = 0; i < testNums.length; ++i) {
for (let i = 0; i < testNums.length; ++i) {
stmt.bindByIndex(0, testNums[i]);
stmt.execute();
}
@ -22,7 +22,7 @@ function setup()
var testSquareFunction = {
calls: 0,
onFunctionCall: function(val) {
onFunctionCall(val) {
++this.calls;
return val.getInt32(0) * val.getInt32(0);
}
@ -62,7 +62,9 @@ function test_function_aliases()
function test_function_call()
{
var stmt = createStatement("SELECT test_square(id) FROM function_tests");
while(stmt.executeStep());
while (stmt.executeStep()) {
// Do nothing.
}
do_check_eq(testNums.length, testSquareFunction.calls);
testSquareFunction.calls = 0;
stmt.finalize();
@ -72,7 +74,7 @@ function test_function_result()
{
var stmt = createStatement("SELECT test_square(42) FROM function_tests");
stmt.executeStep();
do_check_eq(42*42, stmt.getInt32(0));
do_check_eq(42 * 42, stmt.getInt32(0));
testSquareFunction.calls = 0;
stmt.finalize();
}

Просмотреть файл

@ -11,9 +11,9 @@ function setup()
msc.beginTransaction();
var stmt = createStatement("INSERT INTO handler_tests (id, num) VALUES(?1, ?2)");
for(var i = 0; i < 100; ++i) {
for (let i = 0; i < 100; ++i) {
stmt.bindByIndex(0, i);
stmt.bindByIndex(1, Math.floor(Math.random()*1000));
stmt.bindByIndex(1, Math.floor(Math.random() * 1000));
stmt.execute();
}
stmt.reset();
@ -25,7 +25,7 @@ var testProgressHandler = {
calls: 0,
abort: false,
onProgress: function(comm) {
onProgress(comm) {
++this.calls;
return this.abort;
}
@ -59,7 +59,9 @@ function test_handler_call()
// Some long-executing request
var stmt = createStatement(
"SELECT SUM(t1.num * t2.num) FROM handler_tests AS t1, handler_tests AS t2");
while(stmt.executeStep());
while (stmt.executeStep()) {
// Do nothing.
}
do_check_true(testProgressHandler.calls > 0);
stmt.finalize();
}
@ -75,7 +77,9 @@ function test_handler_abort()
const SQLITE_INTERRUPT = 9;
try {
while(stmt.executeStep());
while (stmt.executeStep()) {
// Do nothing.
}
do_throw("We shouldn't get here!");
} catch (e) {
do_check_eq(Cr.NS_ERROR_ABORT, e.result);

Просмотреть файл

@ -97,7 +97,7 @@ function test_backup_new_filename()
{
var backup = getService().backupDatabaseFile(getTestDB(), BACKUP_FILE_NAME);
do_check_eq(BACKUP_FILE_NAME, backup.leafName);
backup.remove(false);
}
@ -107,7 +107,7 @@ function test_backup_new_folder()
parentDir.append("test_storage_temp");
if (parentDir.exists())
parentDir.remove(true);
parentDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
parentDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
do_check_true(parentDir.exists());
var backup = getService().backupDatabaseFile(getTestDB(), BACKUP_FILE_NAME,
@ -133,9 +133,10 @@ var tests = [
function run_test()
{
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -29,7 +29,7 @@ function run_test()
{
for (var i = 0; i < tests.length; i++)
tests[i]();
cleanup();
}

Просмотреть файл

@ -86,7 +86,7 @@ function test_getColumnIndex_different_case()
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
}
try {
do_check_eq(1, stmt.getColumnIndex("Id"));
do_check_eq(1, stmt.getColumnIndex("Id"));
do_throw("should not get here");
} catch (e) {
do_check_eq(Cr.NS_ERROR_INVALID_ARG, e.result);
@ -179,9 +179,10 @@ function run_test()
{
setup();
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -8,14 +8,14 @@ function setup()
{
getOpenedDatabase().createTable("test", "id INTEGER PRIMARY KEY, name TEXT," +
"number REAL, nuller NULL, blobber BLOB");
var stmt = createStatement("INSERT INTO test (name, number, blobber) " +
"VALUES (?1, ?2, ?3)");
stmt.bindByIndex(0, "foo");
stmt.bindByIndex(1, 2.34);
stmt.bindBlobByIndex(2, [], 0);
stmt.execute();
stmt.bindByIndex(0, "");
stmt.bindByIndex(1, 1.23);
stmt.bindBlobByIndex(2, [1, 2], 2);
@ -30,7 +30,7 @@ function test_getIsNull_for_null()
var stmt = createStatement("SELECT nuller, blobber FROM test WHERE id = ?1");
stmt.bindByIndex(0, 1);
do_check_true(stmt.executeStep());
do_check_true(stmt.getIsNull(0)); // null field
do_check_true(stmt.getIsNull(1)); // data is null if size is 0
stmt.reset();
@ -202,9 +202,10 @@ function run_test()
{
setup();
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -5,8 +5,8 @@
// Make sure that there are telemetry entries created by sqlite io
function run_sql(d, sql) {
var stmt = d.createStatement(sql)
stmt.execute()
var stmt = d.createStatement(sql);
stmt.execute();
stmt.finalize();
}
@ -24,7 +24,7 @@ function run_test()
const file = new_file("telemetry.sqlite");
var d = getDatabase(file);
run_sql(d, "CREATE TABLE bloat(data varchar)");
run_sql(d, "DROP TABLE bloat")
do_check_true(read_hgram.snapshot().sum > old_sum)
run_sql(d, "DROP TABLE bloat");
do_check_true(read_hgram.snapshot().sum > old_sum);
}

Просмотреть файл

@ -95,9 +95,10 @@ function run_test()
{
setup();
for (var i = 0; i < tests.length; i++)
for (var i = 0; i < tests.length; i++) {
tests[i]();
}
cleanup();
}

Просмотреть файл

@ -87,6 +87,239 @@ function run_test()
run_next_test();
}
const TESTS = [
function test_common_vacuum()
{
print("\n*** Test that a VACUUM correctly happens and all notifications are fired.");
// Wait for VACUUM begin.
let beginVacuumReceived = false;
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
Services.obs.removeObserver(onVacuum, aTopic);
beginVacuumReceived = true;
}, "test-begin-vacuum", false);
// Wait for heavy IO notifications.
let heavyIOTaskBeginReceived = false;
let heavyIOTaskEndReceived = false;
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
if (heavyIOTaskBeginReceived && heavyIOTaskEndReceived) {
Services.obs.removeObserver(onVacuum, aTopic);
}
if (aData == "vacuum-begin") {
heavyIOTaskBeginReceived = true;
}
else if (aData == "vacuum-end") {
heavyIOTaskEndReceived = true;
}
}, "heavy-io-task", false);
// Wait for VACUUM end.
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
Services.obs.removeObserver(onVacuum, aTopic);
print("Check we received onBeginVacuum");
do_check_true(beginVacuumReceived);
print("Check we received heavy-io-task notifications");
do_check_true(heavyIOTaskBeginReceived);
do_check_true(heavyIOTaskEndReceived);
print("Received onEndVacuum");
run_next_test();
}, "test-end-vacuum", false);
synthesize_idle_daily();
},
function test_skipped_if_recent_vacuum()
{
print("\n*** Test that a VACUUM is skipped if it was run recently.");
Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite",
parseInt(Date.now() / 1000));
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
function test_page_size_change()
{
print("\n*** Test that a VACUUM changes page_size");
// We did setup the database with a small page size, the previous vacuum
// should have updated it.
print("Check that page size was updated.");
let conn = getDatabase(new_db_file("testVacuum"));
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, conn.defaultPageSize);
}
}
finally {
stmt.finalize();
}
run_next_test();
},
function test_skipped_optout_vacuum()
{
print("\n*** Test that a VACUUM is skipped if the participant wants to opt-out.");
Services.obs.notifyObservers(null, "test-options", "opt-out");
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_page_size_change_with_wal()
{
print("\n*** Test that a VACUUM changes page_size with WAL mode");
Services.obs.notifyObservers(null, "test-options", "wal");
// Set a small page size.
let conn = getDatabase(new_db_file("testVacuum2"));
conn.executeSimpleSQL("PRAGMA page_size = 1024");
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, 1024);
}
}
finally {
stmt.finalize();
}
// Use WAL journal mode.
conn.executeSimpleSQL("PRAGMA journal_mode = WAL");
stmt = conn.createStatement("PRAGMA journal_mode");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.journal_mode, "wal");
}
}
finally {
stmt.finalize();
}
// Wait for VACUUM end.
let vacuumObserver = {
observe: function VO_observe(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, aTopic);
print("Check page size has been updated.");
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, Ci.mozIStorageConnection.DEFAULT_PAGE_SIZE);
}
}
finally {
stmt.finalize();
}
print("Check journal mode has been restored.");
stmt = conn.createStatement("PRAGMA journal_mode");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.journal_mode, "wal");
}
}
finally {
stmt.finalize();
}
run_next_test();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
synthesize_idle_daily();
},
*/
function test_memory_database_crash()
{
print("\n*** Test that we don't crash trying to vacuum a memory database");
Services.obs.notifyObservers(null, "test-options", "memory");
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_wal_restore_fail()
{
print("\n*** Test that a failing WAL restoration notifies failure");
Services.obs.notifyObservers(null, "test-options", "wal-fail");
// Wait for VACUUM end.
let vacuumObserver = {
observe: function VO_observe(aSubject, aTopic, aData) {
Services.obs.removeObserver(vacuumObserver, "test-end-vacuum");
print("Check WAL restoration failed.");
do_check_false(aData);
run_next_test();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
synthesize_idle_daily();
},
*/
];
function run_next_test()
{
if (TESTS.length == 0) {
@ -100,236 +333,3 @@ function run_next_test()
do_execute_soon(TESTS.shift());
}
}
const TESTS = [
function test_common_vacuum()
{
print("\n*** Test that a VACUUM correctly happens and all notifications are fired.");
// Wait for VACUUM begin.
let beginVacuumReceived = false;
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
Services.obs.removeObserver(onVacuum, aTopic);
beginVacuumReceived = true;
}, "test-begin-vacuum", false);
// Wait for heavy IO notifications.
let heavyIOTaskBeginReceived = false;
let heavyIOTaskEndReceived = false;
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
if (heavyIOTaskBeginReceived && heavyIOTaskEndReceived) {
Services.obs.removeObserver(onVacuum, aTopic);
}
if (aData == "vacuum-begin") {
heavyIOTaskBeginReceived = true;
}
else if (aData == "vacuum-end") {
heavyIOTaskEndReceived = true;
}
}, "heavy-io-task", false);
// Wait for VACUUM end.
Services.obs.addObserver(function onVacuum(aSubject, aTopic, aData) {
Services.obs.removeObserver(onVacuum, aTopic);
print("Check we received onBeginVacuum");
do_check_true(beginVacuumReceived);
print("Check we received heavy-io-task notifications");
do_check_true(heavyIOTaskBeginReceived);
do_check_true(heavyIOTaskEndReceived);
print("Received onEndVacuum");
run_next_test();
}, "test-end-vacuum", false);
synthesize_idle_daily();
},
function test_skipped_if_recent_vacuum()
{
print("\n*** Test that a VACUUM is skipped if it was run recently.");
Services.prefs.setIntPref("storage.vacuum.last.testVacuum.sqlite",
parseInt(Date.now() / 1000));
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
function test_page_size_change()
{
print("\n*** Test that a VACUUM changes page_size");
// We did setup the database with a small page size, the previous vacuum
// should have updated it.
print("Check that page size was updated.");
let conn = getDatabase(new_db_file("testVacuum"));
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, conn.defaultPageSize);
}
}
finally {
stmt.finalize();
}
run_next_test();
},
function test_skipped_optout_vacuum()
{
print("\n*** Test that a VACUUM is skipped if the participant wants to opt-out.");
Services.obs.notifyObservers(null, "test-options", "opt-out");
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_page_size_change_with_wal()
{
print("\n*** Test that a VACUUM changes page_size with WAL mode");
Services.obs.notifyObservers(null, "test-options", "wal");
// Set a small page size.
let conn = getDatabase(new_db_file("testVacuum2"));
conn.executeSimpleSQL("PRAGMA page_size = 1024");
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, 1024);
}
}
finally {
stmt.finalize();
}
// Use WAL journal mode.
conn.executeSimpleSQL("PRAGMA journal_mode = WAL");
stmt = conn.createStatement("PRAGMA journal_mode");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.journal_mode, "wal");
}
}
finally {
stmt.finalize();
}
// Wait for VACUUM end.
let vacuumObserver = {
observe: function VO_observe(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, aTopic);
print("Check page size has been updated.");
let stmt = conn.createStatement("PRAGMA page_size");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.page_size, Ci.mozIStorageConnection.DEFAULT_PAGE_SIZE);
}
}
finally {
stmt.finalize();
}
print("Check journal mode has been restored.");
stmt = conn.createStatement("PRAGMA journal_mode");
try {
while (stmt.executeStep()) {
do_check_eq(stmt.row.journal_mode, "wal");
}
}
finally {
stmt.finalize();
}
run_next_test();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
synthesize_idle_daily();
},
*/
function test_memory_database_crash()
{
print("\n*** Test that we don't crash trying to vacuum a memory database");
Services.obs.notifyObservers(null, "test-options", "memory");
// Wait for VACUUM begin.
let vacuumObserver = {
gotNotification: false,
observe: function VO_observe(aSubject, aTopic, aData) {
this.gotNotification = true;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-begin-vacuum", false);
// Check after a couple seconds that no VACUUM has been run.
do_timeout(2000, function () {
print("Check VACUUM did not run.");
do_check_false(vacuumObserver.gotNotification);
Services.obs.removeObserver(vacuumObserver, "test-begin-vacuum");
run_next_test();
});
synthesize_idle_daily();
},
/* Changing page size on WAL is not supported till Bug 634374 is properly fixed.
function test_wal_restore_fail()
{
print("\n*** Test that a failing WAL restoration notifies failure");
Services.obs.notifyObservers(null, "test-options", "wal-fail");
// Wait for VACUUM end.
let vacuumObserver = {
observe: function VO_observe(aSubject, aTopic, aData) {
Services.obs.removeObserver(vacuumObserver, "test-end-vacuum");
print("Check WAL restoration failed.");
do_check_false(aData);
run_next_test();
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
}
Services.obs.addObserver(vacuumObserver, "test-end-vacuum", false);
synthesize_idle_daily();
},
*/
];

Просмотреть файл

@ -76,15 +76,17 @@ vacuumParticipant.prototype =
else if (aData == "wal") {
try {
this._dbConn.close();
} catch (e) {
// Do nothing.
}
catch(e) {}
this._dbConn = getDatabase(new_db_file("testVacuum2"));
}
else if (aData == "wal-fail") {
try {
this._dbConn.close();
} catch (e) {
// Do nothing.
}
catch(e) {}
this._dbConn = getDatabase(new_db_file("testVacuum3"));
// Use WAL journal mode.
this._dbConn.executeSimpleSQL("PRAGMA journal_mode = WAL");
@ -96,8 +98,9 @@ vacuumParticipant.prototype =
else if (aData == "memory") {
try {
this._dbConn.asyncClose();
} catch (e) {
// Do nothing.
}
catch(e) {}
this._dbConn = Cc["@mozilla.org/storage/service;1"].
getService(Ci.mozIStorageService).
openSpecialDatabase("memory");
@ -106,14 +109,15 @@ vacuumParticipant.prototype =
Services.obs.removeObserver(this, "test-options");
try {
this._dbConn.asyncClose();
} catch (e) {
// Do nothing.
}
catch(e) {}
}
},
QueryInterface: XPCOMUtils.generateQI([
Ci.mozIStorageVacuumParticipant
, Ci.nsIObserver
Ci.mozIStorageVacuumParticipant,
Ci.nsIObserver,
])
};

Просмотреть файл

@ -155,7 +155,7 @@
// "no-unused-vars": [2, {"vars": "all", "args": "none"}],
// No using variables before defined
// "no-use-before-define": 2,
// "no-use-before-define": [2, "nofunc"],
// No using with
// "no-with": 2,

Просмотреть файл

@ -561,7 +561,7 @@ var View = {
cachedElements.eltName.textContent = `Full name: ${delta.fullName}.`;
cachedElements.eltLoaded.textContent = `Measure start: ${Math.round(delta.age/1000)} seconds ago.`
let processes = [for (proc of delta.diff.processes) `${proc.processId} (${proc.isChildProcess?"child":"parent"})`];
let processes = delta.diff.processes.map(proc => `${proc.processId} (${proc.isChildProcess?"child":"parent"})`);
cachedElements.eltProcess.textContent = `Processes: ${processes.join(", ")}`;
let jankSuffix = "";
let cpowSuffix = "";

Просмотреть файл

@ -164,8 +164,8 @@ function frameScript() {
return;
}
let addonTitles = [for (eltContent of eltAddons.querySelectorAll("span.title")) eltContent.textContent];
let webTitles = [for (eltContent of eltWeb.querySelectorAll("span.title")) eltContent.textContent];
let addonTitles = Array.from(eltAddons.querySelectorAll("span.title"), elt => elt.textContent);
let webTitles = Array.from(eltWeb.querySelectorAll("span.title"), elt => elt.textContent);
hasTitleInAddons = addonTitles.includes(title);
hasTitleInWebpages = webTitles.includes(title);

Просмотреть файл

@ -1,8 +1,8 @@
# -*- 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/.
/* 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/. */
Components.utils.import("resource://gre/modules/AppConstants.jsm");
function AppPicker() {};
@ -117,20 +117,19 @@ AppPicker.prototype =
* Retrieve the pretty description from the file
*/
getFileDisplayName: function getFileDisplayName(file) {
#ifdef XP_WIN
if (file instanceof Components.interfaces.nsILocalFileWin) {
try {
return file.getVersionInfoField("FileDescription");
} catch (e) {}
if (AppConstants.platform == "win") {
if (file instanceof Components.interfaces.nsILocalFileWin) {
try {
return file.getVersionInfoField("FileDescription");
} catch (e) {}
}
} else if (AppConstants.platform == "macosx") {
if (file instanceof Components.interfaces.nsILocalFileMac) {
try {
return file.bundleDisplayName;
} catch (e) {}
}
}
#endif
#ifdef XP_MACOSX
if (file instanceof Components.interfaces.nsILocalFileMac) {
try {
return file.bundleDisplayName;
} catch (e) {}
}
#endif
return file.leafName;
},
@ -186,15 +185,13 @@ AppPicker.prototype =
var fileLoc = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
var startLocation;
#ifdef XP_WIN
startLocation = "ProgF"; // Program Files
#else
#ifdef XP_MACOSX
startLocation = "LocApp"; // Local Applications
#else
startLocation = "Home";
#endif
#endif
if (AppConstants.platform == "win") {
startLocation = "ProgF"; // Program Files
} else if (AppConstants.platform == "macosx") {
startLocation = "LocApp"; // Local Applications
} else {
startLocation = "Home";
}
fp.displayDirectory =
fileLoc.get(startLocation, Components.interfaces.nsILocalFile);

Просмотреть файл

@ -4,5 +4,5 @@
toolkit.jar:
content/global/appPicker.xul (content/appPicker.xul)
* content/global/appPicker.js (content/appPicker.js)
content/global/appPicker.js (content/appPicker.js)

Просмотреть файл

@ -0,0 +1,499 @@
{
"extends": "../../.eslintrc",
"globals": {
"Cc": true,
"Ci": true,
"Components": true,
"Cr": true,
"Cu": true,
"dump": true,
"TextDecoder": false,
"TextEncoder": false,
// Specific to WebExtensions:
"extensions": true,
"global": true,
"Extension": true,
"ExtensionManagement": true,
"ExtensionPage": true,
"GlobalManager": true,
"runSafe": true,
"runSafeSync": true,
"runSafeSyncWithoutClone": true,
"Services": true,
"TabManager": true,
"XPCOMUtils": true,
},
"rules": {
// Rules from the mozilla plugin
"mozilla/balanced-listeners": 2,
"mozilla/components-imports": 1,
"mozilla/import-headjs-globals": 1,
"mozilla/mark-test-function-used": 1,
"mozilla/no-aArgs": 1,
"mozilla/no-cpows-in-tests": 1,
"mozilla/var-only-at-top-level": 1,
// Braces only needed for multi-line arrow function blocks
// "arrow-body-style": [2, "as-needed"],
// Require spacing around =>
"arrow-spacing": 2,
// Always require spacing around a single line block
"block-spacing": 1,
// Enforce one true brace style (opening brace on the same line) and avoid
// start and end braces on the same line.
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
// No space before always a space after a comma
"comma-spacing": [2, {"before": false, "after": true}],
// Commas at the end of the line not the start
"comma-style": 2,
// Don't require spaces around computed properties
"computed-property-spacing": [1, "never"],
// Functions are not required to consistently return something or nothing
"consistent-return": 0,
// Require braces around blocks that start a new line
"curly": [2, "multi-line"],
// Always require a trailing EOL
"eol-last": 2,
// Require function* name()
"generator-star-spacing": [2, {"before": false, "after": true}],
// Two space indent
"indent": [2, 2, { "SwitchCase": 1 }],
// Space after colon not before in property declarations
"key-spacing": [2, { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
// Unix linebreaks
"linebreak-style": [2, "unix"],
// Always require parenthesis for new calls
"new-parens": 2,
// Use [] instead of Array()
"no-array-constructor": 2,
// No duplicate arguments in function declarations
"no-dupe-args": 2,
// No duplicate keys in object declarations
"no-dupe-keys": 2,
// No duplicate cases in switch statements
"no-duplicate-case": 2,
// No labels
// "no-labels": 2,
// If an if block ends with a return no need for an else block
// "no-else-return": 2,
// Disallow empty statements. This will report an error for:
// try { something(); } catch (e) {}
// but will not report it for:
// try { something(); } catch (e) { /* Silencing the error because ...*/ }
// which is a valid use case.
"no-empty": 2,
// No empty character classes in regex
"no-empty-character-class": 2,
// Disallow empty destructuring
"no-empty-pattern": 2,
// No assiging to exception variable
"no-ex-assign": 2,
// No using !! where casting to boolean is already happening
"no-extra-boolean-cast": 1,
// No double semicolon
"no-extra-semi": 2,
// No overwriting defined functions
"no-func-assign": 2,
// No invalid regular expresions
"no-invalid-regexp": 2,
// No odd whitespace characters
"no-irregular-whitespace": 2,
// No single if block inside an else block
"no-lonely-if": 1,
// No mixing spaces and tabs in indent
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
// Disallow use of multiple spaces (sometimes used to align const values,
// array or object items, etc.). It's hard to maintain and doesn't add that
// much benefit.
"no-multi-spaces": 1,
// No reassigning native JS objects
"no-native-reassign": 2,
// No (!foo in bar)
"no-negated-in-lhs": 2,
// Nested ternary statements are confusing
"no-nested-ternary": 2,
// Use {} instead of new Object()
"no-new-object": 2,
// No Math() or JSON()
"no-obj-calls": 2,
// No octal literals
"no-octal": 2,
// No redeclaring variables
"no-redeclare": 2,
// No unnecessary comparisons
"no-self-compare": 2,
// No declaring variables from an outer scope
"no-shadow": 1,
// No declaring variables that hide things like arguments
"no-shadow-restricted-names": 2,
// No spaces between function name and parentheses
"no-spaced-func": 1,
// No trailing whitespace
"no-trailing-spaces": 2,
// No using undeclared variables
"no-undef": 2,
// Error on newline where a semicolon is needed
"no-unexpected-multiline": 2,
// No unreachable statements
"no-unreachable": 2,
// No expressions where a statement is expected
"no-unused-expressions": 2,
// No declaring variables that are never used
"no-unused-vars": [2, { "args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$" }],
// No using variables before defined
"no-use-before-define": 2,
// No using with
"no-with": 2,
// Always require semicolon at end of statement
"semi": [2, "always"],
// Require space after keywords
"space-after-keywords": 2,
// Require space before blocks
"space-before-blocks": 2,
// Never use spaces before function parentheses
"space-before-function-paren": [2, { "anonymous": "never", "named": "never" }],
// Require spaces before finally, catch, etc.
"space-before-keywords": [2, "always"],
// No space padding in parentheses
"space-in-parens": [2, "never"],
// Require spaces around operators, except for a|0.
"space-infix-ops": [2, {"int32Hint": true}],
// Require spaces after return, throw and case
"space-return-throw-case": 2,
// ++ and -- should not need spacing
"space-unary-ops": [1, { "nonwords": false }],
// No comparisons to NaN
"use-isnan": 2,
// Only check typeof against valid results
"valid-typeof": 2,
// Disallow using variables outside the blocks they are defined (especially
// since only let and const are used, see "no-var").
"block-scoped-var": 2,
// Allow trailing commas for easy list extension. Having them does not
// impair readability, but also not required either.
"comma-dangle": [1, "always-multiline"],
// Warn about cyclomatic complexity in functions.
"complexity": 1,
// Don't warn for inconsistent naming when capturing this (not so important
// with auto-binding fat arrow functions).
// "consistent-this": [2, "self"],
// Don't require a default case in switch statements. Avoid being forced to
// add a bogus default when you know all possible cases are handled.
"default-case": 0,
// Enforce dots on the next line with property name.
"dot-location": [1, "property"],
// Encourage the use of dot notation whenever possible.
"dot-notation": 2,
// Allow using == instead of ===, in the interest of landing something since
// the devtools codebase is split on convention here.
"eqeqeq": 0,
// Don't require function expressions to have a name.
// This makes the code more verbose and hard to read. Our engine already
// does a fantastic job assigning a name to the function, which includes
// the enclosing function name, and worst case you have a line number that
// you can just look up.
"func-names": 0,
// Allow use of function declarations and expressions.
"func-style": 0,
// Don't enforce the maximum depth that blocks can be nested. The complexity
// rule is a better rule to check this.
"max-depth": 0,
// Maximum length of a line.
// Disabled because we exceed this in too many places.
"max-len": [0, 80],
// Maximum depth callbacks can be nested.
"max-nested-callbacks": [2, 4],
// Don't limit the number of parameters that can be used in a function.
"max-params": 0,
// Don't limit the maximum number of statement allowed in a function. We
// already have the complexity rule that's a better measurement.
"max-statements": 0,
// Don't require a capital letter for constructors, only check if all new
// operators are followed by a capital letter. Don't warn when capitalized
// functions are used without the new operator.
"new-cap": [0, {"capIsNew": false}],
// Allow use of bitwise operators.
"no-bitwise": 0,
// Disallow use of arguments.caller or arguments.callee.
"no-caller": 2,
// Disallow the catch clause parameter name being the same as a variable in
// the outer scope, to avoid confusion.
"no-catch-shadow": 0,
// Disallow assignment in conditional expressions.
"no-cond-assign": 2,
// Disallow using the console API.
"no-console": 2,
// Allow using constant expressions in conditions like while (true)
"no-constant-condition": 0,
// Allow use of the continue statement.
"no-continue": 0,
// Disallow control characters in regular expressions.
"no-control-regex": 2,
// Disallow use of debugger.
"no-debugger": 2,
// Disallow deletion of variables (deleting properties is fine).
"no-delete-var": 2,
// Allow division operators explicitly at beginning of regular expression.
"no-div-regex": 0,
// Disallow use of labels for anything other then loops and switches.
"no-empty-label": 2,
// Disallow use of eval(). We have other APIs to evaluate code in content.
"no-eval": 2,
// Disallow adding to native types
"no-extend-native": 2,
// Disallow unnecessary function binding.
"no-extra-bind": 2,
// Allow unnecessary parentheses, as they may make the code more readable.
"no-extra-parens": 0,
// Disallow fallthrough of case statements, except if there is a comment.
"no-fallthrough": 2,
// Allow the use of leading or trailing decimal points in numeric literals.
"no-floating-decimal": 0,
// Allow comments inline after code.
"no-inline-comments": 0,
// Disallow use of multiline strings (use template strings instead).
"no-multi-str": 1,
// Disallow multiple empty lines.
"no-multiple-empty-lines": [1, {"max": 2}],
// Allow reassignment of function parameters.
"no-param-reassign": 0,
// Allow string concatenation with __dirname and __filename (not a node env).
"no-path-concat": 0,
// Allow use of unary operators, ++ and --.
"no-plusplus": 0,
// Allow using process.env (not a node environment).
"no-process-env": 0,
// Allow using process.exit (not a node environment).
"no-process-exit": 0,
// Disallow usage of __proto__ property.
"no-proto": 2,
// Disallow multiple spaces in a regular expression literal.
"no-regex-spaces": 2,
// Allow reserved words being used as object literal keys.
"no-reserved-keys": 0,
// Don't restrict usage of specified node modules (not a node environment).
"no-restricted-modules": 0,
// Disallow use of assignment in return statement. It is preferable for a
// single line of code to have only one easily predictable effect.
"no-return-assign": 2,
// Don't warn about declaration of variables already declared in the outer scope.
"no-shadow": 0,
// Disallow shadowing of names such as arguments.
"no-shadow-restricted-names": 2,
// Allow use of synchronous methods (not a node environment).
"no-sync": 0,
// Allow the use of ternary operators.
"no-ternary": 0,
// Disallow throwing literals (eg. throw "error" instead of
// throw new Error("error")).
"no-throw-literal": 2,
// Disallow use of undeclared variables unless mentioned in a /* global */
// block. Note that globals from head.js are automatically imported in tests
// by the import-headjs-globals rule form the mozilla eslint plugin.
"no-undef": 2,
// Allow dangling underscores in identifiers (for privates).
"no-underscore-dangle": 0,
// Allow use of undefined variable.
"no-undefined": 0,
// Disallow the use of Boolean literals in conditional expressions.
"no-unneeded-ternary": 2,
// We use var-only-at-top-level instead of no-var as we allow top level
// vars.
"no-var": 0,
// Allow using TODO/FIXME comments.
"no-warning-comments": 0,
// Don't require method and property shorthand syntax for object literals.
// We use this in the code a lot, but not consistently, and this seems more
// like something to check at code review time.
"object-shorthand": 0,
// Allow more than one variable declaration per function.
"one-var": 0,
// Disallow padding within blocks.
"padded-blocks": [1, "never"],
// Don't require quotes around object literal property names.
"quote-props": 0,
// Double quotes should be used.
"quotes": [1, "double", "avoid-escape"],
// Require use of the second argument for parseInt().
"radix": 2,
// Enforce spacing after semicolons.
"semi-spacing": [2, {"before": false, "after": true}],
// Don't require to sort variables within the same declaration block.
// Anyway, one-var is disabled.
"sort-vars": 0,
// Require a space after keywords.
"space-after-keywords": [1, "always"],
// Require a space immediately following the // in a line comment.
"spaced-comment": [2, "always"],
// Require "use strict" to be defined globally in the script.
"strict": [2, "global"],
// Warn about invalid JSDoc comments.
"valid-jsdoc": 0,
// Allow vars to be declared anywhere in the scope.
"vars-on-top": 0,
// Don't require immediate function invocation to be wrapped in parentheses.
"wrap-iife": 0,
// Don't require regex literals to be wrapped in parentheses (which
// supposedly prevent them from being mistaken for division operators).
"wrap-regex": 0,
// Disallow Yoda conditions (where literal value comes first).
"yoda": 2,
// disallow use of eval()-like methods
"no-implied-eval": 2,
// Disallow function or variable declarations in nested blocks
"no-inner-declarations": 2,
// Disallow usage of __iterator__ property
"no-iterator": 2,
// Disallow labels that share a name with a variable
"no-label-var": 2,
// Disallow negation of the left operand of an in expression
"no-negated-in-lhs": 2,
// Disallow creating new instances of String, Number, and Boolean
"no-new-wrappers": 2,
}
}

Просмотреть файл

@ -6,6 +6,8 @@
this.EXPORTED_SYMBOLS = ["Extension", "ExtensionData"];
/* globals Extension ExtensionData */
/*
* This file is the main entry point for extensions. When an extension
* loads, its bootstrap.js file creates a Extension instance
@ -21,8 +23,9 @@ const Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource://devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
"resource://gre/modules/Locale.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Log",
@ -67,13 +70,14 @@ var {
injectAPI,
extend,
flushJarCache,
instanceOf,
} = ExtensionUtils;
const LOGGER_ID_BASE = "addons.webextension.";
var scriptScope = this;
var ExtensionPage, GlobalManager;
// This object loads the ext-*.js scripts that define the extension API.
var Management = {
initialized: false,
@ -165,7 +169,7 @@ var Management = {
off(hook, callback) {
this.emitter.off(hook, callback);
}
},
};
// A MessageBroker that's used to send and receive messages for
@ -183,9 +187,8 @@ var globalBroker = new MessageBroker([Services.mm, Services.ppmm]);
// |uri| is the URI of the content (optional).
// |docShell| is the docshell the content runs in (optional).
// |incognito| is the content running in a private context (default: false).
function ExtensionPage(extension, params)
{
let {type, contentWindow, uri, docShell} = params;
ExtensionPage = function(extension, params) {
let {type, contentWindow, uri} = params;
this.extension = extension;
this.type = type;
this.contentWindow = contentWindow || null;
@ -206,7 +209,7 @@ function ExtensionPage(extension, params)
this.messenger = new Messenger(this, globalBroker, sender, filter, delegate);
this.extension.views.add(this);
}
};
ExtensionPage.prototype = {
get cloneScope() {
@ -264,7 +267,7 @@ ExtensionPage.prototype = {
};
// Responsible for loading extension APIs into the right globals.
var GlobalManager = {
GlobalManager = {
// Number of extensions currently enabled.
count: 0,
@ -365,8 +368,7 @@ var GlobalManager = {
//
// No functionality of this class is guaranteed to work before
// |readManifest| has been called, and completed.
this.ExtensionData = function(rootURI)
{
this.ExtensionData = function(rootURI) {
this.rootURI = rootURI;
this.manifest = null;
@ -375,7 +377,7 @@ this.ExtensionData = function(rootURI)
this._promiseLocales = null;
this.errors = [];
}
};
ExtensionData.prototype = {
get logger() {
@ -406,11 +408,12 @@ ExtensionData.prototype = {
yield iter.forEach(entry => {
results.push(entry);
});
} catch (e) {}
} catch (e) {
// Always return a list, even if the directory does not exist (or is
// not a directory) for symmetry with the ZipReader behavior.
}
iter.close();
// Always return a list, even if the directory does not exist (or is
// not a directory) for symmetry with the ZipReader behavior.
return results;
}
@ -488,7 +491,9 @@ ExtensionData.prototype = {
try {
this.id = this.manifest.applications.gecko.id;
} catch (e) {}
} catch (e) {
// Errors are handled by the type check below.
}
if (typeof this.id != "string") {
this.manifestError("Missing required `applications.gecko.id` property");
@ -626,8 +631,7 @@ ExtensionData.prototype = {
// installed (by trying to load a moz-extension URI referring to a
// web_accessible_resource from the extension). getExtensionUUID
// returns the UUID for a given add-on ID.
function getExtensionUUID(id)
{
function getExtensionUUID(id) {
const PREF_NAME = "extensions.webextensions.uuids";
let pref = Preferences.get(PREF_NAME, "{}");
@ -653,8 +657,7 @@ function getExtensionUUID(id)
// We create one instance of this class per extension. |addonData|
// comes directly from bootstrap.js when initializing.
this.Extension = function(addonData)
{
this.Extension = function(addonData) {
ExtensionData.call(this, addonData.resourceURI);
this.uuid = getExtensionUUID(addonData.id);
@ -683,7 +686,7 @@ this.Extension = function(addonData)
this.webAccessibleResources = new Set();
this.emitter = new EventEmitter();
}
};
/**
* This code is designed to make it easy to test a WebExtension
@ -710,8 +713,7 @@ this.Extension = function(addonData)
* The generated extension is stored in the system temporary directory,
* and an nsIFile object pointing to it is returned.
*/
this.Extension.generateXPI = function(id, data)
{
this.Extension.generateXPI = function(id, data) {
let manifest = data.manifest;
if (!manifest) {
manifest = {};
@ -799,8 +801,7 @@ this.Extension.generateXPI = function(id, data)
* Generates a new extension using |Extension.generateXPI|, and initializes a
* new |Extension| instance which will execute it.
*/
this.Extension.generate = function(id, data)
{
this.Extension.generate = function(id, data) {
let file = this.generateXPI(id, data);
flushJarCache(file);
@ -812,7 +813,7 @@ this.Extension.generate = function(id, data)
return new Extension({
id,
resourceURI: jarURI,
cleanupFile: file
cleanupFile: file,
});
};
@ -856,7 +857,7 @@ Extension.prototype = extend(Object.create(ExtensionData.prototype), {
manifest: this.manifest,
resourceURL: this.addonData.resourceURI.spec,
baseURL: this.baseURI.spec,
content_scripts: this.manifest.content_scripts || [],
content_scripts: this.manifest.content_scripts || [], // eslint-disable-line camelcase
webAccessibleResources: this.webAccessibleResources,
whiteListedHosts: this.whiteListedHosts.serialize(),
localeData: this.localeData.serialize(),

Просмотреть файл

@ -6,6 +6,8 @@
this.EXPORTED_SYMBOLS = ["ExtensionContent"];
/* globals ExtensionContent */
/*
* This file handles the content process side of extensions. It mainly
* takes care of content script injection, content script APIs, and
@ -38,8 +40,7 @@ var {
flushJarCache,
} = ExtensionUtils;
function isWhenBeforeOrSame(when1, when2)
{
function isWhenBeforeOrSame(when1, when2) {
let table = {"document_start": 0,
"document_end": 1,
"document_idle": 2};
@ -48,63 +49,65 @@ function isWhenBeforeOrSame(when1, when2)
// This is the fairly simple API that we inject into content
// scripts.
var api = context => { return {
runtime: {
connect: function(extensionId, connectInfo) {
if (!connectInfo) {
connectInfo = extensionId;
extensionId = null;
}
let name = connectInfo && connectInfo.name || "";
let recipient = extensionId ? {extensionId} : {extensionId: context.extensionId};
return context.messenger.connect(context.messageManager, name, recipient);
var api = context => {
return {
runtime: {
connect: function(extensionId, connectInfo) {
if (!connectInfo) {
connectInfo = extensionId;
extensionId = null;
}
let name = connectInfo && connectInfo.name || "";
let recipient = extensionId ? {extensionId} : {extensionId: context.extensionId};
return context.messenger.connect(context.messageManager, name, recipient);
},
getManifest: function() {
return Cu.cloneInto(context.extension.manifest, context.cloneScope);
},
getURL: function(url) {
return context.extension.baseURI.resolve(url);
},
onConnect: context.messenger.onConnect("runtime.onConnect"),
onMessage: context.messenger.onMessage("runtime.onMessage"),
sendMessage: function(...args) {
let options; // eslint-disable-line no-unused-vars
let extensionId, message, responseCallback;
if (args.length == 1) {
message = args[0];
} else if (args.length == 2) {
[message, responseCallback] = args;
} else {
[extensionId, message, options, responseCallback] = args;
}
let recipient = extensionId ? {extensionId} : {extensionId: context.extensionId};
context.messenger.sendMessage(context.messageManager, message, recipient, responseCallback);
},
},
getManifest: function() {
return Cu.cloneInto(context.extension.manifest, context.cloneScope);
extension: {
getURL: function(url) {
return context.extension.baseURI.resolve(url);
},
inIncognitoContext: PrivateBrowsingUtils.isContentWindowPrivate(context.contentWindow),
},
getURL: function(url) {
return context.extension.baseURI.resolve(url);
i18n: {
getMessage: function(messageName, substitutions) {
return context.extension.localizeMessage(messageName, substitutions);
},
},
onConnect: context.messenger.onConnect("runtime.onConnect"),
onMessage: context.messenger.onMessage("runtime.onMessage"),
sendMessage: function(...args) {
let extensionId, message, options, responseCallback;
if (args.length == 1) {
message = args[0];
} else if (args.length == 2) {
[message, responseCallback] = args;
} else {
[extensionId, message, options, responseCallback] = args;
}
let recipient = extensionId ? {extensionId} : {extensionId: context.extensionId};
context.messenger.sendMessage(context.messageManager, message, recipient, responseCallback);
},
},
extension: {
getURL: function(url) {
return context.extension.baseURI.resolve(url);
},
inIncognitoContext: PrivateBrowsingUtils.isContentWindowPrivate(context.contentWindow),
},
i18n: {
getMessage: function(messageName, substitutions) {
return context.extension.localizeMessage(messageName, substitutions);
},
},
}};
};
};
// Represents a content script.
function Script(options)
{
function Script(options) {
this.options = options;
this.run_at = this.options.run_at;
this.js = this.options.js || [];
@ -155,8 +158,8 @@ Script.prototype = {
}
if (shouldRun("document_start")) {
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
for (let url of this.css) {
url = extension.baseURI.resolve(url);
@ -183,8 +186,8 @@ Script.prototype = {
let options = {
target: sandbox,
charset: "UTF-8",
async: AppConstants.platform == "gonk"
}
async: AppConstants.platform == "gonk",
};
runSafeSyncWithoutClone(Services.scriptloader.loadSubScriptWithOptions, url, options);
}
@ -195,8 +198,7 @@ Script.prototype = {
},
};
function getWindowMessageManager(contentWindow)
{
function getWindowMessageManager(contentWindow) {
let ir = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor);
@ -208,11 +210,12 @@ function getWindowMessageManager(contentWindow)
}
}
var ExtensionManager;
// Scope in which extension content script code can run. It uses
// Cu.Sandbox to run the code. There is a separate scope for each
// frame.
function ExtensionContext(extensionId, contentWindow)
{
function ExtensionContext(extensionId, contentWindow) {
this.extension = ExtensionManager.get(extensionId);
this.extensionId = extensionId;
this.contentWindow = contentWindow;
@ -239,7 +242,7 @@ function ExtensionContext(extensionId, contentWindow)
let delegate = {
getSender(context, target, sender) {
// Nothing to do here.
}
},
};
let url = contentWindow.location.href;
@ -280,8 +283,7 @@ ExtensionContext.prototype = {
},
};
function windowId(window)
{
function windowId(window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
@ -332,8 +334,10 @@ var DocumentManager = {
}
this.trigger("document_start", window);
/* eslint-disable mozilla/balanced-listeners */
window.addEventListener("DOMContentLoaded", this, true);
window.addEventListener("load", this, true);
/* eslint-enable mozilla/balanced-listeners */
} else if (topic == "inner-window-destroyed") {
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (!this.windows.has(id)) {
@ -341,7 +345,7 @@ var DocumentManager = {
}
let extensions = this.windows.get(id);
for (let [extensionId, context] of extensions) {
for (let [, context] of extensions) {
context.close();
}
@ -385,7 +389,7 @@ var DocumentManager = {
enumerateWindows: function*(docShell) {
let window = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.getInterface(Ci.nsIDOMWindow);
yield [window, this.getWindowState(window)];
for (let i = 0; i < docShell.childCount; i++) {
@ -430,7 +434,7 @@ var DocumentManager = {
},
shutdownExtension(extensionId) {
for (let [windowId, extensions] of this.windows) {
for (let [, extensions] of this.windows) {
let context = extensions.get(extensionId);
if (context) {
context.close();
@ -458,8 +462,7 @@ var DocumentManager = {
};
// Represents a browser extension in the content process.
function BrowserExtensionContent(data)
{
function BrowserExtensionContent(data) {
this.id = data.id;
this.uuid = data.uuid;
this.data = data;
@ -478,7 +481,7 @@ function BrowserExtensionContent(data)
// Extension.jsm takes care of this in the parent.
ExtensionManagement.startupExtension(this.uuid, uri, this);
}
};
}
BrowserExtensionContent.prototype = {
shutdown() {
@ -496,7 +499,7 @@ BrowserExtensionContent.prototype = {
},
};
var ExtensionManager = {
ExtensionManager = {
// Map[extensionId, BrowserExtensionContent]
extensions: new Map(),
@ -546,7 +549,7 @@ var ExtensionManager = {
break;
}
}
}
},
};
this.ExtensionContent = {
@ -581,11 +584,11 @@ this.ExtensionContent = {
receiveMessage({target, name, data}) {
switch (name) {
case "Extension:Execute":
let script = new Script(data.options);
let {extensionId} = data;
DocumentManager.executeScript(target, extensionId, script);
break;
case "Extension:Execute":
let script = new Script(data.options);
let {extensionId} = data;
DocumentManager.executeScript(target, extensionId, script);
break;
}
},
};

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше