Bug 1449055 Make browser_all_files_referenced.js work with formautofill as a webextension r=florian
☠☠ backed out by e01f02f3bb21 ☠ ☠
authorAndrew Swan <aswan@mozilla.com>
Wed, 01 Aug 2018 18:22:23 -0700
changeset 828925 644216b0ad9b5f9e1e9e8f1f930d4db1c6e717a1
parent 828924 ecda6532c852b3f225fce998e3ce83ad157760e6
child 828926 e01f02f3bb217eac0ac24d56bf1dba4e85e342a7
push id118727
push userbmo:rbartlensky@mozilla.com
push dateTue, 14 Aug 2018 10:49:39 +0000
reviewersflorian
bugs1449055
milestone63.0a1
Bug 1449055 Make browser_all_files_referenced.js work with formautofill as a webextension r=florian MozReview-Commit-ID: JV3vA8bmDWt
browser/base/content/test/static/browser_all_files_referenced.js
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -234,23 +234,33 @@ trackResourcePrefix("app");
 
 function getBaseUriForChromeUri(chromeUri) {
   let chromeFile = chromeUri + "gobbledygooknonexistentfile.reallynothere";
   let uri = Services.io.newURI(chromeFile);
   let fileUri = gChromeReg.convertChromeURL(uri);
   return fileUri.resolve(".");
 }
 
+function trackChromeUri(uri) {
+  gChromeMap.set(getBaseUriForChromeUri(uri), uri);
+}
+
+// formautofill registers resource://formautofill/ and
+// chrome://formautofill/content/ dynamically at runtime.
+// Bug 1480276 is about addressing this without this hard-coding.
+trackResourcePrefix("formautofill");
+trackChromeUri("chrome://formautofill/content/");
+
 function parseManifest(manifestUri) {
   return fetchFile(manifestUri.spec).then(data => {
     for (let line of data.split("\n")) {
       let [type, ...argv] = line.split(/\s+/);
       if (type == "content" || type == "skin" || type == "locale") {
         let chromeUri = `chrome://${argv[0]}/${type}/`;
-        gChromeMap.set(getBaseUriForChromeUri(chromeUri), chromeUri);
+        trackChromeUri(chromeUri);
       } else if (type == "override" || type == "overlay") {
         // Overlays aren't really overrides, but behave the same in
         // that the overlay is only referenced if the original xul
         // file is referenced somewhere.
         let os = "os=" + Services.appinfo.OS;
         if (!argv.some(s => s.startsWith("os=") && s != os)) {
           gOverrideMap.set(Services.io.newURI(argv[1]).specIgnoringRef,
                            Services.io.newURI(argv[0]).specIgnoringRef);
@@ -261,16 +271,45 @@ function parseManifest(manifestUri) {
         trackResourcePrefix(argv[0]);
       } else if (type == "component") {
         gComponentsSet.add(argv[1]);
       }
     }
   });
 }
 
+// If the given URI is a webextension manifest, extract the scripts
+// for any embedded APIs.  Returns the passed in URI if the manifest
+// is not a webextension manifest, null otherwise.
+async function parseJsonManifest(uri) {
+  let raw = await fetchFile(uri.spec);
+  let data;
+  try {
+    data = JSON.parse(raw);
+  } catch (ex) {
+    return uri;
+  }
+
+  // Simplistic test for whether this is a webextension manifest:
+  if (data.manifest_version !== 2) {
+    return uri;
+  }
+
+  if (data.experiment_apis) {
+    for (let api of Object.values(data.experiment_apis)) {
+      if (api.parent && api.parent.script) {
+        let script = uri.resolve(api.parent.script);
+        gReferencesFromCode.set(script, null);
+      }
+    }
+  }
+
+  return null;
+}
+
 function addCodeReference(url, fromURI) {
   let from = convertToCodeURI(fromURI.spec);
 
   // Ignore self references.
   if (url == from)
     return;
 
   let ref;
@@ -521,29 +560,42 @@ add_task(async function checkAllTheFiles
   // test infrastructure because it runs against jarfiles there, and
   // our zipreader APIs are all sync)
   let uris = await generateURIsFromDirTree(appDir, [".css", ".manifest", ".jpg", ".png", ".gif", ".svg",  ".dtd", ".properties"].concat(kCodeExtensions));
 
   // Parse and remove all manifests from the list.
   // NOTE that this must be done before filtering out devtools paths
   // so that all chrome paths can be recorded.
   let manifestURIs = [];
+  let jsonManifests = [];
   uris = uris.filter(uri => {
     let path = uri.pathQueryRef;
     if (path.endsWith(".manifest")) {
       manifestURIs.push(uri);
       return false;
+    } else if (path.endsWith("/manifest.json")) {
+      jsonManifests.push(uri);
+      return false;
     }
 
     return true;
   });
 
   // Wait for all manifest to be parsed
   await throttledMapPromises(manifestURIs, parseManifest);
 
+  // manifest.json is a common name, it is used for WebExtension manifests
+  // but also for other things.  To tell them apart, we have to actually
+  // read the contents.  This will populate gExtensionRoots with all
+  // embedded extension APIs, and return any manifest.json files that aren't
+  // webextensions.
+  let nonWebextManifests = (await Promise.all(jsonManifests.map(parseJsonManifest)))
+                                         .filter(uri => !!uri);
+  uris.push(...nonWebextManifests);
+
   // We build a list of promises that get resolved when their respective
   // files have loaded and produced no errors.
   let allPromises = [];
 
   for (let uri of uris) {
     let path = uri.pathQueryRef;
     if (path.endsWith(".css"))
       allPromises.push([parseCSSFile, uri]);