import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,4 @@
content test chrome/test/one
locale ab-X-stuff chrome/test/three
overlay chrome://one/file.xml chrome://two/otherfile.xml
skin test classic chrome/test/one

View file

@ -0,0 +1,36 @@
# -*- makefile -*-
#
# 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/.
#
export STANDALONE_MAKEFILE=1
PYTHON ?= python
PYTEST = $(PYTHON) -E
# python -B not supported by older interpreters
export PYTHONDONTWRITEBYTECODE=1
include $(topsrcdir)/config/rules.mk
autotgt_tests = .deps/autotargets.mk.ts
tgts =\
.deps/.mkdir.done\
$(autotgt_tests)
$(NULL)
export MAKE
##------------------_##
##---] TARGETS [---##
##------------------_##
all::
check:: $(tgts)
# Only run unit test when autotargets.mk is modified
$(autotgt_tests): $(topsrcdir)/config/makefiles/autotargets.mk
$(PYTEST) $(srcdir)/check_mkdir.tpy
@$(TOUCH) $@

View file

@ -0,0 +1,269 @@
#!/usr/bin/env 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/.
#
import os
import sys
import tempfile
from subprocess import call
from shutil import rmtree
import logging
import unittest
def banner():
"""
Display interpreter and system info for the test env
"""
print '*' * 75
cmd = os.path.basename(__file__)
print "%s: python version is %s" % (cmd, sys.version)
print '*' * 75
def myopts(vals):
"""
Storage for extra command line args passed.
Returns:
hash - argparse::Namespace object values
"""
if not hasattr(myopts, 'vals'):
if 'argparse' in sys.modules:
tmp = { } # key existance enables unittest module debug
else:
tmp = { 'debug': False, 'verbose': False }
for k in dir(vals):
if k[0:1] == '_':
continue
tmp[k] = getattr(vals, k)
myopts.vals = tmp
return myopts.vals
def path2posix(src):
"""
Normalize directory path syntax
Keyword arguments:
src - path to normalize
Returns:
scalar - a file path with drive separators and windows slashes removed
Todo:
move to {build,config,tools,toolkit}/python for use in a library
"""
## (drive, tail) = os.path.splitdrive(src)
## Support path testing on all platforms
drive = ''
winpath = src.find(':')
if -1 != winpath and 10 > winpath:
(drive, tail) = src.split(':', 1)
if drive:
todo = [ '', drive.rstrip(':').lstrip('/').lstrip('\\') ]
todo.extend( tail.lstrip('/').lstrip('\\').split('\\') ) # c:\a => [a]
else: # os.name == 'posix'
todo = src.split('\\')
dst = '/'.join(todo)
return dst
def checkMkdir(work, debug=False):
"""
Verify arg permutations for directory mutex creation.
Keyword arguments:
None
Returns:
Exception on error
Note:
Exception() rather than self.assertTrue() is used in this test
function to enable scatch cleanup on test exit/failure conditions.
Not guaranteed by python closures on early exit.
"""
logging.debug("Testing: checkMkdir")
# On Windows, don't convert paths to POSIX
skipposix = sys.platform == "win32"
if skipposix:
path = os.path.abspath(__file__)
dirname_fun = os.path.dirname
else:
path = path2posix(os.path.abspath(__file__))
import posixpath
dirname_fun = posixpath.dirname
src = dirname_fun(path)
# root is 5 directories up from path
root = reduce(lambda x, _: dirname_fun(x), xrange(5), path)
rootP = path2posix(root)
srcP = path2posix(src)
workP = path2posix(work)
# C:\foo -vs- /c/foo
# [0] command paths use /c/foo
# [1] os.path.exists() on mingw() requires C:\
paths = [
"mkdir_bycall", # function generated
"mkdir_bydep", # explicit dependency
"mkdir_bygen", # by GENERATED_DIRS macro
]
## Use make from the parent "make check" call when available
cmd = { 'make': 'make' }
shell0 = os.environ.get('MAKE')
if shell0:
shell = os.path.splitext(shell0)[0] # strip: .exe, .py
if -1 != shell.find('make'):
print "MAKE COMMAND FOUND: %s" % (shell0)
cmd['make'] = shell0 if skipposix else path2posix(shell0)
args = []
args.append('%s' % (cmd['make']))
args.append('-C %s' % (work if skipposix else workP))
args.append("-f %s/testor.tmpl" % (src if skipposix else srcP))
args.append('topsrcdir=%s' % (root if skipposix else rootP))
args.append('deps_mkdir_bycall=%s' % paths[0])
args.append('deps_mkdir_bydep=%s' % paths[1])
args.append('deps_mkdir_bygen=%s' % paths[2])
args.append('checkup') # target
# Call will fail on mingw with output redirected ?!?
if debug:
pass
if False: # if not debug:
args.append('>/dev/null')
cmd = '%s' % (' '.join(args))
logging.debug("Running: %s" % (cmd))
rc = call(cmd, shell=True)
if rc:
raise Exception("make failed ($?=%s): cmd=%s" % (rc, cmd))
for i in paths:
path = os.path.join(work, i)
logging.debug("Did testing mkdir(%s) succeed?" % (path))
if not os.path.exists(path):
raise Exception("Test path %s does not exist" % (path))
def parseargs():
"""
Support additional command line arguments for testing
Returns:
hash - arguments of interested parsed from the command line
"""
opts = None
try:
import argparse2
parser = argparse.ArgumentParser()
parser.add_argument('--debug',
action="store_true",
default=False,
help='Enable debug mode')
# Cannot overload verbose, Verbose: False enables debugging
parser.add_argument('--verbose',
action="store_true",
default=False,
help='Enable verbose mode')
parser.add_argument('unittest_args',
nargs='*'
# help='Slurp/pass remaining args to unittest'
)
opts = parser.parse_args()
except ImportError:
pass
return opts
class TestMakeLogic(unittest.TestCase):
"""
Test suite used to validate makefile library rules and macros
"""
def setUp(self):
opts = myopts(None) # NameSpace object not hash
self.debug = opts['debug']
self.verbose = opts['verbose']
if self.debug:
logging.basicConfig(level=logging.DEBUG)
if self.verbose:
print
print "ENVIRONMENT DUMP:"
print '=' * 75
for k,v in os.environ.items():
print "env{%s} => %s" % (k, v)
print
def test_path2posix(self):
todo = {
'/dev/null' : '/dev/null',
'A:\\a\\b\\c' : '/A/a/b/c',
'B:/x/y' : '/B/x/y',
'C:/x\\y/z' : '/C/x/y/z',
'//FOO/bar/tans': '//FOO/bar/tans',
'//X\\a/b\\c/d' : '//X/a/b/c/d',
'\\c:mozilla\\sandbox': '/c/mozilla/sandbox',
}
for val,exp in todo.items():
found = path2posix(val)
tst = "posix2path(%s): %s != %s)" % (val, exp, found)
self.assertEqual(exp, found, "%s: invalid path detected" % (tst))
def test_mkdir(self):
"""
Verify directory creation rules and macros
"""
failed = True
# Exception handling is used to cleanup scratch space on error
try:
work = tempfile.mkdtemp()
checkMkdir(work, self.debug)
failed = False
finally:
if os.path.exists(work):
rmtree(work)
self.assertFalse(failed, "Unit test failure detected")
if __name__ == '__main__':
banner()
opts = parseargs()
myopts(opts)
if opts:
if hasattr(opts, 'unittest_args'):
sys.argv[1:] = opts.unittest_args
else:
sys.argv[1:] = []
unittest.main()

View file

@ -0,0 +1,6 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=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/.

View file

@ -0,0 +1,64 @@
# -*- makefile -*-
#
# 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/.
#
###########################################################################
## Intent: Standalone unit tests for makefile rules and target logic
###########################################################################
deps =$(NULL)
tgts =$(NULL)
ifdef VERBOSE
tgts += show
endif
# Define macros
include $(topsrcdir)/config/makefiles/makeutils.mk
include $(topsrcdir)/config/makefiles/autotargets.mk
##########################
## Verify threadsafe mkdir
##########################
ifdef deps_mkdir_bycall
deps += $(call mkdir_deps,deps_mkdir_bycall)
tgts += check_mkdir
endif
ifdef deps_mkdir_bydep
deps += $(foreach dir,$(deps_mkdir_bydep),$(dir)/.mkdir.done)
tgts += check_mkdir
endif
ifdef deps_mkdir_bygen
GENERATED_DIRS += $(deps_mkdir_bygen)
tgts += check_mkdir
endif
###########################
## Minimal environment load
###########################
MKDIR ?= mkdir -p
TOUCH ?= touch
INCLUDED_CONFIG_MK = 1
MOZILLA_DIR := $(topsrcdir)
include $(topsrcdir)/config/rules.mk
##-------------------##
##---] TARGETS [---##
##-------------------##
all::
# Quarks:
# o Use of 'all' would trigger export target processing
checkup: $(tgts)
# AUTO_DEPS - verify GENERATED_DIRS
check_mkdir: $(deps) $(AUTO_DEPS)
show:
@echo "tgts=[$(tgts)]"
@echo "deps=[$(deps)]"
find $(dir $(deps)) -print

View file

@ -0,0 +1 @@
<?xml version="1.0"><doc/>

View file

@ -0,0 +1,2 @@
This is ab-X-stuff.

View file

@ -0,0 +1,6 @@
#div: {
/* this is a ID rule, and should stay intact */
}
[lang=ab-X-stuff] {
/* this selector should match content with lang="ab-X-stuff" */
}

View file

@ -0,0 +1 @@
localized content

View file

@ -0,0 +1 @@
<?xml version="1.0"><otherdoc/>

View file

@ -0,0 +1,38 @@
#
# 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/.
LOCALE_SRCDIR = $(srcdir)/l10n
EXTERNALLY_MANAGED_MAKE_FILE := 1
STANDALONE_MAKEFILE := 1
JAR_MANIFEST := $(srcdir)/jar.mn
include $(topsrcdir)/config/config.mk
XPI_NAME = test_jar_mn
ACDEFINES += \
-DAB_CD=ab-X-stuff \
$(NULL)
MY_MANIFEST = $(if $(USE_EXTENSION_MANIFEST), $(FINAL_TARGET)/chrome.manifest, $(FINAL_TARGET)/chrome/test.manifest)
REF_MANIFEST = $(if $(USE_EXTENSION_MANIFEST),chrome.manifest,test.manifest)
check-%::
if test -d $(FINAL_TARGET); then rm -rf $(FINAL_TARGET); fi;
$(MAKE) realchrome MOZ_JAR_MAKER_FILE_FORMAT=$*
@echo 'Comparing manifests...'
@if ! sort $(MY_MANIFEST) | diff --text -U 0 $(srcdir)/../$(REF_MANIFEST).$* - ; then \
echo 'TEST-UNEXPECTED-FAIL | config/tests/$(REF_MANIFEST).$* | differing content in manifest!' ; \
false; \
fi
@if [ $* = 'jar' ]; then \
$(UNZIP) -d $(FINAL_TARGET)/chrome/test $(FINAL_TARGET)/chrome/test.jar; \
fi
@echo 'Comparing packages...'
@if ! diff -ur $(srcdir)/../ref-simple $(FINAL_TARGET)/chrome/test ; then\
echo 'TEST-UNEXPECTED-FAIL | config/tests/ref-simple | different content in jar' ; \
false; \
fi

View file

@ -0,0 +1,22 @@
#filter substitution
test.jar:
# test chrome with flags and path expansion
% content test %one
# test locale with variable substitution and path expansion
% locale @AB_CD@ %three
# test overlays
% overlay chrome://one/file.xml chrome://two/otherfile.xml
# test regular file, preprocessed file, preprocessed css
one/file.xml (thesrcdir/file.xml)
* one/preproc (thesrcdir/preproc.in)
* one/some.css (thesrcdir/some.css)
# test reference against topsrcdir
two/otherfile.xml (/config/tests/src-simple/thetopsrcdir/otherfile.xml)
# test reference against localesrcdir
three/l10nfile.txt (%l10nfile.txt)
test.jar:
# test manifest update the locale one was already added above, add skin
% locale @AB_CD@ %three
% skin test classic %one

View file

@ -0,0 +1 @@
localized content

View file

@ -0,0 +1,7 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=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/.
JAR_MANIFESTS += ['jar.mn']

View file

@ -0,0 +1 @@
<?xml version="1.0"><doc/>

View file

@ -0,0 +1,6 @@
# This would be an processed out
# pretty lengthy
# license header.
# For example.
#expand This is __AB_CD__.

View file

@ -0,0 +1,6 @@
#div: {
/* this is a ID rule, and should stay intact */
}
%expand [lang=__AB_CD__] {
/* this selector should match content with lang="ab-X-stuff" */
}

View file

@ -0,0 +1 @@
<?xml version="1.0"><otherdoc/>

View file

@ -0,0 +1,4 @@
content test test/one
locale ab-X-stuff test/three
overlay chrome://one/file.xml chrome://two/otherfile.xml
skin test classic test/one

View file

@ -0,0 +1,4 @@
content test jar:test.jar!/one
locale ab-X-stuff jar:test.jar!/three
overlay chrome://one/file.xml chrome://two/otherfile.xml
skin test classic jar:test.jar!/one

View file

@ -0,0 +1,4 @@
content test test/one
locale ab-X-stuff test/three
overlay chrome://one/file.xml chrome://two/otherfile.xml
skin test classic test/one

View file

@ -0,0 +1,116 @@
# 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 unicode_literals
import os
import sys
import unittest
from mozunit import main
from mozbuild.base import MozbuildObject
from mozpack.files import FileFinder
from mozbuild.frontend.context import Files
from mozbuild.frontend.reader import (
BuildReader,
EmptyConfig,
)
class TestMozbuildReading(unittest.TestCase):
# This hack is needed to appease running in automation.
def setUp(self):
self._old_env = dict(os.environ)
os.environ.pop('MOZCONFIG', None)
os.environ.pop('MOZ_OBJDIR', None)
def tearDown(self):
os.environ.clear()
os.environ.update(self._old_env)
def _mozbuilds(self, reader):
if not hasattr(self, '_mozbuild_paths'):
self._mozbuild_paths = set(reader.all_mozbuild_paths())
return self._mozbuild_paths
@unittest.skip('failing in SpiderMonkey builds')
def test_filesystem_traversal_reading(self):
"""Reading moz.build according to filesystem traversal works.
We attempt to read every known moz.build file via filesystem traversal.
If this test fails, it means that metadata extraction will fail.
"""
mb = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)
config = mb.config_environment
reader = BuildReader(config)
all_paths = self._mozbuilds(reader)
paths, contexts = reader.read_relevant_mozbuilds(all_paths)
self.assertEqual(set(paths), all_paths)
self.assertGreaterEqual(len(contexts), len(paths))
def test_filesystem_traversal_no_config(self):
"""Reading moz.build files via filesystem traversal mode with no build config.
This is similar to the above test except no build config is applied.
This will likely fail in more scenarios than the above test because a
lot of moz.build files assumes certain variables are present.
"""
here = os.path.abspath(os.path.dirname(__file__))
root = os.path.normpath(os.path.join(here, '..', '..'))
config = EmptyConfig(root)
reader = BuildReader(config)
all_paths = self._mozbuilds(reader)
paths, contexts = reader.read_relevant_mozbuilds(all_paths)
self.assertEqual(set(paths.keys()), all_paths)
self.assertGreaterEqual(len(contexts), len(paths))
def test_orphan_file_patterns(self):
if sys.platform == 'win32':
raise unittest.SkipTest('failing on windows builds')
mb = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False)
try:
config = mb.config_environment
except Exception as e:
if e.message == 'config.status not available. Run configure.':
raise unittest.SkipTest('failing without config.status')
raise
if config.substs['MOZ_BUILD_APP'] == 'js':
raise unittest.SkipTest('failing in Spidermonkey builds')
reader = BuildReader(config)
all_paths = self._mozbuilds(reader)
_, contexts = reader.read_relevant_mozbuilds(all_paths)
finder = FileFinder(config.topsrcdir, find_executables=False,
ignore=['obj*'])
def pattern_exists(pat):
return [p for p in finder.find(pat)] != []
for ctx in contexts:
if not isinstance(ctx, Files):
continue
relsrcdir = ctx.relsrcdir
if not pattern_exists(os.path.join(relsrcdir, ctx.pattern)):
self.fail("The pattern '%s' in a Files() entry in "
"'%s' corresponds to no files in the tree.\n"
"Please update this entry." %
(ctx.pattern, ctx.main_path))
test_files = ctx['IMPACTED_TESTS'].files
for p in test_files:
if not pattern_exists(os.path.relpath(p.full_path, config.topsrcdir)):
self.fail("The pattern '%s' in a dependent tests entry "
"in '%s' corresponds to no files in the tree.\n"
"Please update this entry." %
(p, ctx.main_path))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,431 @@
import subprocess
import unittest
import sys
import os
import imp
from tempfile import mkdtemp
from shutil import rmtree
import mozunit
from UserString import UserString
# Create a controlled configuration for use by expandlibs
config_win = {
'AR': 'lib',
'AR_EXTRACT': '',
'DLL_PREFIX': '',
'LIB_PREFIX': '',
'OBJ_SUFFIX': '.obj',
'LIB_SUFFIX': '.lib',
'DLL_SUFFIX': '.dll',
'IMPORT_LIB_SUFFIX': '.lib',
'LIBS_DESC_SUFFIX': '.desc',
'EXPAND_LIBS_LIST_STYLE': 'list',
}
config_unix = {
'AR': 'ar',
'AR_EXTRACT': 'ar -x',
'DLL_PREFIX': 'lib',
'LIB_PREFIX': 'lib',
'OBJ_SUFFIX': '.o',
'LIB_SUFFIX': '.a',
'DLL_SUFFIX': '.so',
'IMPORT_LIB_SUFFIX': '',
'LIBS_DESC_SUFFIX': '.desc',
'EXPAND_LIBS_LIST_STYLE': 'linkerscript',
}
config = sys.modules['expandlibs_config'] = imp.new_module('expandlibs_config')
from expandlibs import LibDescriptor, ExpandArgs, relativize
from expandlibs_gen import generate
from expandlibs_exec import ExpandArgsMore, SectionFinder
def Lib(name):
return config.LIB_PREFIX + name + config.LIB_SUFFIX
def Obj(name):
return name + config.OBJ_SUFFIX
def Dll(name):
return config.DLL_PREFIX + name + config.DLL_SUFFIX
def ImportLib(name):
if not len(config.IMPORT_LIB_SUFFIX): return Dll(name)
return config.LIB_PREFIX + name + config.IMPORT_LIB_SUFFIX
class TestRelativize(unittest.TestCase):
def test_relativize(self):
'''Test relativize()'''
os_path_exists = os.path.exists
def exists(path):
return True
os.path.exists = exists
self.assertEqual(relativize(os.path.abspath(os.curdir)), os.curdir)
self.assertEqual(relativize(os.path.abspath(os.pardir)), os.pardir)
self.assertEqual(relativize(os.path.join(os.curdir, 'a')), 'a')
self.assertEqual(relativize(os.path.join(os.path.abspath(os.curdir), 'a')), 'a')
# relativize is expected to return the absolute path if it is shorter
self.assertEqual(relativize(os.sep), os.sep)
os.path.exists = os.path.exists
class TestLibDescriptor(unittest.TestCase):
def test_serialize(self):
'''Test LibDescriptor's serialization'''
desc = LibDescriptor()
desc[LibDescriptor.KEYS[0]] = ['a', 'b']
self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0]))
desc['unsupported-key'] = ['a']
self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0]))
desc[LibDescriptor.KEYS[1]] = ['c', 'd', 'e']
self.assertEqual(str(desc),
"{0} = a b\n{1} = c d e"
.format(LibDescriptor.KEYS[0], LibDescriptor.KEYS[1]))
desc[LibDescriptor.KEYS[0]] = []
self.assertEqual(str(desc), "{0} = c d e".format(LibDescriptor.KEYS[1]))
def test_read(self):
'''Test LibDescriptor's initialization'''
desc_list = ["# Comment",
"{0} = a b".format(LibDescriptor.KEYS[1]),
"", # Empty line
"foo = bar", # Should be discarded
"{0} = c d e".format(LibDescriptor.KEYS[0])]
desc = LibDescriptor(desc_list)
self.assertEqual(desc[LibDescriptor.KEYS[1]], ['a', 'b'])
self.assertEqual(desc[LibDescriptor.KEYS[0]], ['c', 'd', 'e'])
self.assertEqual(False, 'foo' in desc)
def wrap_method(conf, wrapped_method):
'''Wrapper used to call a test with a specific configuration'''
def _method(self):
for key in conf:
setattr(config, key, conf[key])
self.init()
try:
wrapped_method(self)
except:
raise
finally:
self.cleanup()
return _method
class ReplicateTests(type):
'''Replicates tests for unix and windows variants'''
def __new__(cls, clsName, bases, dict):
for name in [key for key in dict if key.startswith('test_')]:
dict[name + '_unix'] = wrap_method(config_unix, dict[name])
dict[name + '_unix'].__doc__ = dict[name].__doc__ + ' (unix)'
dict[name + '_win'] = wrap_method(config_win, dict[name])
dict[name + '_win'].__doc__ = dict[name].__doc__ + ' (win)'
del dict[name]
return type.__new__(cls, clsName, bases, dict)
class TestCaseWithTmpDir(unittest.TestCase):
__metaclass__ = ReplicateTests
def init(self):
self.tmpdir = os.path.abspath(mkdtemp(dir=os.curdir))
def cleanup(self):
rmtree(self.tmpdir)
def touch(self, files):
for f in files:
open(f, 'w').close()
def tmpfile(self, *args):
return os.path.join(self.tmpdir, *args)
class TestExpandLibsGen(TestCaseWithTmpDir):
def test_generate(self):
'''Test library descriptor generation'''
files = [self.tmpfile(f) for f in
[Lib('a'), Obj('b'), Lib('c'), Obj('d'), Obj('e'), Lib('f')]]
self.touch(files[:-1])
self.touch([files[-1] + config.LIBS_DESC_SUFFIX])
desc = generate(files)
self.assertEqual(desc['OBJS'], [self.tmpfile(Obj(s)) for s in ['b', 'd', 'e']])
self.assertEqual(desc['LIBS'], [self.tmpfile(Lib(s)) for s in ['a', 'c', 'f']])
self.assertRaises(Exception, generate, files + [self.tmpfile(Obj('z'))])
self.assertRaises(Exception, generate, files + [self.tmpfile(Lib('y'))])
class TestExpandInit(TestCaseWithTmpDir):
def init(self):
''' Initializes test environment for library expansion tests'''
super(TestExpandInit, self).init()
# Create 2 fake libraries, each containing 3 objects, and the second
# including the first one and another library.
os.mkdir(self.tmpfile('libx'))
os.mkdir(self.tmpfile('liby'))
self.libx_files = [self.tmpfile('libx', Obj(f)) for f in ['g', 'h', 'i']]
self.liby_files = [self.tmpfile('liby', Obj(f)) for f in ['j', 'k', 'l']] + [self.tmpfile('liby', Lib('z'))]
self.touch(self.libx_files + self.liby_files)
with open(self.tmpfile('libx', Lib('x') + config.LIBS_DESC_SUFFIX), 'w') as f:
f.write(str(generate(self.libx_files)))
with open(self.tmpfile('liby', Lib('y') + config.LIBS_DESC_SUFFIX), 'w') as f:
f.write(str(generate(self.liby_files + [self.tmpfile('libx', Lib('x'))])))
# Create various objects and libraries
self.arg_files = [self.tmpfile(f) for f in [Lib('a'), Obj('b'), Obj('c'), Lib('d'), Obj('e')]]
# We always give library names (LIB_PREFIX/SUFFIX), even for
# dynamic/import libraries
self.files = self.arg_files + [self.tmpfile(ImportLib('f'))]
self.arg_files += [self.tmpfile(Lib('f'))]
self.touch(self.files)
def assertRelEqual(self, args1, args2):
self.assertEqual(args1, [relativize(a) for a in args2])
class TestExpandArgs(TestExpandInit):
def test_expand(self):
'''Test library expansion'''
# Expanding arguments means libraries with a descriptor are expanded
# with the descriptor content, and import libraries are used when
# a library doesn't exist
args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
# When a library exists at the same time as a descriptor, we still use
# the descriptor.
self.touch([self.tmpfile('libx', Lib('x'))])
args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
self.touch([self.tmpfile('liby', Lib('y'))])
args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))])
self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
class TestExpandArgsMore(TestExpandInit):
def test_makelist(self):
'''Test grouping object files in lists'''
# ExpandArgsMore does the same as ExpandArgs
with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
# But also has an extra method replacing object files with a list
args.makelist()
# self.files has objects at #1, #2, #4
self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
self.assertRelEqual(args[4:], [self.files[3]] + self.files[5:] + [self.tmpfile('liby', Lib('z'))])
# Check the list file content
objs = [f for f in self.files + self.liby_files + self.libx_files if f.endswith(config.OBJ_SUFFIX)]
if config.EXPAND_LIBS_LIST_STYLE == "linkerscript":
self.assertNotEqual(args[3][0], '@')
filename = args[3]
content = ['INPUT("{0}")'.format(relativize(f)) for f in objs]
with open(filename, 'r') as f:
self.assertEqual([l.strip() for l in f.readlines() if len(l.strip())], content)
elif config.EXPAND_LIBS_LIST_STYLE == "list":
self.assertEqual(args[3][0], '@')
filename = args[3][1:]
content = objs
with open(filename, 'r') as f:
self.assertRelEqual([l.strip() for l in f.readlines() if len(l.strip())], content)
tmp = args.tmp
# Check that all temporary files are properly removed
self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
def test_extract(self):
'''Test library extraction'''
# Divert subprocess.call
subprocess_call = subprocess.call
subprocess_check_output = subprocess.check_output
def call(args, **kargs):
if config.AR == 'lib':
self.assertEqual(args[:2], [config.AR, '-NOLOGO'])
self.assertTrue(args[2].startswith('-EXTRACT:'))
extract = [args[2][len('-EXTRACT:'):]]
self.assertTrue(extract)
args = args[3:]
else:
# The command called is always AR_EXTRACT
ar_extract = config.AR_EXTRACT.split()
self.assertEqual(args[:len(ar_extract)], ar_extract)
args = args[len(ar_extract):]
# Remaining argument is always one library
self.assertEqual(len(args), 1)
arg = args[0]
self.assertEqual(os.path.splitext(arg)[1], config.LIB_SUFFIX)
# Simulate file extraction
lib = os.path.splitext(os.path.basename(arg))[0]
if config.AR != 'lib':
extract = [lib, lib + '2']
extract = [os.path.join(kargs['cwd'], f) for f in extract]
if config.AR != 'lib':
extract = [Obj(f) for f in extract]
if not lib in extracted:
extracted[lib] = []
extracted[lib].extend(extract)
self.touch(extract)
subprocess.call = call
def check_output(args, **kargs):
# The command called is always AR
ar = config.AR
self.assertEqual(args[0:3], [ar, '-NOLOGO', '-LIST'])
# Remaining argument is always one library
self.assertRelEqual([os.path.splitext(arg)[1] for arg in args[3:]],
[config.LIB_SUFFIX])
# Simulate LIB -NOLOGO -LIST
lib = os.path.splitext(os.path.basename(args[3]))[0]
return '%s\n%s\n' % (Obj(lib), Obj(lib + '2'))
subprocess.check_output = check_output
# ExpandArgsMore does the same as ExpandArgs
self.touch([self.tmpfile('liby', Lib('y'))])
for iteration in (1, 2):
with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
files = self.files + self.liby_files + self.libx_files
self.assertRelEqual(args, ['foo', '-bar'] + files)
extracted = {}
# ExpandArgsMore also has an extra method extracting static libraries
# when possible
args.extract()
# With AR_EXTRACT, it uses the descriptors when there are, and
# actually
# extracts the remaining libraries
extracted_args = []
for f in files:
if f.endswith(config.LIB_SUFFIX):
base = os.path.splitext(os.path.basename(f))[0]
# On the first iteration, we test the behavior of
# extracting archives that don't have a copy of their
# contents next to them, which is to use the file
# extracted from the archive in a temporary directory.
# On the second iteration, we test extracting archives
# that do have a copy of their contents next to them,
# in which case those contents are used instead of the
# temporarily extracted files.
if iteration == 1:
extracted_args.extend(sorted(extracted[base]))
else:
dirname = os.path.dirname(f[len(self.tmpdir)+1:])
if base.endswith('f'):
dirname = os.path.join(dirname, 'foo', 'bar')
extracted_args.extend([self.tmpfile(dirname, Obj(base)), self.tmpfile(dirname, Obj(base + '2'))])
else:
extracted_args.append(f)
self.assertRelEqual(args, ['foo', '-bar'] + extracted_args)
tmp = args.tmp
# Check that all temporary files are properly removed
self.assertEqual(True, all([not os.path.exists(f) for f in tmp]))
# Create archives contents next to them for the second iteration.
base = os.path.splitext(Lib('_'))[0]
self.touch(self.tmpfile(Obj(base.replace('_', suffix))) for suffix in ('a', 'a2', 'd', 'd2'))
try:
os.makedirs(self.tmpfile('foo', 'bar'))
except:
pass
self.touch(self.tmpfile('foo', 'bar', Obj(base.replace('_', suffix))) for suffix in ('f', 'f2'))
self.touch(self.tmpfile('liby', Obj(base.replace('_', suffix))) for suffix in ('z', 'z2'))
# Restore subprocess.call and subprocess.check_output
subprocess.call = subprocess_call
subprocess.check_output = subprocess_check_output
class FakeProcess(object):
def __init__(self, out, err = ''):
self.out = out
self.err = err
def communicate(self):
return (self.out, self.err)
OBJDUMPS = {
'foo.o': '''
00000000 g F .text\t00000001 foo
00000000 g F .text._Z6foobarv\t00000001 _Z6foobarv
00000000 g F .text.hello\t00000001 hello
00000000 g F .text._ZThn4_6foobarv\t00000001 _ZThn4_6foobarv
''',
'bar.o': '''
00000000 g F .text.hi\t00000001 hi
00000000 g F .text.hot._Z6barbazv\t00000001 .hidden _Z6barbazv
''',
}
PRINT_ICF = '''
ld: ICF folding section '.text.hello' in file 'foo.o'into '.text.hi' in file 'bar.o'
ld: ICF folding section '.foo' in file 'foo.o'into '.foo' in file 'bar.o'
'''
class SubprocessPopen(object):
def __init__(self, test):
self.test = test
def __call__(self, args, stdout = None, stderr = None):
self.test.assertEqual(stdout, subprocess.PIPE)
self.test.assertEqual(stderr, subprocess.PIPE)
if args[0] == 'objdump':
self.test.assertEqual(args[1], '-t')
self.test.assertTrue(args[2] in OBJDUMPS)
return FakeProcess(OBJDUMPS[args[2]])
else:
return FakeProcess('', PRINT_ICF)
class TestSectionFinder(unittest.TestCase):
def test_getSections(self):
'''Test SectionFinder'''
# Divert subprocess.Popen
subprocess_popen = subprocess.Popen
subprocess.Popen = SubprocessPopen(self)
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
config.OBJ_SUFFIX = '.o'
config.LIB_SUFFIX = '.a'
finder = SectionFinder(['foo.o', 'bar.o'])
self.assertEqual(finder.getSections('foobar'), [])
self.assertEqual(finder.getSections('_Z6barbazv'), ['.text.hot._Z6barbazv'])
self.assertEqual(finder.getSections('_Z6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
self.assertEqual(finder.getSections('_ZThn4_6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
subprocess.Popen = subprocess_popen
class TestSymbolOrder(unittest.TestCase):
def test_getOrderedSections(self):
'''Test ExpandMoreArgs' _getOrderedSections'''
# Divert subprocess.Popen
subprocess_popen = subprocess.Popen
subprocess.Popen = SubprocessPopen(self)
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
config.OBJ_SUFFIX = '.o'
config.LIB_SUFFIX = '.a'
config.LD_PRINT_ICF_SECTIONS = ''
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
self.assertEqual(args._getOrderedSections(['_Z6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
subprocess.Popen = subprocess_popen
def test_getFoldedSections(self):
'''Test ExpandMoreArgs' _getFoldedSections'''
# Divert subprocess.Popen
subprocess_popen = subprocess.Popen
subprocess.Popen = SubprocessPopen(self)
config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
self.assertEqual(args._getFoldedSections(), {'.text.hello': ['.text.hi'], '.text.hi': ['.text.hello']})
subprocess.Popen = subprocess_popen
def test_getOrderedSectionsWithICF(self):
'''Test ExpandMoreArgs' _getOrderedSections, with ICF'''
# Divert subprocess.Popen
subprocess_popen = subprocess.Popen
subprocess.Popen = SubprocessPopen(self)
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
config.OBJ_SUFFIX = '.o'
config.LIB_SUFFIX = '.a'
config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hello', '.text.hi', '.text.hot._Z6barbazv'])
self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
subprocess.Popen = subprocess_popen
if __name__ == '__main__':
mozunit.main()

View file

@ -0,0 +1,86 @@
# 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 sys
import os
from mozunit import main, MockedOpen
import unittest
from tempfile import mkstemp
class TestMozUnit(unittest.TestCase):
def test_mocked_open(self):
# Create a temporary file on the file system.
(fd, path) = mkstemp()
with os.fdopen(fd, 'w') as file:
file.write('foobar');
self.assertFalse(os.path.exists('file1'))
self.assertFalse(os.path.exists('file2'))
with MockedOpen({'file1': 'content1',
'file2': 'content2'}):
self.assertTrue(os.path.exists('file1'))
self.assertTrue(os.path.exists('file2'))
self.assertFalse(os.path.exists('foo/file1'))
# Check the contents of the files given at MockedOpen creation.
self.assertEqual(open('file1', 'r').read(), 'content1')
self.assertEqual(open('file2', 'r').read(), 'content2')
# Check that overwriting these files alters their content.
with open('file1', 'w') as file:
file.write('foo')
self.assertTrue(os.path.exists('file1'))
self.assertEqual(open('file1', 'r').read(), 'foo')
# ... but not until the file is closed.
file = open('file2', 'w')
file.write('bar')
self.assertEqual(open('file2', 'r').read(), 'content2')
file.close()
self.assertEqual(open('file2', 'r').read(), 'bar')
# Check that appending to a file does append
with open('file1', 'a') as file:
file.write('bar')
self.assertEqual(open('file1', 'r').read(), 'foobar')
self.assertFalse(os.path.exists('file3'))
# Opening a non-existing file ought to fail.
self.assertRaises(IOError, open, 'file3', 'r')
self.assertFalse(os.path.exists('file3'))
# Check that writing a new file does create the file.
with open('file3', 'w') as file:
file.write('baz')
self.assertEqual(open('file3', 'r').read(), 'baz')
self.assertTrue(os.path.exists('file3'))
# Check the content of the file created outside MockedOpen.
self.assertEqual(open(path, 'r').read(), 'foobar')
# Check that overwriting a file existing on the file system
# does modify its content.
with open(path, 'w') as file:
file.write('bazqux')
self.assertEqual(open(path, 'r').read(), 'bazqux')
with MockedOpen():
# Check that appending to a file existing on the file system
# does modify its content.
with open(path, 'a') as file:
file.write('bazqux')
self.assertEqual(open(path, 'r').read(), 'foobarbazqux')
# Check that the file was not actually modified on the file system.
self.assertEqual(open(path, 'r').read(), 'foobar')
os.remove(path)
# Check that the file created inside MockedOpen wasn't actually
# created.
self.assertRaises(IOError, open, 'file3', 'r')
if __name__ == "__main__":
main()

View file

@ -0,0 +1,174 @@
import unittest
import os, sys, os.path, time
from tempfile import mkdtemp
from shutil import rmtree
import mozunit
from mozprocess import processhandler
from nsinstall import nsinstall
import nsinstall as nsinstall_module
NSINSTALL_PATH = nsinstall_module.__file__
# Run the non-ASCII tests on (a) Windows, or (b) any platform with
# sys.stdin.encoding set to UTF-8
import codecs
RUN_NON_ASCII_TESTS = (sys.platform == "win32" or
(sys.stdin.encoding is not None and
codecs.lookup(sys.stdin.encoding) == codecs.lookup("utf-8")))
class TestNsinstall(unittest.TestCase):
"""
Unit tests for nsinstall.py
"""
def setUp(self):
self.tmpdir = mkdtemp()
def tearDown(self):
# Unicode strings means non-ASCII children can be deleted properly on
# Windows
if sys.stdin.encoding is None:
tmpdir = unicode(self.tmpdir)
else:
tmpdir = unicode(self.tmpdir, sys.stdin.encoding)
rmtree(tmpdir)
# utility methods for tests
def touch(self, file, dir=None):
if dir is None:
dir = self.tmpdir
f = os.path.join(dir, file)
open(f, 'w').close()
return f
def mkdirs(self, dir):
d = os.path.join(self.tmpdir, dir)
os.makedirs(d)
return d
def test_nsinstall_D(self):
"Test nsinstall -D <dir>"
testdir = os.path.join(self.tmpdir, "test")
self.assertEqual(nsinstall(["-D", testdir]), 0)
self.assert_(os.path.isdir(testdir))
def test_nsinstall_basic(self):
"Test nsinstall <file> <dir>"
testfile = self.touch("testfile")
testdir = self.mkdirs("testdir")
self.assertEqual(nsinstall([testfile, testdir]), 0)
self.assert_(os.path.isfile(os.path.join(testdir, "testfile")))
def test_nsinstall_basic_recursive(self):
"Test nsinstall <dir> <dest dir>"
sourcedir = self.mkdirs("sourcedir")
self.touch("testfile", sourcedir)
Xfile = self.touch("Xfile", sourcedir)
copieddir = self.mkdirs("sourcedir/copieddir")
self.touch("testfile2", copieddir)
Xdir = self.mkdirs("sourcedir/Xdir")
self.touch("testfile3", Xdir)
destdir = self.mkdirs("destdir")
self.assertEqual(nsinstall([sourcedir, destdir,
'-X', Xfile,
'-X', Xdir]), 0)
testdir = os.path.join(destdir, "sourcedir")
self.assert_(os.path.isdir(testdir))
self.assert_(os.path.isfile(os.path.join(testdir, "testfile")))
self.assert_(not os.path.exists(os.path.join(testdir, "Xfile")))
self.assert_(os.path.isdir(os.path.join(testdir, "copieddir")))
self.assert_(os.path.isfile(os.path.join(testdir, "copieddir", "testfile2")))
self.assert_(not os.path.exists(os.path.join(testdir, "Xdir")))
def test_nsinstall_multiple(self):
"Test nsinstall <three files> <dest dir>"
testfiles = [self.touch("testfile1"),
self.touch("testfile2"),
self.touch("testfile3")]
testdir = self.mkdirs("testdir")
self.assertEqual(nsinstall(testfiles + [testdir]), 0)
for f in testfiles:
self.assert_(os.path.isfile(os.path.join(testdir,
os.path.basename(f))))
def test_nsinstall_dir_exists(self):
"Test nsinstall <dir> <dest dir>, where <dest dir>/<dir> already exists"
srcdir = self.mkdirs("test")
destdir = self.mkdirs("testdir/test")
self.assertEqual(nsinstall([srcdir, os.path.dirname(destdir)]), 0)
self.assert_(os.path.isdir(destdir))
def test_nsinstall_t(self):
"Test that nsinstall -t works (preserve timestamp)"
testfile = self.touch("testfile")
testdir = self.mkdirs("testdir")
# set mtime to now - 30 seconds
t = int(time.time()) - 30
os.utime(testfile, (t, t))
self.assertEqual(nsinstall(["-t", testfile, testdir]), 0)
destfile = os.path.join(testdir, "testfile")
self.assert_(os.path.isfile(destfile))
self.assertEqual(os.stat(testfile).st_mtime,
os.stat(destfile).st_mtime)
if sys.platform != "win32":
# can't run this test on windows, don't have real file modes there
def test_nsinstall_m(self):
"Test that nsinstall -m works (set mode)"
testfile = self.touch("testfile")
mode = 0o600
os.chmod(testfile, mode)
testdir = self.mkdirs("testdir")
self.assertEqual(nsinstall(["-m", "{0:04o}"
.format(mode), testfile, testdir]), 0)
destfile = os.path.join(testdir, "testfile")
self.assert_(os.path.isfile(destfile))
self.assertEqual(os.stat(testfile).st_mode,
os.stat(destfile).st_mode)
def test_nsinstall_d(self):
"Test that nsinstall -d works (create directories in target)"
# -d makes no sense to me, but ok!
testfile = self.touch("testfile")
testdir = self.mkdirs("testdir")
destdir = os.path.join(testdir, "subdir")
self.assertEqual(nsinstall(["-d", testfile, destdir]), 0)
self.assert_(os.path.isdir(os.path.join(destdir, "testfile")))
if RUN_NON_ASCII_TESTS:
def test_nsinstall_non_ascii(self):
"Test that nsinstall handles non-ASCII files"
filename = u"\u2325\u3452\u2415\u5081"
testfile = self.touch(filename)
testdir = self.mkdirs(u"\u4241\u1D04\u1414")
self.assertEqual(nsinstall([testfile.encode("utf-8"),
testdir.encode("utf-8")]), 0)
destfile = os.path.join(testdir, filename)
self.assert_(os.path.isfile(destfile))
def test_nsinstall_non_ascii_subprocess(self):
"Test that nsinstall as a subprocess handles non-ASCII files"
filename = u"\u2325\u3452\u2415\u5081"
testfile = self.touch(filename)
testdir = self.mkdirs(u"\u4241\u1D04\u1414")
# We don't use subprocess because it can't handle Unicode on
# Windows <http://bugs.python.org/issue1759845>. mozprocess calls
# CreateProcessW directly so it's perfect.
p = processhandler.ProcessHandlerMixin([sys.executable,
NSINSTALL_PATH,
testfile, testdir])
p.run()
rv = p.waitForFinish()
self.assertEqual(rv, 0)
destfile = os.path.join(testdir, filename)
self.assert_(os.path.isfile(destfile))
#TODO: implement -R, -l, -L and test them!
if __name__ == '__main__':
mozunit.main()

View file

@ -0,0 +1,80 @@
import unittest
import sys
import os.path
import mozunit
from printprereleasesuffix import get_prerelease_suffix
class TestGetPreReleaseSuffix(unittest.TestCase):
"""
Unit tests for the get_prerelease_suffix function
"""
def test_alpha_1(self):
"""test 1a1 version string"""
self.c = get_prerelease_suffix('1a1')
self.assertEqual(self.c, ' 1 Alpha 1')
def test_alpha_10(self):
"""test 1.2a10 version string"""
self.c = get_prerelease_suffix('1.2a10')
self.assertEqual(self.c, ' 1.2 Alpha 10')
def test_beta_3(self):
"""test 1.2.3b3 version string"""
self.c = get_prerelease_suffix('1.2.3b3')
self.assertEqual(self.c, ' 1.2.3 Beta 3')
def test_beta_30(self):
"""test 1.2.3.4b30 version string"""
self.c = get_prerelease_suffix('1.2.3.4b30')
self.assertEqual(self.c, ' 1.2.3.4 Beta 30')
def test_release_1(self):
"""test 1.2.3.4 version string"""
self.c = get_prerelease_suffix('1.2.3.4')
self.assertEqual(self.c, '')
def test_alpha_1_pre(self):
"""test 1.2a1pre version string"""
self.c = get_prerelease_suffix('1.2a1pre')
self.assertEqual(self.c, '')
def test_beta_10_pre(self):
"""test 3.4b10pre version string"""
self.c = get_prerelease_suffix('3.4b10pre')
self.assertEqual(self.c, '')
def test_pre_0(self):
"""test 1.2pre0 version string"""
self.c = get_prerelease_suffix('1.2pre0')
self.assertEqual(self.c, '')
def test_pre_1_b(self):
"""test 1.2pre1b version string"""
self.c = get_prerelease_suffix('1.2pre1b')
self.assertEqual(self.c, '')
def test_a_a(self):
"""test 1.2aa version string"""
self.c = get_prerelease_suffix('1.2aa')
self.assertEqual(self.c, '')
def test_b_b(self):
"""test 1.2bb version string"""
self.c = get_prerelease_suffix('1.2bb')
self.assertEqual(self.c, '')
def test_a_b(self):
"""test 1.2ab version string"""
self.c = get_prerelease_suffix('1.2ab')
self.assertEqual(self.c, '')
def test_plus(self):
"""test 1.2+ version string """
self.c = get_prerelease_suffix('1.2+')
self.assertEqual(self.c, '')
if __name__ == '__main__':
mozunit.main()

View file

@ -0,0 +1,201 @@
# 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
import shutil
import os
import re
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()