tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_packager_formats.py (18345B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 import unittest
      6 from itertools import chain
      7 
      8 import mozunit
      9 
     10 import mozpack.path as mozpath
     11 from mozpack.chrome.manifest import (
     12    ManifestBinaryComponent,
     13    ManifestComponent,
     14    ManifestContent,
     15    ManifestLocale,
     16    ManifestResource,
     17    ManifestSkin,
     18 )
     19 from mozpack.copier import FileRegistry
     20 from mozpack.errors import ErrorMessage
     21 from mozpack.files import GeneratedFile, ManifestFile
     22 from mozpack.packager.formats import FlatFormatter, JarFormatter, OmniJarFormatter
     23 from mozpack.test.test_files import bar_xpt, foo2_xpt, foo_xpt
     24 from test_errors import TestErrors
     25 
     26 CONTENTS = {
     27    "bases": {
     28        # base_path: is_addon?
     29        "": False,
     30        "app": False,
     31        "addon0": "unpacked",
     32        "addon1": True,
     33        "app/chrome/addons/addon2": True,
     34    },
     35    "manifests": [
     36        ManifestContent("chrome/f", "oo", "oo/"),
     37        ManifestContent("chrome/f", "bar", "oo/bar/"),
     38        ManifestResource("chrome/f", "foo", "resource://bar/"),
     39        ManifestBinaryComponent("components", "foo.so"),
     40        ManifestContent("app/chrome", "content", "foo/"),
     41        ManifestComponent("app/components", "{foo-id}", "foo.js"),
     42        ManifestContent("addon0/chrome", "addon0", "foo/bar/"),
     43        ManifestContent("addon1/chrome", "addon1", "foo/bar/"),
     44        ManifestContent("app/chrome/addons/addon2/chrome", "addon2", "foo/bar/"),
     45    ],
     46    "files": {
     47        "chrome/f/oo/bar/baz": GeneratedFile(b"foobarbaz"),
     48        "chrome/f/oo/baz": GeneratedFile(b"foobaz"),
     49        "chrome/f/oo/qux": GeneratedFile(b"fooqux"),
     50        "components/foo.so": GeneratedFile(b"foo.so"),
     51        "components/foo.xpt": foo_xpt,
     52        "components/bar.xpt": bar_xpt,
     53        "foo": GeneratedFile(b"foo"),
     54        "app/chrome/foo/foo": GeneratedFile(b"appfoo"),
     55        "app/components/foo.js": GeneratedFile(b"foo.js"),
     56        "addon0/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
     57        "addon0/components/foo.xpt": foo2_xpt,
     58        "addon0/components/bar.xpt": bar_xpt,
     59        "addon1/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
     60        "addon1/components/foo.xpt": foo2_xpt,
     61        "addon1/components/bar.xpt": bar_xpt,
     62        "app/chrome/addons/addon2/chrome/foo/bar/baz": GeneratedFile(b"foobarbaz"),
     63        "app/chrome/addons/addon2/components/foo.xpt": foo2_xpt,
     64        "app/chrome/addons/addon2/components/bar.xpt": bar_xpt,
     65    },
     66 }
     67 
     68 FILES = CONTENTS["files"]
     69 
     70 RESULT_FLAT = {
     71    "chrome.manifest": [
     72        "manifest chrome/chrome.manifest",
     73        "manifest components/components.manifest",
     74    ],
     75    "chrome/chrome.manifest": [
     76        "manifest f/f.manifest",
     77    ],
     78    "chrome/f/f.manifest": [
     79        "content oo oo/",
     80        "content bar oo/bar/",
     81        "resource foo resource://bar/",
     82    ],
     83    "chrome/f/oo/bar/baz": FILES["chrome/f/oo/bar/baz"],
     84    "chrome/f/oo/baz": FILES["chrome/f/oo/baz"],
     85    "chrome/f/oo/qux": FILES["chrome/f/oo/qux"],
     86    "components/components.manifest": [
     87        "binary-component foo.so",
     88        "interfaces bar.xpt",
     89        "interfaces foo.xpt",
     90    ],
     91    "components/foo.so": FILES["components/foo.so"],
     92    "components/foo.xpt": foo_xpt,
     93    "components/bar.xpt": bar_xpt,
     94    "foo": FILES["foo"],
     95    "app/chrome.manifest": [
     96        "manifest chrome/chrome.manifest",
     97        "manifest components/components.manifest",
     98    ],
     99    "app/chrome/chrome.manifest": [
    100        "content content foo/",
    101    ],
    102    "app/chrome/foo/foo": FILES["app/chrome/foo/foo"],
    103    "app/components/components.manifest": [
    104        "component {foo-id} foo.js",
    105    ],
    106    "app/components/foo.js": FILES["app/components/foo.js"],
    107 }
    108 
    109 for addon in ("addon0", "addon1", "app/chrome/addons/addon2"):
    110    RESULT_FLAT.update({
    111        mozpath.join(addon, p): f
    112        for p, f in {
    113            "chrome.manifest": [
    114                "manifest chrome/chrome.manifest",
    115                "manifest components/components.manifest",
    116            ],
    117            "chrome/chrome.manifest": ["content %s foo/bar/" % mozpath.basename(addon)],
    118            "chrome/foo/bar/baz": FILES[mozpath.join(addon, "chrome/foo/bar/baz")],
    119            "components/components.manifest": [
    120                "interfaces bar.xpt",
    121                "interfaces foo.xpt",
    122            ],
    123            "components/bar.xpt": bar_xpt,
    124            "components/foo.xpt": foo2_xpt,
    125        }.items()
    126    })
    127 
    128 RESULT_JAR = {
    129    p: RESULT_FLAT[p]
    130    for p in (
    131        "chrome.manifest",
    132        "chrome/chrome.manifest",
    133        "components/components.manifest",
    134        "components/foo.so",
    135        "components/foo.xpt",
    136        "components/bar.xpt",
    137        "foo",
    138        "app/chrome.manifest",
    139        "app/components/components.manifest",
    140        "app/components/foo.js",
    141        "addon0/chrome.manifest",
    142        "addon0/components/components.manifest",
    143        "addon0/components/foo.xpt",
    144        "addon0/components/bar.xpt",
    145    )
    146 }
    147 
    148 RESULT_JAR.update({
    149    "chrome/f/f.manifest": [
    150        "content oo jar:oo.jar!/",
    151        "content bar jar:oo.jar!/bar/",
    152        "resource foo resource://bar/",
    153    ],
    154    "chrome/f/oo.jar": {
    155        "bar/baz": FILES["chrome/f/oo/bar/baz"],
    156        "baz": FILES["chrome/f/oo/baz"],
    157        "qux": FILES["chrome/f/oo/qux"],
    158    },
    159    "app/chrome/chrome.manifest": [
    160        "content content jar:foo.jar!/",
    161    ],
    162    "app/chrome/foo.jar": {
    163        "foo": FILES["app/chrome/foo/foo"],
    164    },
    165    "addon0/chrome/chrome.manifest": [
    166        "content addon0 jar:foo.jar!/bar/",
    167    ],
    168    "addon0/chrome/foo.jar": {
    169        "bar/baz": FILES["addon0/chrome/foo/bar/baz"],
    170    },
    171    "addon1.xpi": {
    172        mozpath.relpath(p, "addon1"): f
    173        for p, f in RESULT_FLAT.items()
    174        if p.startswith("addon1/")
    175    },
    176    "app/chrome/addons/addon2.xpi": {
    177        mozpath.relpath(p, "app/chrome/addons/addon2"): f
    178        for p, f in RESULT_FLAT.items()
    179        if p.startswith("app/chrome/addons/addon2/")
    180    },
    181 })
    182 
    183 RESULT_OMNIJAR = {
    184    p: RESULT_FLAT[p]
    185    for p in (
    186        "components/foo.so",
    187        "foo",
    188    )
    189 }
    190 
    191 RESULT_OMNIJAR.update({p: RESULT_JAR[p] for p in RESULT_JAR if p.startswith("addon")})
    192 
    193 RESULT_OMNIJAR.update({
    194    "omni.foo": {
    195        "components/components.manifest": [
    196            "interfaces bar.xpt",
    197            "interfaces foo.xpt",
    198        ],
    199    },
    200    "chrome.manifest": [
    201        "manifest components/components.manifest",
    202    ],
    203    "components/components.manifest": [
    204        "binary-component foo.so",
    205    ],
    206    "app/omni.foo": {
    207        p: RESULT_FLAT["app/" + p]
    208        for p in chain(
    209            (
    210                "chrome.manifest",
    211                "chrome/chrome.manifest",
    212                "chrome/foo/foo",
    213                "components/components.manifest",
    214                "components/foo.js",
    215            ),
    216            (
    217                mozpath.relpath(p, "app")
    218                for p in RESULT_FLAT.keys()
    219                if p.startswith("app/chrome/addons/addon2/")
    220            ),
    221        )
    222    },
    223 })
    224 
    225 RESULT_OMNIJAR["omni.foo"].update({
    226    p: RESULT_FLAT[p]
    227    for p in (
    228        "chrome.manifest",
    229        "chrome/chrome.manifest",
    230        "chrome/f/f.manifest",
    231        "chrome/f/oo/bar/baz",
    232        "chrome/f/oo/baz",
    233        "chrome/f/oo/qux",
    234        "components/foo.xpt",
    235        "components/bar.xpt",
    236    )
    237 })
    238 
    239 RESULT_OMNIJAR_WITH_SUBPATH = {
    240    k.replace("omni.foo", "bar/omni.foo"): v for k, v in RESULT_OMNIJAR.items()
    241 }
    242 
    243 CONTENTS_WITH_BASE = {
    244    "bases": {
    245        mozpath.join("base/root", b) if b else "base/root": a
    246        for b, a in CONTENTS["bases"].items()
    247    },
    248    "manifests": [
    249        m.move(mozpath.join("base/root", m.base)) for m in CONTENTS["manifests"]
    250    ],
    251    "files": {mozpath.join("base/root", p): f for p, f in CONTENTS["files"].items()},
    252 }
    253 
    254 EXTRA_CONTENTS = {
    255    "extra/file": GeneratedFile(b"extra file"),
    256 }
    257 
    258 CONTENTS_WITH_BASE["files"].update(EXTRA_CONTENTS)
    259 
    260 
    261 def result_with_base(results):
    262    result = {mozpath.join("base/root", p): v for p, v in results.items()}
    263    result.update(EXTRA_CONTENTS)
    264    return result
    265 
    266 
    267 RESULT_FLAT_WITH_BASE = result_with_base(RESULT_FLAT)
    268 RESULT_JAR_WITH_BASE = result_with_base(RESULT_JAR)
    269 RESULT_OMNIJAR_WITH_BASE = result_with_base(RESULT_OMNIJAR)
    270 
    271 
    272 def fill_formatter(formatter, contents):
    273    for base, is_addon in sorted(contents["bases"].items()):
    274        formatter.add_base(base, is_addon)
    275 
    276    for manifest in contents["manifests"]:
    277        formatter.add_manifest(manifest)
    278 
    279    for k, v in sorted(contents["files"].items()):
    280        if k.endswith(".xpt"):
    281            formatter.add_interfaces(k, v)
    282        else:
    283            formatter.add(k, v)
    284 
    285 
    286 def get_contents(registry, read_all=False, mode="rt"):
    287    result = {}
    288    for k, v in registry:
    289        if isinstance(v, FileRegistry):
    290            result[k] = get_contents(v)
    291        elif isinstance(v, ManifestFile) or read_all:
    292            if "b" in mode:
    293                result[k] = v.open().read()
    294            else:
    295                result[k] = v.open().read().decode().splitlines()
    296        else:
    297            result[k] = v
    298    return result
    299 
    300 
    301 class TestFormatters(TestErrors, unittest.TestCase):
    302    maxDiff = None
    303 
    304    def test_bases(self):
    305        formatter = FlatFormatter(FileRegistry())
    306        formatter.add_base("")
    307        formatter.add_base("addon0", addon=True)
    308        formatter.add_base("browser")
    309        self.assertEqual(formatter._get_base("platform.ini"), ("", "platform.ini"))
    310        self.assertEqual(
    311            formatter._get_base("browser/application.ini"),
    312            ("browser", "application.ini"),
    313        )
    314        self.assertEqual(
    315            formatter._get_base("addon0/install.rdf"), ("addon0", "install.rdf")
    316        )
    317 
    318    def do_test_contents(self, formatter, contents):
    319        for f in contents["files"]:
    320            # .xpt files are merged, so skip them.
    321            if not f.endswith(".xpt"):
    322                self.assertTrue(formatter.contains(f))
    323 
    324    def test_flat_formatter(self):
    325        registry = FileRegistry()
    326        formatter = FlatFormatter(registry)
    327 
    328        fill_formatter(formatter, CONTENTS)
    329        self.assertEqual(get_contents(registry), RESULT_FLAT)
    330        self.do_test_contents(formatter, CONTENTS)
    331 
    332    def test_jar_formatter(self):
    333        registry = FileRegistry()
    334        formatter = JarFormatter(registry)
    335 
    336        fill_formatter(formatter, CONTENTS)
    337        self.assertEqual(get_contents(registry), RESULT_JAR)
    338        self.do_test_contents(formatter, CONTENTS)
    339 
    340    def test_omnijar_formatter(self):
    341        registry = FileRegistry()
    342        formatter = OmniJarFormatter(registry, "omni.foo")
    343 
    344        fill_formatter(formatter, CONTENTS)
    345        self.assertEqual(get_contents(registry), RESULT_OMNIJAR)
    346        self.do_test_contents(formatter, CONTENTS)
    347 
    348    def test_flat_formatter_with_base(self):
    349        registry = FileRegistry()
    350        formatter = FlatFormatter(registry)
    351 
    352        fill_formatter(formatter, CONTENTS_WITH_BASE)
    353        self.assertEqual(get_contents(registry), RESULT_FLAT_WITH_BASE)
    354        self.do_test_contents(formatter, CONTENTS_WITH_BASE)
    355 
    356    def test_jar_formatter_with_base(self):
    357        registry = FileRegistry()
    358        formatter = JarFormatter(registry)
    359 
    360        fill_formatter(formatter, CONTENTS_WITH_BASE)
    361        self.assertEqual(get_contents(registry), RESULT_JAR_WITH_BASE)
    362        self.do_test_contents(formatter, CONTENTS_WITH_BASE)
    363 
    364    def test_omnijar_formatter_with_base(self):
    365        registry = FileRegistry()
    366        formatter = OmniJarFormatter(registry, "omni.foo")
    367 
    368        fill_formatter(formatter, CONTENTS_WITH_BASE)
    369        self.assertEqual(get_contents(registry), RESULT_OMNIJAR_WITH_BASE)
    370        self.do_test_contents(formatter, CONTENTS_WITH_BASE)
    371 
    372    def test_omnijar_formatter_with_subpath(self):
    373        registry = FileRegistry()
    374        formatter = OmniJarFormatter(registry, "bar/omni.foo")
    375 
    376        fill_formatter(formatter, CONTENTS)
    377        self.assertEqual(get_contents(registry), RESULT_OMNIJAR_WITH_SUBPATH)
    378        self.do_test_contents(formatter, CONTENTS)
    379 
    380    def test_omnijar_is_resource(self):
    381        def is_resource(base, path):
    382            registry = FileRegistry()
    383            f = OmniJarFormatter(
    384                registry,
    385                "omni.foo",
    386                non_resources=[
    387                    "defaults/messenger/mailViews.dat",
    388                    "defaults/foo/*",
    389                    "*/dummy",
    390                ],
    391            )
    392            f.add_base("")
    393            f.add_base("app")
    394            f.add(mozpath.join(base, path), GeneratedFile(b""))
    395            if f.copier.contains(mozpath.join(base, path)):
    396                return False
    397            self.assertTrue(f.copier.contains(mozpath.join(base, "omni.foo")))
    398            self.assertTrue(f.copier[mozpath.join(base, "omni.foo")].contains(path))
    399            return True
    400 
    401        for base in ["", "app/"]:
    402            self.assertTrue(is_resource(base, "chrome"))
    403            self.assertTrue(is_resource(base, "chrome/foo/bar/baz.properties"))
    404            self.assertFalse(is_resource(base, "chrome/icons/foo.png"))
    405            self.assertTrue(is_resource(base, "components/foo.js"))
    406            self.assertFalse(is_resource(base, "components/foo.so"))
    407            self.assertTrue(is_resource(base, "res/foo.css"))
    408            self.assertFalse(is_resource(base, "res/cursors/foo.png"))
    409            self.assertFalse(is_resource(base, "res/MainMenu.nib/foo"))
    410            self.assertTrue(is_resource(base, "defaults/pref/foo.js"))
    411            self.assertFalse(is_resource(base, "defaults/pref/channel-prefs.js"))
    412            self.assertTrue(is_resource(base, "defaults/preferences/foo.js"))
    413            self.assertFalse(is_resource(base, "defaults/preferences/channel-prefs.js"))
    414            self.assertTrue(is_resource(base, "modules/foo.jsm"))
    415            self.assertTrue(is_resource(base, "greprefs.js"))
    416            self.assertTrue(is_resource(base, "hyphenation/foo"))
    417            self.assertTrue(is_resource(base, "default.locale"))
    418            self.assertFalse(is_resource(base, "foo"))
    419            self.assertFalse(is_resource(base, "foo/bar/greprefs.js"))
    420            self.assertTrue(is_resource(base, "defaults/messenger/foo.dat"))
    421            self.assertFalse(is_resource(base, "defaults/messenger/mailViews.dat"))
    422            self.assertTrue(is_resource(base, "defaults/pref/foo.js"))
    423            self.assertFalse(is_resource(base, "defaults/foo/bar.dat"))
    424            self.assertFalse(is_resource(base, "defaults/foo/bar/baz.dat"))
    425            self.assertTrue(is_resource(base, "chrome/foo/bar/baz/dummy_"))
    426            self.assertFalse(is_resource(base, "chrome/foo/bar/baz/dummy"))
    427            self.assertTrue(is_resource(base, "chrome/foo/bar/dummy_"))
    428            self.assertFalse(is_resource(base, "chrome/foo/bar/dummy"))
    429 
    430    def test_chrome_override(self):
    431        registry = FileRegistry()
    432        f = FlatFormatter(registry)
    433        f.add_base("")
    434        f.add_manifest(ManifestContent("chrome", "foo", "foo/unix"))
    435        # A more specific entry for a given chrome name can override a more
    436        # generic one.
    437        f.add_manifest(ManifestContent("chrome", "foo", "foo/win", "os=WINNT"))
    438        f.add_manifest(ManifestContent("chrome", "foo", "foo/osx", "os=Darwin"))
    439 
    440        # Chrome with the same name overrides the previous registration.
    441        with self.assertRaises(ErrorMessage) as e:
    442            f.add_manifest(ManifestContent("chrome", "foo", "foo/"))
    443 
    444        self.assertEqual(
    445            str(e.exception),
    446            'error: "content foo foo/" overrides "content foo foo/unix"',
    447        )
    448 
    449        # Chrome with the same name and same flags overrides the previous
    450        # registration.
    451        with self.assertRaises(ErrorMessage) as e:
    452            f.add_manifest(ManifestContent("chrome", "foo", "foo/", "os=WINNT"))
    453 
    454        self.assertEqual(
    455            str(e.exception),
    456            'error: "content foo foo/ os=WINNT" overrides '
    457            '"content foo foo/win os=WINNT"',
    458        )
    459 
    460        # We may start with the more specific entry first
    461        f.add_manifest(ManifestContent("chrome", "bar", "bar/win", "os=WINNT"))
    462        # Then adding a more generic one overrides it.
    463        with self.assertRaises(ErrorMessage) as e:
    464            f.add_manifest(ManifestContent("chrome", "bar", "bar/unix"))
    465 
    466        self.assertEqual(
    467            str(e.exception),
    468            'error: "content bar bar/unix" overrides "content bar bar/win os=WINNT"',
    469        )
    470 
    471        # Adding something more specific still works.
    472        f.add_manifest(
    473            ManifestContent("chrome", "bar", "bar/win", "os=WINNT osversion>=7.0")
    474        )
    475 
    476        # Variations of skin/locales are allowed.
    477        f.add_manifest(
    478            ManifestSkin("chrome", "foo", "classic/1.0", "foo/skin/classic/")
    479        )
    480        f.add_manifest(ManifestSkin("chrome", "foo", "modern/1.0", "foo/skin/modern/"))
    481 
    482        f.add_manifest(ManifestLocale("chrome", "foo", "en-US", "foo/locale/en-US/"))
    483        f.add_manifest(ManifestLocale("chrome", "foo", "ja-JP", "foo/locale/ja-JP/"))
    484 
    485        # But same-skin/locale still error out.
    486        with self.assertRaises(ErrorMessage) as e:
    487            f.add_manifest(
    488                ManifestSkin("chrome", "foo", "classic/1.0", "foo/skin/classic/foo")
    489            )
    490 
    491        self.assertEqual(
    492            str(e.exception),
    493            'error: "skin foo classic/1.0 foo/skin/classic/foo" overrides '
    494            '"skin foo classic/1.0 foo/skin/classic/"',
    495        )
    496 
    497        with self.assertRaises(ErrorMessage) as e:
    498            f.add_manifest(
    499                ManifestLocale("chrome", "foo", "en-US", "foo/locale/en-US/foo")
    500            )
    501 
    502        self.assertEqual(
    503            str(e.exception),
    504            'error: "locale foo en-US foo/locale/en-US/foo" overrides '
    505            '"locale foo en-US foo/locale/en-US/"',
    506        )
    507 
    508        # Duplicating existing manifest entries is not an error.
    509        f.add_manifest(ManifestContent("chrome", "foo", "foo/unix"))
    510 
    511        self.assertEqual(
    512            self.get_output(),
    513            [
    514                'warning: "content foo foo/unix" is duplicated. Skipping.',
    515            ],
    516        )
    517 
    518 
    519 if __name__ == "__main__":
    520    mozunit.main()