# 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()