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/.
13
from string import letters
16
Test case infrastructure for MozZipFile.
18
This isn't really a unit test, but a test case generator and runner.
19
For a given set of files, lengths, and number of writes, we create
20
a testcase for every combination of the three. There are some
21
symmetries used to reduce the number of test cases, the first file
22
written is always the first file, the second is either the first or
23
the second, the third is one of the first three. That is, if we
24
had 4 files, but only three writes, the fourth file would never even
27
The content written to the jars is pseudorandom with a fixed seed.
31
__file__ = sys.argv[0]
32
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
34
from MozZipFile import ZipFile
40
'thirddir/with/sub/threeleaf')
41
_lengths = map(lambda n: n * 64, [16, 64, 80])
46
'''Return a length given in the _lengths array to allow manual
47
tuning of which lengths of zip entries to use.
53
''''Tensor product of a list of iterables.
55
This generator returns lists of items, one of each given
56
iterable. It iterates over all possible combinations.
58
for item in iterables[0]:
59
if len(iterables) == 1:
62
for others in prod(*iterables[1:]):
67
'Convert a list of ints to a string.'
68
return reduce(lambda x,y: x+'%d%d'%tuple(y), descs,'')
71
def getContent(length):
72
'Get pseudo random content of given length.'
74
for i in xrange(length):
75
rv[i] = random.choice(letters)
79
def createWriter(sizer, *items):
80
'Helper method to fill in tests, one set of writes, one for each item'
81
locitems = copy.deepcopy(items)
83
item['length'] = sizer(item.pop('length', 0))
86
if os.path.isfile(self.f):
88
zf = ZipFile(self.f, mode, self.compression)
90
self._write(zf, **item)
95
def createTester(name, *writes):
96
'''Helper method to fill in tests, calls into a list of write
99
_writes = copy.copy(writes)
105
# unit tests get confused if the method name isn't test...
106
tester.__name__ = name
109
class TestExtensiveStored(unittest.TestCase):
110
'''Unit tests for MozZipFile
112
The testcase are actually populated by code following the class
116
stage = "mozzipfilestage"
117
compression = zipfile.ZIP_STORED
119
def leaf(self, *leafs):
120
return os.path.join(self.stage, *leafs)
122
if os.path.exists(self.stage):
123
shutil.rmtree(self.stage)
125
self.f = self.leaf('test.jar')
133
def _verifyZip(self):
134
zf = zipfile.ZipFile(self.f)
135
badEntry = zf.testzip()
136
self.failIf(badEntry, badEntry)
137
zlist = zf.namelist()
139
vlist = self.ref.keys()
141
self.assertEqual(zlist, vlist)
142
for leaf, content in self.ref.iteritems():
143
zcontent = zf.read(leaf)
144
self.assertEqual(content, zcontent)
146
def _write(self, zf, seed=None, leaf=0, length=0):
152
content = getContent(length)
153
self.ref[leaf] = content
154
zf.writestr(leaf, content)
155
dir = os.path.dirname(self.leaf('stage', leaf))
156
if not os.path.isdir(dir):
158
open(self.leaf('stage', leaf), 'w').write(content)
160
# all leafs in all lengths
161
atomics = list(prod(xrange(len(leafs)), xrange(lengths)))
163
# populate TestExtensiveStore with testcases
164
for w in xrange(writes):
165
# Don't iterate over all files for the the first n passes,
166
# those are redundant as long as w < lengths.
167
# There are symmetries in the trailing end, too, but I don't know
168
# how to reduce those out right now.
169
nonatomics = [list(prod(range(min(i,len(leafs))), xrange(lengths)))
170
for i in xrange(1, w+1)] + [atomics]
171
for descs in prod(*nonatomics):
172
suffix = getid(descs)
173
dicts = [dict(leaf=leaf, length=length) for leaf, length in descs]
174
setattr(TestExtensiveStored, '_write' + suffix,
175
createWriter(givenlength, *dicts))
176
setattr(TestExtensiveStored, 'test' + suffix,
177
createTester('test' + suffix, '_write' + suffix))
179
# now create another round of tests, with two writing passes
180
# first, write all file combinations into the jar, close it,
181
# and then write all atomics again.
182
# This should catch more or less all artifacts generated
183
# by the final ordering step when closing the jar.
184
files = [list(prod([i], xrange(lengths))) for i in xrange(len(leafs))]
185
allfiles = reduce(lambda l,r:l+r,
186
[list(prod(*files[:(i+1)])) for i in xrange(len(leafs))])
188
for first in allfiles:
189
testbasename = 'test%s_' % getid(first)
190
test = [None, '_write' + getid(first), None]
191
for second in atomics:
192
test[0] = testbasename + getid([second])
193
test[2] = '_write' + getid([second])
194
setattr(TestExtensiveStored, test[0], createTester(*test))
196
class TestExtensiveDeflated(TestExtensiveStored):
197
'Test all that has been tested with ZIP_STORED with DEFLATED, too.'
198
compression = zipfile.ZIP_DEFLATED
200
if __name__ == '__main__':