forked from mirrors/gecko-dev
		
	Allow-list all Python code in tree for use with the black linter, and re-format all code in-tree accordingly. To produce this patch I did all of the following: 1. Make changes to tools/lint/black.yml to remove include: stanza and update list of source extensions. 2. Run ./mach lint --linter black --fix 3. Make some ad-hoc manual updates to python/mozbuild/mozbuild/test/configure/test_configure.py -- it has some hard-coded line numbers that the reformat breaks. 4. Make some ad-hoc manual updates to `testing/marionette/client/setup.py`, `testing/marionette/harness/setup.py`, and `testing/firefox-ui/harness/setup.py`, which have hard-coded regexes that break after the reformat. 5. Add a set of exclusions to black.yml. These will be deleted in a follow-up bug (1672023). # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D94045
		
			
				
	
	
		
			215 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
	
		
			6.2 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/.
 | 
						|
 | 
						|
from __future__ import absolute_import
 | 
						|
import unittest
 | 
						|
 | 
						|
import shutil
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import random
 | 
						|
import copy
 | 
						|
from string import letters
 | 
						|
 | 
						|
"""
 | 
						|
Test case infrastructure for MozZipFile.
 | 
						|
 | 
						|
This isn't really a unit test, but a test case generator and runner.
 | 
						|
For a given set of files, lengths, and number of writes, we create
 | 
						|
a testcase for every combination of the three. There are some
 | 
						|
symmetries used to reduce the number of test cases, the first file
 | 
						|
written is always the first file, the second is either the first or
 | 
						|
the second, the third is one of the first three. That is, if we
 | 
						|
had 4 files, but only three writes, the fourth file would never even
 | 
						|
get tried.
 | 
						|
 | 
						|
The content written to the jars is pseudorandom with a fixed seed.
 | 
						|
"""
 | 
						|
 | 
						|
if not __file__:
 | 
						|
    __file__ = sys.argv[0]
 | 
						|
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
 | 
						|
 | 
						|
from MozZipFile import ZipFile
 | 
						|
import zipfile
 | 
						|
 | 
						|
leafs = ("firstdir/oneleaf", "seconddir/twoleaf", "thirddir/with/sub/threeleaf")
 | 
						|
_lengths = map(lambda n: n * 64, [16, 64, 80])
 | 
						|
lengths = 3
 | 
						|
writes = 5
 | 
						|
 | 
						|
 | 
						|
def givenlength(i):
 | 
						|
    """Return a length given in the _lengths array to allow manual
 | 
						|
    tuning of which lengths of zip entries to use.
 | 
						|
    """
 | 
						|
    return _lengths[i]
 | 
						|
 | 
						|
 | 
						|
def prod(*iterables):
 | 
						|
    """'Tensor product of a list of iterables.
 | 
						|
 | 
						|
    This generator returns lists of items, one of each given
 | 
						|
    iterable. It iterates over all possible combinations.
 | 
						|
    """
 | 
						|
    for item in iterables[0]:
 | 
						|
        if len(iterables) == 1:
 | 
						|
            yield [item]
 | 
						|
        else:
 | 
						|
            for others in prod(*iterables[1:]):
 | 
						|
                yield [item] + others
 | 
						|
 | 
						|
 | 
						|
def getid(descs):
 | 
						|
    "Convert a list of ints to a string."
 | 
						|
    return reduce(lambda x, y: x + "{0}{1}".format(*tuple(y)), descs, "")
 | 
						|
 | 
						|
 | 
						|
def getContent(length):
 | 
						|
    "Get pseudo random content of given length."
 | 
						|
    rv = [None] * length
 | 
						|
    for i in xrange(length):
 | 
						|
        rv[i] = random.choice(letters)
 | 
						|
    return "".join(rv)
 | 
						|
 | 
						|
 | 
						|
def createWriter(sizer, *items):
 | 
						|
    "Helper method to fill in tests, one set of writes, one for each item"
 | 
						|
    locitems = copy.deepcopy(items)
 | 
						|
    for item in locitems:
 | 
						|
        item["length"] = sizer(item.pop("length", 0))
 | 
						|
 | 
						|
    def helper(self):
 | 
						|
        mode = "w"
 | 
						|
        if os.path.isfile(self.f):
 | 
						|
            mode = "a"
 | 
						|
        zf = ZipFile(self.f, mode, self.compression)
 | 
						|
        for item in locitems:
 | 
						|
            self._write(zf, **item)
 | 
						|
        zf = None
 | 
						|
        pass
 | 
						|
 | 
						|
    return helper
 | 
						|
 | 
						|
 | 
						|
def createTester(name, *writes):
 | 
						|
    """Helper method to fill in tests, calls into a list of write
 | 
						|
    helper methods.
 | 
						|
    """
 | 
						|
    _writes = copy.copy(writes)
 | 
						|
 | 
						|
    def tester(self):
 | 
						|
        for w in _writes:
 | 
						|
            getattr(self, w)()
 | 
						|
        self._verifyZip()
 | 
						|
        pass
 | 
						|
 | 
						|
    # unit tests get confused if the method name isn't test...
 | 
						|
    tester.__name__ = name
 | 
						|
    return tester
 | 
						|
 | 
						|
 | 
						|
class TestExtensiveStored(unittest.TestCase):
 | 
						|
    """Unit tests for MozZipFile
 | 
						|
 | 
						|
    The testcase are actually populated by code following the class
 | 
						|
    definition.
 | 
						|
    """
 | 
						|
 | 
						|
    stage = "mozzipfilestage"
 | 
						|
    compression = zipfile.ZIP_STORED
 | 
						|
 | 
						|
    def leaf(self, *leafs):
 | 
						|
        return os.path.join(self.stage, *leafs)
 | 
						|
 | 
						|
    def setUp(self):
 | 
						|
        if os.path.exists(self.stage):
 | 
						|
            shutil.rmtree(self.stage)
 | 
						|
        os.mkdir(self.stage)
 | 
						|
        self.f = self.leaf("test.jar")
 | 
						|
        self.ref = {}
 | 
						|
        self.seed = 0
 | 
						|
 | 
						|
    def tearDown(self):
 | 
						|
        self.f = None
 | 
						|
        self.ref = None
 | 
						|
 | 
						|
    def _verifyZip(self):
 | 
						|
        zf = zipfile.ZipFile(self.f)
 | 
						|
        badEntry = zf.testzip()
 | 
						|
        self.failIf(badEntry, badEntry)
 | 
						|
        zlist = zf.namelist()
 | 
						|
        zlist.sort()
 | 
						|
        vlist = self.ref.keys()
 | 
						|
        vlist.sort()
 | 
						|
        self.assertEqual(zlist, vlist)
 | 
						|
        for leaf, content in self.ref.iteritems():
 | 
						|
            zcontent = zf.read(leaf)
 | 
						|
            self.assertEqual(content, zcontent)
 | 
						|
 | 
						|
    def _write(self, zf, seed=None, leaf=0, length=0):
 | 
						|
        if seed is None:
 | 
						|
            seed = self.seed
 | 
						|
            self.seed += 1
 | 
						|
        random.seed(seed)
 | 
						|
        leaf = leafs[leaf]
 | 
						|
        content = getContent(length)
 | 
						|
        self.ref[leaf] = content
 | 
						|
        zf.writestr(leaf, content)
 | 
						|
        dir = os.path.dirname(self.leaf("stage", leaf))
 | 
						|
        if not os.path.isdir(dir):
 | 
						|
            os.makedirs(dir)
 | 
						|
        open(self.leaf("stage", leaf), "w").write(content)
 | 
						|
 | 
						|
 | 
						|
# all leafs in all lengths
 | 
						|
atomics = list(prod(xrange(len(leafs)), xrange(lengths)))
 | 
						|
 | 
						|
# populate TestExtensiveStore with testcases
 | 
						|
for w in xrange(writes):
 | 
						|
    # Don't iterate over all files for the the first n passes,
 | 
						|
    # those are redundant as long as w < lengths.
 | 
						|
    # There are symmetries in the trailing end, too, but I don't know
 | 
						|
    # how to reduce those out right now.
 | 
						|
    nonatomics = [
 | 
						|
        list(prod(range(min(i, len(leafs))), xrange(lengths))) for i in xrange(1, w + 1)
 | 
						|
    ] + [atomics]
 | 
						|
    for descs in prod(*nonatomics):
 | 
						|
        suffix = getid(descs)
 | 
						|
        dicts = [dict(leaf=leaf, length=length) for leaf, length in descs]
 | 
						|
        setattr(
 | 
						|
            TestExtensiveStored, "_write" + suffix, createWriter(givenlength, *dicts)
 | 
						|
        )
 | 
						|
        setattr(
 | 
						|
            TestExtensiveStored,
 | 
						|
            "test" + suffix,
 | 
						|
            createTester("test" + suffix, "_write" + suffix),
 | 
						|
        )
 | 
						|
 | 
						|
# now create another round of tests, with two writing passes
 | 
						|
# first, write all file combinations into the jar, close it,
 | 
						|
# and then write all atomics again.
 | 
						|
# This should catch more or less all artifacts generated
 | 
						|
# by the final ordering step when closing the jar.
 | 
						|
files = [list(prod([i], xrange(lengths))) for i in xrange(len(leafs))]
 | 
						|
allfiles = reduce(
 | 
						|
    lambda l, r: l + r, [list(prod(*files[: (i + 1)])) for i in xrange(len(leafs))]
 | 
						|
)
 | 
						|
 | 
						|
for first in allfiles:
 | 
						|
    testbasename = "test{0}_".format(getid(first))
 | 
						|
    test = [None, "_write" + getid(first), None]
 | 
						|
    for second in atomics:
 | 
						|
        test[0] = testbasename + getid([second])
 | 
						|
        test[2] = "_write" + getid([second])
 | 
						|
        setattr(TestExtensiveStored, test[0], createTester(*test))
 | 
						|
 | 
						|
 | 
						|
class TestExtensiveDeflated(TestExtensiveStored):
 | 
						|
    "Test all that has been tested with ZIP_STORED with DEFLATED, too."
 | 
						|
    compression = zipfile.ZIP_DEFLATED
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    unittest.main()
 |