530 lines
18 KiB
Python
530 lines
18 KiB
Python
# 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 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 {
|
|
"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,
|
|
}.items()
|
|
}
|
|
)
|
|
|
|
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 RESULT_FLAT.items()
|
|
if p.startswith("addon1/")
|
|
},
|
|
"app/chrome/addons/addon2.xpi": {
|
|
mozpath.relpath(p, "app/chrome/addons/addon2"): f
|
|
for p, f in RESULT_FLAT.items()
|
|
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 RESULT_FLAT.keys()
|
|
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 CONTENTS["bases"].items()
|
|
},
|
|
"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 CONTENTS["files"].items()},
|
|
}
|
|
|
|
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 results.items()}
|
|
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(contents["files"].items()):
|
|
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] = v.open().read().decode().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, "default.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()
|