addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,516 @@
     1.4 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 +
     1.8 +import os
     1.9 +import unittest
    1.10 +import zipfile
    1.11 +import pprint
    1.12 +import shutil
    1.13 +
    1.14 +import simplejson as json
    1.15 +from cuddlefish import xpi, packaging, manifest, buildJID
    1.16 +from cuddlefish.tests import test_packaging
    1.17 +from test_linker import up
    1.18 +
    1.19 +import xml.etree.ElementTree as ElementTree
    1.20 +
    1.21 +xpi_template_path = os.path.join(test_packaging.static_files_path,
    1.22 +                                 'xpi-template')
    1.23 +
    1.24 +fake_manifest = '<RDF><!-- Extension metadata is here. --></RDF>'
    1.25 +
    1.26 +class PrefsTests(unittest.TestCase):
    1.27 +    def makexpi(self, pkg_name):
    1.28 +        self.xpiname = "%s.xpi" % pkg_name
    1.29 +        create_xpi(self.xpiname, pkg_name, 'preferences-files')
    1.30 +        self.xpi = zipfile.ZipFile(self.xpiname, 'r')
    1.31 +        options = self.xpi.read('harness-options.json')
    1.32 +        self.xpi_harness_options = json.loads(options)
    1.33 +
    1.34 +    def setUp(self):
    1.35 +        self.xpiname = None
    1.36 +        self.xpi = None
    1.37 +
    1.38 +    def tearDown(self):
    1.39 +        if self.xpi:
    1.40 +            self.xpi.close()
    1.41 +        if self.xpiname and os.path.exists(self.xpiname):
    1.42 +            os.remove(self.xpiname)
    1.43 +
    1.44 +    def testPackageWithSimplePrefs(self):
    1.45 +        self.makexpi('simple-prefs')
    1.46 +        packageName = 'jid1-fZHqN9JfrDBa8A@jetpack'
    1.47 +        self.failUnless('options.xul' in self.xpi.namelist())
    1.48 +        optsxul = self.xpi.read('options.xul').decode("utf-8")
    1.49 +        self.failUnlessEqual(self.xpi_harness_options["jetpackID"], packageName)
    1.50 +        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], packageName)
    1.51 +
    1.52 +        root = ElementTree.XML(optsxul.encode('utf-8'))
    1.53 +
    1.54 +        xulNamespacePrefix = \
    1.55 +            "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
    1.56 +
    1.57 +        settings = root.findall(xulNamespacePrefix + 'setting')
    1.58 +
    1.59 +        def assertPref(setting, name, prefType, title):
    1.60 +            self.failUnlessEqual(setting.get('data-jetpack-id'), packageName)
    1.61 +            self.failUnlessEqual(setting.get('pref'),
    1.62 +                                 'extensions.' + packageName + '.' + name)
    1.63 +            self.failUnlessEqual(setting.get('pref-name'), name)
    1.64 +            self.failUnlessEqual(setting.get('type'), prefType)
    1.65 +            self.failUnlessEqual(setting.get('title'), title)
    1.66 +
    1.67 +        assertPref(settings[0], 'test', 'bool', u't\u00EBst')
    1.68 +        assertPref(settings[1], 'test2', 'string', u't\u00EBst')
    1.69 +        assertPref(settings[2], 'test3', 'menulist', '"><test')
    1.70 +        assertPref(settings[3], 'test4', 'radio', u't\u00EBst')
    1.71 +
    1.72 +        menuItems = settings[2].findall(
    1.73 +            '%(0)smenulist/%(0)smenupopup/%(0)smenuitem' % { "0": xulNamespacePrefix })
    1.74 +        radios = settings[3].findall(
    1.75 +            '%(0)sradiogroup/%(0)sradio' % { "0": xulNamespacePrefix })
    1.76 +
    1.77 +        def assertOption(option, value, label):
    1.78 +            self.failUnlessEqual(option.get('value'), value)
    1.79 +            self.failUnlessEqual(option.get('label'), label)
    1.80 +
    1.81 +        assertOption(menuItems[0], "0", "label1")
    1.82 +        assertOption(menuItems[1], "1", "label2")
    1.83 +        assertOption(radios[0], "red", "rouge")
    1.84 +        assertOption(radios[1], "blue", "bleu")
    1.85 +
    1.86 +        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
    1.87 +        exp = [u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test", false);',
    1.88 +               u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test2", "\u00FCnic\u00F8d\u00E9");',
    1.89 +               u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test3", "1");',
    1.90 +               u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test4", "red");',
    1.91 +               ]
    1.92 +        self.failUnlessEqual(prefsjs, "\n".join(exp)+"\n")
    1.93 +
    1.94 +    def testPackageWithPreferencesBranch(self):
    1.95 +        self.makexpi('preferences-branch')
    1.96 +        self.failUnless('options.xul' in self.xpi.namelist())
    1.97 +        optsxul = self.xpi.read('options.xul').decode("utf-8")
    1.98 +        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], 
    1.99 +                             "human-readable")
   1.100 +
   1.101 +        root = ElementTree.XML(optsxul.encode('utf-8'))
   1.102 +        xulNamespacePrefix = \
   1.103 +            "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
   1.104 +        
   1.105 +        setting = root.find(xulNamespacePrefix + 'setting')
   1.106 +        self.failUnlessEqual(setting.get('pref'),
   1.107 +                             'extensions.human-readable.test42')
   1.108 +
   1.109 +        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
   1.110 +        self.failUnlessEqual(prefsjs, 
   1.111 +                            'pref("extensions.human-readable.test42", true);\n')
   1.112 +
   1.113 +    def testPackageWithNoPrefs(self):
   1.114 +        self.makexpi('no-prefs')
   1.115 +        self.failIf('options.xul' in self.xpi.namelist())
   1.116 +        self.failUnlessEqual(self.xpi_harness_options["jetpackID"],
   1.117 +                             "jid1-fZHqN9JfrDBa8A@jetpack")
   1.118 +        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
   1.119 +        self.failUnlessEqual(prefsjs, "")
   1.120 +
   1.121 +    def testPackageWithInvalidPreferencesBranch(self):
   1.122 +        self.makexpi('curly-id')
   1.123 +        self.failIfEqual(self.xpi_harness_options["preferencesBranch"], 
   1.124 +                         "invalid^branch*name")
   1.125 +        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], 
   1.126 +                             "{34a1eae1-c20a-464f-9b0e-000000000000}")
   1.127 +
   1.128 +    def testPackageWithCurlyID(self):
   1.129 +        self.makexpi('curly-id')
   1.130 +        self.failUnlessEqual(self.xpi_harness_options["jetpackID"], 
   1.131 +                             "{34a1eae1-c20a-464f-9b0e-000000000000}")
   1.132 +
   1.133 +        self.failUnless('options.xul' in self.xpi.namelist())
   1.134 +        optsxul = self.xpi.read('options.xul').decode("utf-8")
   1.135 +
   1.136 +        root = ElementTree.XML(optsxul.encode('utf-8'))
   1.137 +        xulNamespacePrefix = \
   1.138 +            "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
   1.139 +        
   1.140 +        setting = root.find(xulNamespacePrefix + 'setting')
   1.141 +        self.failUnlessEqual(setting.get('pref'),
   1.142 +                             'extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13')
   1.143 +
   1.144 +        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
   1.145 +        self.failUnlessEqual(prefsjs, 
   1.146 +                            'pref("extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13", 26);\n')
   1.147 +
   1.148 +
   1.149 +class Bug588119Tests(unittest.TestCase):
   1.150 +    def makexpi(self, pkg_name):
   1.151 +        self.xpiname = "%s.xpi" % pkg_name
   1.152 +        create_xpi(self.xpiname, pkg_name, 'bug-588119-files')
   1.153 +        self.xpi = zipfile.ZipFile(self.xpiname, 'r')
   1.154 +        options = self.xpi.read('harness-options.json')
   1.155 +        self.xpi_harness_options = json.loads(options)
   1.156 +
   1.157 +    def setUp(self):
   1.158 +        self.xpiname = None
   1.159 +        self.xpi = None
   1.160 +
   1.161 +    def tearDown(self):
   1.162 +        if self.xpi:
   1.163 +            self.xpi.close()
   1.164 +        if self.xpiname and os.path.exists(self.xpiname):
   1.165 +            os.remove(self.xpiname)
   1.166 +
   1.167 +    def testPackageWithImplicitIcon(self):
   1.168 +        self.makexpi('implicit-icon')
   1.169 +        assert 'icon.png' in self.xpi.namelist()
   1.170 +
   1.171 +    def testPackageWithImplicitIcon64(self):
   1.172 +        self.makexpi('implicit-icon')
   1.173 +        assert 'icon64.png' in self.xpi.namelist()
   1.174 +
   1.175 +    def testPackageWithExplicitIcon(self):
   1.176 +        self.makexpi('explicit-icon')
   1.177 +        assert 'icon.png' in self.xpi.namelist()
   1.178 +
   1.179 +    def testPackageWithExplicitIcon64(self):
   1.180 +        self.makexpi('explicit-icon')
   1.181 +        assert 'icon64.png' in self.xpi.namelist()
   1.182 +
   1.183 +    def testPackageWithNoIcon(self):
   1.184 +        self.makexpi('no-icon')
   1.185 +        assert 'icon.png' not in self.xpi.namelist()
   1.186 +
   1.187 +    def testIconPathNotInHarnessOptions(self):
   1.188 +        self.makexpi('implicit-icon')
   1.189 +        assert 'icon' not in self.xpi_harness_options
   1.190 +
   1.191 +    def testIcon64PathNotInHarnessOptions(self):
   1.192 +        self.makexpi('implicit-icon')
   1.193 +        assert 'icon64' not in self.xpi_harness_options
   1.194 +
   1.195 +class ExtraHarnessOptions(unittest.TestCase):
   1.196 +    def setUp(self):
   1.197 +        self.xpiname = None
   1.198 +        self.xpi = None
   1.199 +
   1.200 +    def tearDown(self):
   1.201 +        if self.xpi:
   1.202 +            self.xpi.close()
   1.203 +        if self.xpiname and os.path.exists(self.xpiname):
   1.204 +            os.remove(self.xpiname)
   1.205 +
   1.206 +    def testOptions(self):
   1.207 +        pkg_name = "extra-options"
   1.208 +        self.xpiname = "%s.xpi" % pkg_name
   1.209 +        create_xpi(self.xpiname, pkg_name, "bug-669274-files",
   1.210 +                   extra_harness_options={"builderVersion": "futuristic"})
   1.211 +        self.xpi = zipfile.ZipFile(self.xpiname, 'r')
   1.212 +        options = self.xpi.read('harness-options.json')
   1.213 +        hopts = json.loads(options)
   1.214 +        self.failUnless("builderVersion" in hopts)
   1.215 +        self.failUnlessEqual(hopts["builderVersion"], "futuristic")
   1.216 +
   1.217 +    def testBadOptionName(self):
   1.218 +        pkg_name = "extra-options"
   1.219 +        self.xpiname = "%s.xpi" % pkg_name
   1.220 +        self.failUnlessRaises(xpi.HarnessOptionAlreadyDefinedError,
   1.221 +                              create_xpi,
   1.222 +                              self.xpiname, pkg_name, "bug-669274-files",
   1.223 +                              extra_harness_options={"main": "already in use"})
   1.224 +
   1.225 +class SmallXPI(unittest.TestCase):
   1.226 +    def setUp(self):
   1.227 +        self.root = up(os.path.abspath(__file__), 4)
   1.228 +    def get_linker_files_dir(self, name):
   1.229 +        return os.path.join(up(os.path.abspath(__file__)), "linker-files", name)
   1.230 +    def get_pkg(self, name):
   1.231 +        d = self.get_linker_files_dir(name)
   1.232 +        return packaging.get_config_in_dir(d)
   1.233 +
   1.234 +    def get_basedir(self):
   1.235 +        return os.path.join(".test_tmp", self.id())
   1.236 +    def make_basedir(self):
   1.237 +        basedir = self.get_basedir()
   1.238 +        if os.path.isdir(basedir):
   1.239 +            here = os.path.abspath(os.getcwd())
   1.240 +            assert os.path.abspath(basedir).startswith(here) # safety
   1.241 +            shutil.rmtree(basedir)
   1.242 +        os.makedirs(basedir)
   1.243 +        return basedir
   1.244 +
   1.245 +    def test_contents(self):
   1.246 +        target_cfg = self.get_pkg("three")
   1.247 +        package_path = [self.get_linker_files_dir("three-deps")]
   1.248 +        pkg_cfg = packaging.build_config(self.root, target_cfg,
   1.249 +                                         packagepath=package_path)
   1.250 +        deps = packaging.get_deps_for_targets(pkg_cfg,
   1.251 +                                              [target_cfg.name, "addon-sdk"])
   1.252 +        addon_sdk_dir = pkg_cfg.packages["addon-sdk"].lib[0]
   1.253 +        m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
   1.254 +        used_files = list(m.get_used_files(True))
   1.255 +        here = up(os.path.abspath(__file__))
   1.256 +        def absify(*parts):
   1.257 +            fn = os.path.join(here, "linker-files", *parts)
   1.258 +            return os.path.abspath(fn)
   1.259 +        expected = [absify(*parts) for parts in
   1.260 +                    [("three", "lib", "main.js"),
   1.261 +                     ("three-deps", "three-a", "lib", "main.js"),
   1.262 +                     ("three-deps", "three-a", "lib", "subdir", "subfile.js"),
   1.263 +                     ("three", "data", "msg.txt"),
   1.264 +                     ("three", "data", "subdir", "submsg.txt"),
   1.265 +                     ("three-deps", "three-b", "lib", "main.js"),
   1.266 +                     ("three-deps", "three-c", "lib", "main.js"),
   1.267 +                     ("three-deps", "three-c", "lib", "sub", "foo.js")
   1.268 +                     ]]
   1.269 +
   1.270 +        add_addon_sdk= lambda path: os.path.join(addon_sdk_dir, path)
   1.271 +        expected.extend([add_addon_sdk(module) for module in [
   1.272 +            os.path.join("sdk", "self.js"),
   1.273 +            os.path.join("sdk", "core", "promise.js"),
   1.274 +            os.path.join("sdk", "net", "url.js"),
   1.275 +            os.path.join("sdk", "util", "object.js"),
   1.276 +            os.path.join("sdk", "util", "array.js")
   1.277 +            ]])
   1.278 +
   1.279 +        missing = set(expected) - set(used_files)
   1.280 +        extra = set(used_files) - set(expected)
   1.281 +
   1.282 +        self.failUnlessEqual(list(missing), [])
   1.283 +        self.failUnlessEqual(list(extra), [])
   1.284 +        used_deps = m.get_used_packages()
   1.285 +
   1.286 +        build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name,
   1.287 +                                                    used_deps,
   1.288 +                                                    include_tests=False)
   1.289 +        options = {'main': target_cfg.main}
   1.290 +        options.update(build)
   1.291 +        basedir = self.make_basedir()
   1.292 +        xpi_name = os.path.join(basedir, "contents.xpi")
   1.293 +        xpi.build_xpi(template_root_dir=xpi_template_path,
   1.294 +                      manifest=fake_manifest,
   1.295 +                      xpi_path=xpi_name,
   1.296 +                      harness_options=options,
   1.297 +                      limit_to=used_files)
   1.298 +        x = zipfile.ZipFile(xpi_name, "r")
   1.299 +        names = x.namelist()
   1.300 +        expected = ["components/",
   1.301 +                    "components/harness.js",
   1.302 +                    # the real template also has 'bootstrap.js', but the fake
   1.303 +                    # one in tests/static-files/xpi-template doesn't
   1.304 +                    "harness-options.json",
   1.305 +                    "install.rdf",
   1.306 +                    "defaults/preferences/prefs.js",
   1.307 +                    "resources/",
   1.308 +                    "resources/addon-sdk/",
   1.309 +                    "resources/addon-sdk/lib/",
   1.310 +                    "resources/addon-sdk/lib/sdk/",
   1.311 +                    "resources/addon-sdk/lib/sdk/self.js",
   1.312 +                    "resources/addon-sdk/lib/sdk/core/",
   1.313 +                    "resources/addon-sdk/lib/sdk/util/",
   1.314 +                    "resources/addon-sdk/lib/sdk/net/",
   1.315 +                    "resources/addon-sdk/lib/sdk/core/promise.js",
   1.316 +                    "resources/addon-sdk/lib/sdk/util/object.js",
   1.317 +                    "resources/addon-sdk/lib/sdk/util/array.js",
   1.318 +                    "resources/addon-sdk/lib/sdk/net/url.js",
   1.319 +                    "resources/three/",
   1.320 +                    "resources/three/lib/",
   1.321 +                    "resources/three/lib/main.js",
   1.322 +                    "resources/three/data/",
   1.323 +                    "resources/three/data/msg.txt",
   1.324 +                    "resources/three/data/subdir/",
   1.325 +                    "resources/three/data/subdir/submsg.txt",
   1.326 +                    "resources/three-a/",
   1.327 +                    "resources/three-a/lib/",
   1.328 +                    "resources/three-a/lib/main.js",
   1.329 +                    "resources/three-a/lib/subdir/",
   1.330 +                    "resources/three-a/lib/subdir/subfile.js",
   1.331 +                    "resources/three-b/",
   1.332 +                    "resources/three-b/lib/",
   1.333 +                    "resources/three-b/lib/main.js",
   1.334 +                    "resources/three-c/",
   1.335 +                    "resources/three-c/lib/",
   1.336 +                    "resources/three-c/lib/main.js",
   1.337 +                    "resources/three-c/lib/sub/",
   1.338 +                    "resources/three-c/lib/sub/foo.js",
   1.339 +                    # notably absent: three-a/lib/unused.js
   1.340 +                    "locale/",
   1.341 +                    "locale/fr-FR.json",
   1.342 +                    "locales.json",
   1.343 +                    ]
   1.344 +        # showing deltas makes failures easier to investigate
   1.345 +        missing = set(expected) - set(names)
   1.346 +        extra = set(names) - set(expected)
   1.347 +        self.failUnlessEqual((list(missing), list(extra)), ([], []))
   1.348 +        self.failUnlessEqual(sorted(names), sorted(expected))
   1.349 +
   1.350 +        # check locale files
   1.351 +        localedata = json.loads(x.read("locales.json"))
   1.352 +        self.failUnlessEqual(sorted(localedata["locales"]), sorted(["fr-FR"]))
   1.353 +        content = x.read("locale/fr-FR.json")
   1.354 +        locales = json.loads(content)
   1.355 +        # Locale files are merged into one.
   1.356 +        # Conflicts are silently resolved by taking last package translation,
   1.357 +        # so that we get "No" translation from three-c instead of three-b one.
   1.358 +        self.failUnlessEqual(locales, json.loads(u'''
   1.359 +          {
   1.360 +            "No": "Nein",
   1.361 +            "one": "un",
   1.362 +            "What?": "Quoi?",
   1.363 +            "Yes": "Oui",
   1.364 +            "plural": {
   1.365 +              "other": "other",
   1.366 +              "one": "one"
   1.367 +            },
   1.368 +            "uft8_value": "\u00e9"
   1.369 +          }'''))
   1.370 +
   1.371 +    def test_scantests(self):
   1.372 +        target_cfg = self.get_pkg("three")
   1.373 +        package_path = [self.get_linker_files_dir("three-deps")]
   1.374 +        pkg_cfg = packaging.build_config(self.root, target_cfg,
   1.375 +                                         packagepath=package_path)
   1.376 +
   1.377 +        deps = packaging.get_deps_for_targets(pkg_cfg,
   1.378 +                                              [target_cfg.name, "addon-sdk"])
   1.379 +        m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True)
   1.380 +        self.failUnlessEqual(sorted(m.get_all_test_modules()),
   1.381 +                             sorted(["three/tests/test-one", "three/tests/test-two"]))
   1.382 +        # the current __init__.py code omits limit_to=used_files for 'cfx
   1.383 +        # test', so all test files are included in the XPI. But the test
   1.384 +        # runner will only execute the tests that m.get_all_test_modules()
   1.385 +        # tells us about (which are put into the .allTestModules property of
   1.386 +        # harness-options.json).
   1.387 +        used_deps = m.get_used_packages()
   1.388 +
   1.389 +        build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name,
   1.390 +                                                    used_deps,
   1.391 +                                                    include_tests=True)
   1.392 +        options = {'main': target_cfg.main}
   1.393 +        options.update(build)
   1.394 +        basedir = self.make_basedir()
   1.395 +        xpi_name = os.path.join(basedir, "contents.xpi")
   1.396 +        xpi.build_xpi(template_root_dir=xpi_template_path,
   1.397 +                      manifest=fake_manifest,
   1.398 +                      xpi_path=xpi_name,
   1.399 +                      harness_options=options,
   1.400 +                      limit_to=None)
   1.401 +        x = zipfile.ZipFile(xpi_name, "r")
   1.402 +        names = x.namelist()
   1.403 +        self.failUnless("resources/addon-sdk/lib/sdk/deprecated/unit-test.js" in names, names)
   1.404 +        self.failUnless("resources/addon-sdk/lib/sdk/deprecated/unit-test-finder.js" in names, names)
   1.405 +        self.failUnless("resources/addon-sdk/lib/sdk/test/harness.js" in names, names)
   1.406 +        self.failUnless("resources/addon-sdk/lib/sdk/test/runner.js" in names, names)
   1.407 +        # all files are copied into the XPI, even the things that don't look
   1.408 +        # like tests.
   1.409 +        self.failUnless("resources/three/tests/test-one.js" in names, names)
   1.410 +        self.failUnless("resources/three/tests/test-two.js" in names, names)
   1.411 +        self.failUnless("resources/three/tests/nontest.js" in names, names)
   1.412 +
   1.413 +    def test_scantests_filter(self):
   1.414 +        target_cfg = self.get_pkg("three")
   1.415 +        package_path = [self.get_linker_files_dir("three-deps")]
   1.416 +        pkg_cfg = packaging.build_config(self.root, target_cfg,
   1.417 +                                         packagepath=package_path)
   1.418 +        deps = packaging.get_deps_for_targets(pkg_cfg,
   1.419 +                                              [target_cfg.name, "addon-sdk"])
   1.420 +        FILTER = ".*one.*"
   1.421 +        m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=True,
   1.422 +                                    test_filter_re=FILTER)
   1.423 +        self.failUnlessEqual(sorted(m.get_all_test_modules()),
   1.424 +                             sorted(["three/tests/test-one"]))
   1.425 +        # the current __init__.py code omits limit_to=used_files for 'cfx
   1.426 +        # test', so all test files are included in the XPI. But the test
   1.427 +        # runner will only execute the tests that m.get_all_test_modules()
   1.428 +        # tells us about (which are put into the .allTestModules property of
   1.429 +        # harness-options.json).
   1.430 +        used_deps = m.get_used_packages()
   1.431 +
   1.432 +        build = packaging.generate_build_for_target(pkg_cfg, target_cfg.name,
   1.433 +                                                    used_deps,
   1.434 +                                                    include_tests=True)
   1.435 +        options = {'main': target_cfg.main}
   1.436 +        options.update(build)
   1.437 +        basedir = self.make_basedir()
   1.438 +        xpi_name = os.path.join(basedir, "contents.xpi")
   1.439 +        xpi.build_xpi(template_root_dir=xpi_template_path,
   1.440 +                      manifest=fake_manifest,
   1.441 +                      xpi_path=xpi_name,
   1.442 +                      harness_options=options,
   1.443 +                      limit_to=None)
   1.444 +        x = zipfile.ZipFile(xpi_name, "r")
   1.445 +        names = x.namelist()
   1.446 +        self.failUnless("resources/addon-sdk/lib/sdk/deprecated/unit-test.js" in names, names)
   1.447 +        self.failUnless("resources/addon-sdk/lib/sdk/deprecated/unit-test-finder.js" in names, names)
   1.448 +        self.failUnless("resources/addon-sdk/lib/sdk/test/harness.js" in names, names)
   1.449 +        self.failUnless("resources/addon-sdk/lib/sdk/test/runner.js" in names, names)
   1.450 +        # get_all_test_modules() respects the filter. But all files are still
   1.451 +        # copied into the XPI.
   1.452 +        self.failUnless("resources/three/tests/test-one.js" in names, names)
   1.453 +        self.failUnless("resources/three/tests/test-two.js" in names, names)
   1.454 +        self.failUnless("resources/three/tests/nontest.js" in names, names)
   1.455 +
   1.456 +
   1.457 +def document_dir(name):
   1.458 +    if name in ['packages', 'xpi-template']:
   1.459 +        dirname = os.path.join(test_packaging.static_files_path, name)
   1.460 +        document_dir_files(dirname)
   1.461 +    elif name == 'xpi-output':
   1.462 +        create_xpi('test-xpi.xpi')
   1.463 +        document_zip_file('test-xpi.xpi')
   1.464 +        os.remove('test-xpi.xpi')
   1.465 +    else:
   1.466 +        raise Exception('unknown dir: %s' % name)
   1.467 +
   1.468 +def normpath(path):
   1.469 +    """
   1.470 +    Make a platform-specific relative path use '/' as a separator.
   1.471 +    """
   1.472 +
   1.473 +    return path.replace(os.path.sep, '/')
   1.474 +
   1.475 +def document_zip_file(path):
   1.476 +    zip = zipfile.ZipFile(path, 'r')
   1.477 +    for name in sorted(zip.namelist()):
   1.478 +        contents = zip.read(name)
   1.479 +        lines = contents.splitlines()
   1.480 +        if len(lines) == 1 and name.endswith('.json') and len(lines[0]) > 75:
   1.481 +            # Ideally we would json-decode this, but it results
   1.482 +            # in an annoying 'u' before every string literal,
   1.483 +            # since json decoding makes all strings unicode.
   1.484 +            contents = eval(contents)
   1.485 +            contents = pprint.pformat(contents)
   1.486 +            lines = contents.splitlines()
   1.487 +        contents = "\n  ".join(lines)
   1.488 +        print "%s:\n  %s" % (normpath(name), contents)
   1.489 +    zip.close()
   1.490 +
   1.491 +def document_dir_files(path):
   1.492 +    filename_contents_tuples = []
   1.493 +    for dirpath, dirnames, filenames in os.walk(path):
   1.494 +        relpath = dirpath[len(path)+1:]
   1.495 +        for filename in filenames:
   1.496 +            abspath = os.path.join(dirpath, filename)
   1.497 +            contents = open(abspath, 'r').read()
   1.498 +            contents = "\n  ".join(contents.splitlines())
   1.499 +            relfilename = os.path.join(relpath, filename)
   1.500 +            filename_contents_tuples.append((normpath(relfilename), contents))
   1.501 +    filename_contents_tuples.sort()
   1.502 +    for filename, contents in filename_contents_tuples:
   1.503 +        print "%s:" % filename
   1.504 +        print "  %s" % contents
   1.505 +
   1.506 +def create_xpi(xpiname, pkg_name='aardvark', dirname='static-files',
   1.507 +               extra_harness_options={}):
   1.508 +    configs = test_packaging.get_configs(pkg_name, dirname)
   1.509 +    options = {'main': configs.target_cfg.main,
   1.510 +               'jetpackID': buildJID(configs.target_cfg), }
   1.511 +    options.update(configs.build)
   1.512 +    xpi.build_xpi(template_root_dir=xpi_template_path,
   1.513 +                  manifest=fake_manifest,
   1.514 +                  xpi_path=xpiname,
   1.515 +                  harness_options=options,
   1.516 +                  extra_harness_options=extra_harness_options)
   1.517 +
   1.518 +if __name__ == '__main__':
   1.519 +    unittest.main()

mercurial