Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

# 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/.
import unittest
from itertools import chain
import mozunit
import six
import mozpack.path as mozpath
from mozpack.chrome.manifest import (
ManifestBinaryComponent,
ManifestComponent,
ManifestContent,
ManifestLocale,
ManifestResource,
ManifestSkin,
)
from mozpack.copier import FileRegistry
from mozpack.errors import ErrorMessage
from mozpack.files import GeneratedFile, ManifestFile
from mozpack.packager.formats import FlatFormatter, JarFormatter, OmniJarFormatter
from mozpack.test.test_files import bar_xpt, foo2_xpt, foo_xpt
from test_errors import TestErrors
CONTENTS = {
"bases": {
# base_path: is_addon?
"": False,
"app": False,
"addon0": "unpacked",
"addon1": True,
"app/chrome/addons/addon2": True,
},
"manifests": [
ManifestContent("chrome/f", "oo", "oo/"),
ManifestContent("chrome/f", "bar", "oo/bar/"),
ManifestResource("chrome/f", "foo", "resource://bar/"),
ManifestBinaryComponent("components", "foo.so"),
ManifestContent("app/chrome", "content", "foo/"),
ManifestComponent("app/components", "{foo-id}", "foo.js"),
ManifestContent("addon0/chrome", "addon0", "foo/bar/"),
ManifestContent("addon1/chrome", "addon1", "foo/bar/"),
ManifestContent("app/chrome/addons/addon2/chrome", "addon2", "foo/bar/"),
],
"files": {
"chrome/f/oo/bar/baz": GeneratedFile(b"foobarbaz"),
"chrome/f/oo/baz": GeneratedFile(b"foobaz"),
"chrome/f/oo/qux": GeneratedFile(b"fooqux"),
"components/foo.so": GeneratedFile(b"foo.so"),
"components/foo.xpt": foo_xpt,
"components/bar.xpt": bar_xpt,
"foo": GeneratedFile(b"foo"),
"app/chrome/foo/foo": GeneratedFile(b"appfoo"),
"app/components/foo.js": GeneratedFile(b"foo.js"),
"addon0/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
"addon0/components/foo.xpt": foo2_xpt,
"addon0/components/bar.xpt": bar_xpt,
"addon1/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
"addon1/components/foo.xpt": foo2_xpt,
"addon1/components/bar.xpt": bar_xpt,
"app/chrome/addons/addon2/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
"app/chrome/addons/addon2/components/foo.xpt": foo2_xpt,
"app/chrome/addons/addon2/components/bar.xpt": bar_xpt,
},
}
FILES = CONTENTS["files"]
RESULT_FLAT = {
"chrome.manifest": [
"manifest chrome/chrome.manifest",
"manifest components/components.manifest",
],
"chrome/chrome.manifest": [
"manifest f/f.manifest",
],
"chrome/f/f.manifest": [
"content oo oo/",
"content bar oo/bar/",
"resource foo resource://bar/",
],
"chrome/f/oo/bar/baz": FILES["chrome/f/oo/bar/baz"],
"chrome/f/oo/baz": FILES["chrome/f/oo/baz"],
"chrome/f/oo/qux": FILES["chrome/f/oo/qux"],
"components/components.manifest": [
"binary-component foo.so",
"interfaces bar.xpt",
"interfaces foo.xpt",
],
"components/foo.so": FILES["components/foo.so"],
"components/foo.xpt": foo_xpt,
"components/bar.xpt": bar_xpt,
"foo": FILES["foo"],
"app/chrome.manifest": [
"manifest chrome/chrome.manifest",
"manifest components/components.manifest",
],
"app/chrome/chrome.manifest": [
"content content foo/",
],
"app/chrome/foo/foo": FILES["app/chrome/foo/foo"],
"app/components/components.manifest": [
"component {foo-id} foo.js",
],
"app/components/foo.js": FILES["app/components/foo.js"],
}
for addon in ("addon0", "addon1", "app/chrome/addons/addon2"):
RESULT_FLAT.update(
{
mozpath.join(addon, p): f
for p, f in six.iteritems(
{
"chrome.manifest": [
"manifest chrome/chrome.manifest",
"manifest components/components.manifest",
],
"chrome/chrome.manifest": [
"content %s foo/bar/" % mozpath.basename(addon),
],
"chrome/foo/bar/baz": FILES[
mozpath.join(addon, "chrome/foo/bar/baz")
],
"components/components.manifest": [
"interfaces bar.xpt",
"interfaces foo.xpt",
],
"components/bar.xpt": bar_xpt,
"components/foo.xpt": foo2_xpt,
}
)
}
)
RESULT_JAR = {
p: RESULT_FLAT[p]
for p in (
"chrome.manifest",
"chrome/chrome.manifest",
"components/components.manifest",
"components/foo.so",
"components/foo.xpt",
"components/bar.xpt",
"foo",
"app/chrome.manifest",
"app/components/components.manifest",
"app/components/foo.js",
"addon0/chrome.manifest",
"addon0/components/components.manifest",
"addon0/components/foo.xpt",
"addon0/components/bar.xpt",
)
}
RESULT_JAR.update(
{
"chrome/f/f.manifest": [
"content oo jar:oo.jar!/",
"content bar jar:oo.jar!/bar/",
"resource foo resource://bar/",
],
"chrome/f/oo.jar": {
"bar/baz": FILES["chrome/f/oo/bar/baz"],
"baz": FILES["chrome/f/oo/baz"],
"qux": FILES["chrome/f/oo/qux"],
},
"app/chrome/chrome.manifest": [
"content content jar:foo.jar!/",
],
"app/chrome/foo.jar": {
"foo": FILES["app/chrome/foo/foo"],
},
"addon0/chrome/chrome.manifest": [
"content addon0 jar:foo.jar!/bar/",
],
"addon0/chrome/foo.jar": {
"bar/baz": FILES["addon0/chrome/foo/bar/baz"],
},
"addon1.xpi": {
mozpath.relpath(p, "addon1"): f
for p, f in six.iteritems(RESULT_FLAT)
if p.startswith("addon1/")
},
"app/chrome/addons/addon2.xpi": {
mozpath.relpath(p, "app/chrome/addons/addon2"): f
for p, f in six.iteritems(RESULT_FLAT)
if p.startswith("app/chrome/addons/addon2/")
},
}
)
RESULT_OMNIJAR = {
p: RESULT_FLAT[p]
for p in (
"components/foo.so",
"foo",
)
}
RESULT_OMNIJAR.update({p: RESULT_JAR[p] for p in RESULT_JAR if p.startswith("addon")})
RESULT_OMNIJAR.update(
{
"omni.foo": {
"components/components.manifest": [
"interfaces bar.xpt",
"interfaces foo.xpt",
],
},
"chrome.manifest": [
"manifest components/components.manifest",
],
"components/components.manifest": [
"binary-component foo.so",
],
"app/omni.foo": {
p: RESULT_FLAT["app/" + p]
for p in chain(
(
"chrome.manifest",
"chrome/chrome.manifest",
"chrome/foo/foo",
"components/components.manifest",
"components/foo.js",
),
(
mozpath.relpath(p, "app")
for p in six.iterkeys(RESULT_FLAT)
if p.startswith("app/chrome/addons/addon2/")
),
)
},
}
)
RESULT_OMNIJAR["omni.foo"].update(
{
p: RESULT_FLAT[p]
for p in (
"chrome.manifest",
"chrome/chrome.manifest",
"chrome/f/f.manifest",
"chrome/f/oo/bar/baz",
"chrome/f/oo/baz",
"chrome/f/oo/qux",
"components/foo.xpt",
"components/bar.xpt",
)
}
)
RESULT_OMNIJAR_WITH_SUBPATH = {
k.replace("omni.foo", "bar/omni.foo"): v for k, v in RESULT_OMNIJAR.items()
}
CONTENTS_WITH_BASE = {
"bases": {
mozpath.join("base/root", b) if b else "base/root": a
for b, a in six.iteritems(CONTENTS["bases"])
},
"manifests": [
m.move(mozpath.join("base/root", m.base)) for m in CONTENTS["manifests"]
],
"files": {
mozpath.join("base/root", p): f for p, f in six.iteritems(CONTENTS["files"])
},
}
EXTRA_CONTENTS = {
"extra/file": GeneratedFile(b"extra file"),
}
CONTENTS_WITH_BASE["files"].update(EXTRA_CONTENTS)
def result_with_base(results):
result = {mozpath.join("base/root", p): v for p, v in six.iteritems(results)}
result.update(EXTRA_CONTENTS)
return result
RESULT_FLAT_WITH_BASE = result_with_base(RESULT_FLAT)
RESULT_JAR_WITH_BASE = result_with_base(RESULT_JAR)
RESULT_OMNIJAR_WITH_BASE = result_with_base(RESULT_OMNIJAR)
def fill_formatter(formatter, contents):
for base, is_addon in sorted(contents["bases"].items()):
formatter.add_base(base, is_addon)
for manifest in contents["manifests"]:
formatter.add_manifest(manifest)
for k, v in sorted(six.iteritems(contents["files"])):
if k.endswith(".xpt"):
formatter.add_interfaces(k, v)
else:
formatter.add(k, v)
def get_contents(registry, read_all=False, mode="rt"):
result = {}
for k, v in registry:
if isinstance(v, FileRegistry):
result[k] = get_contents(v)
elif isinstance(v, ManifestFile) or read_all:
if "b" in mode:
result[k] = v.open().read()
else:
result[k] = six.ensure_text(v.open().read()).splitlines()
else:
result[k] = v
return result
class TestFormatters(TestErrors, unittest.TestCase):
maxDiff = None
def test_bases(self):
formatter = FlatFormatter(FileRegistry())
formatter.add_base("")
formatter.add_base("addon0", addon=True)
formatter.add_base("browser")
self.assertEqual(formatter._get_base("platform.ini"), ("", "platform.ini"))
self.assertEqual(
formatter._get_base("browser/application.ini"),
("browser", "application.ini"),
)
self.assertEqual(
formatter._get_base("addon0/install.rdf"), ("addon0", "install.rdf")
)
def do_test_contents(self, formatter, contents):
for f in contents["files"]:
# .xpt files are merged, so skip them.
if not f.endswith(".xpt"):
self.assertTrue(formatter.contains(f))
def test_flat_formatter(self):
registry = FileRegistry()
formatter = FlatFormatter(registry)
fill_formatter(formatter, CONTENTS)
self.assertEqual(get_contents(registry), RESULT_FLAT)
self.do_test_contents(formatter, CONTENTS)
def test_jar_formatter(self):
registry = FileRegistry()
formatter = JarFormatter(registry)
fill_formatter(formatter, CONTENTS)
self.assertEqual(get_contents(registry), RESULT_JAR)
self.do_test_contents(formatter, CONTENTS)
def test_omnijar_formatter(self):
registry = FileRegistry()
formatter = OmniJarFormatter(registry, "omni.foo")
fill_formatter(formatter, CONTENTS)
self.assertEqual(get_contents(registry), RESULT_OMNIJAR)
self.do_test_contents(formatter, CONTENTS)
def test_flat_formatter_with_base(self):
registry = FileRegistry()
formatter = FlatFormatter(registry)
fill_formatter(formatter, CONTENTS_WITH_BASE)
self.assertEqual(get_contents(registry), RESULT_FLAT_WITH_BASE)
self.do_test_contents(formatter, CONTENTS_WITH_BASE)
def test_jar_formatter_with_base(self):
registry = FileRegistry()
formatter = JarFormatter(registry)
fill_formatter(formatter, CONTENTS_WITH_BASE)
self.assertEqual(get_contents(registry), RESULT_JAR_WITH_BASE)
self.do_test_contents(formatter, CONTENTS_WITH_BASE)
def test_omnijar_formatter_with_base(self):
registry = FileRegistry()
formatter = OmniJarFormatter(registry, "omni.foo")
fill_formatter(formatter, CONTENTS_WITH_BASE)
self.assertEqual(get_contents(registry), RESULT_OMNIJAR_WITH_BASE)
self.do_test_contents(formatter, CONTENTS_WITH_BASE)
def test_omnijar_formatter_with_subpath(self):
registry = FileRegistry()
formatter = OmniJarFormatter(registry, "bar/omni.foo")
fill_formatter(formatter, CONTENTS)
self.assertEqual(get_contents(registry), RESULT_OMNIJAR_WITH_SUBPATH)
self.do_test_contents(formatter, CONTENTS)
def test_omnijar_is_resource(self):
def is_resource(base, path):
registry = FileRegistry()
f = OmniJarFormatter(
registry,
"omni.foo",
non_resources=[
"defaults/messenger/mailViews.dat",
"defaults/foo/*",
"*/dummy",
],
)
f.add_base("")
f.add_base("app")
f.add(mozpath.join(base, path), GeneratedFile(b""))
if f.copier.contains(mozpath.join(base, path)):
return False
self.assertTrue(f.copier.contains(mozpath.join(base, "omni.foo")))
self.assertTrue(f.copier[mozpath.join(base, "omni.foo")].contains(path))
return True
for base in ["", "app/"]:
self.assertTrue(is_resource(base, "chrome"))
self.assertTrue(is_resource(base, "chrome/foo/bar/baz.properties"))
self.assertFalse(is_resource(base, "chrome/icons/foo.png"))
self.assertTrue(is_resource(base, "components/foo.js"))
self.assertFalse(is_resource(base, "components/foo.so"))
self.assertTrue(is_resource(base, "res/foo.css"))
self.assertFalse(is_resource(base, "res/cursors/foo.png"))
self.assertFalse(is_resource(base, "res/MainMenu.nib/foo"))
self.assertTrue(is_resource(base, "defaults/pref/foo.js"))
self.assertFalse(is_resource(base, "defaults/pref/channel-prefs.js"))
self.assertTrue(is_resource(base, "defaults/preferences/foo.js"))
self.assertFalse(is_resource(base, "defaults/preferences/channel-prefs.js"))
self.assertTrue(is_resource(base, "modules/foo.jsm"))
self.assertTrue(is_resource(base, "greprefs.js"))
self.assertTrue(is_resource(base, "hyphenation/foo"))
self.assertTrue(is_resource(base, "update.locale"))
self.assertFalse(is_resource(base, "foo"))
self.assertFalse(is_resource(base, "foo/bar/greprefs.js"))
self.assertTrue(is_resource(base, "defaults/messenger/foo.dat"))
self.assertFalse(is_resource(base, "defaults/messenger/mailViews.dat"))
self.assertTrue(is_resource(base, "defaults/pref/foo.js"))
self.assertFalse(is_resource(base, "defaults/foo/bar.dat"))
self.assertFalse(is_resource(base, "defaults/foo/bar/baz.dat"))
self.assertTrue(is_resource(base, "chrome/foo/bar/baz/dummy_"))
self.assertFalse(is_resource(base, "chrome/foo/bar/baz/dummy"))
self.assertTrue(is_resource(base, "chrome/foo/bar/dummy_"))
self.assertFalse(is_resource(base, "chrome/foo/bar/dummy"))
def test_chrome_override(self):
registry = FileRegistry()
f = FlatFormatter(registry)
f.add_base("")
f.add_manifest(ManifestContent("chrome", "foo", "foo/unix"))
# A more specific entry for a given chrome name can override a more
# generic one.
f.add_manifest(ManifestContent("chrome", "foo", "foo/win", "os=WINNT"))
f.add_manifest(ManifestContent("chrome", "foo", "foo/osx", "os=Darwin"))
# Chrome with the same name overrides the previous registration.
with self.assertRaises(ErrorMessage) as e:
f.add_manifest(ManifestContent("chrome", "foo", "foo/"))
self.assertEqual(
str(e.exception),
'error: "content foo foo/" overrides ' '"content foo foo/unix"',
)
# Chrome with the same name and same flags overrides the previous
# registration.
with self.assertRaises(ErrorMessage) as e:
f.add_manifest(ManifestContent("chrome", "foo", "foo/", "os=WINNT"))
self.assertEqual(
str(e.exception),
'error: "content foo foo/ os=WINNT" overrides '
'"content foo foo/win os=WINNT"',
)
# We may start with the more specific entry first
f.add_manifest(ManifestContent("chrome", "bar", "bar/win", "os=WINNT"))
# Then adding a more generic one overrides it.
with self.assertRaises(ErrorMessage) as e:
f.add_manifest(ManifestContent("chrome", "bar", "bar/unix"))
self.assertEqual(
str(e.exception),
'error: "content bar bar/unix" overrides ' '"content bar bar/win os=WINNT"',
)
# Adding something more specific still works.
f.add_manifest(
ManifestContent("chrome", "bar", "bar/win", "os=WINNT osversion>=7.0")
)
# Variations of skin/locales are allowed.
f.add_manifest(
ManifestSkin("chrome", "foo", "classic/1.0", "foo/skin/classic/")
)
f.add_manifest(ManifestSkin("chrome", "foo", "modern/1.0", "foo/skin/modern/"))
f.add_manifest(ManifestLocale("chrome", "foo", "en-US", "foo/locale/en-US/"))
f.add_manifest(ManifestLocale("chrome", "foo", "ja-JP", "foo/locale/ja-JP/"))
# But same-skin/locale still error out.
with self.assertRaises(ErrorMessage) as e:
f.add_manifest(
ManifestSkin("chrome", "foo", "classic/1.0", "foo/skin/classic/foo")
)
self.assertEqual(
str(e.exception),
'error: "skin foo classic/1.0 foo/skin/classic/foo" overrides '
'"skin foo classic/1.0 foo/skin/classic/"',
)
with self.assertRaises(ErrorMessage) as e:
f.add_manifest(
ManifestLocale("chrome", "foo", "en-US", "foo/locale/en-US/foo")
)
self.assertEqual(
str(e.exception),
'error: "locale foo en-US foo/locale/en-US/foo" overrides '
'"locale foo en-US foo/locale/en-US/"',
)
# Duplicating existing manifest entries is not an error.
f.add_manifest(ManifestContent("chrome", "foo", "foo/unix"))
self.assertEqual(
self.get_output(),
[
'warning: "content foo foo/unix" is duplicated. Skipping.',
],
)
if __name__ == "__main__":
mozunit.main()