diff options
Diffstat (limited to 'config/tests')
23 files changed, 782 insertions, 0 deletions
diff --git a/config/tests/chrome.manifest.flat b/config/tests/chrome.manifest.flat new file mode 100644 index 0000000000..6c0a7e5362 --- /dev/null +++ b/config/tests/chrome.manifest.flat @@ -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 diff --git a/config/tests/python.toml b/config/tests/python.toml new file mode 100644 index 0000000000..ed6cb41f40 --- /dev/null +++ b/config/tests/python.toml @@ -0,0 +1,10 @@ +[DEFAULT] +subsuite = "mozbuild" + +["test_mozbuild_reading.py"] + +["unit-mozunit.py"] + +["unit-nsinstall.py"] + +["unit-printprereleasesuffix.py"] diff --git a/config/tests/ref-simple/one/file.xml b/config/tests/ref-simple/one/file.xml new file mode 100644 index 0000000000..21aacb9bd6 --- /dev/null +++ b/config/tests/ref-simple/one/file.xml @@ -0,0 +1 @@ +<?xml version="1.0"><doc/> diff --git a/config/tests/ref-simple/one/preproc b/config/tests/ref-simple/one/preproc new file mode 100644 index 0000000000..3e04d6329d --- /dev/null +++ b/config/tests/ref-simple/one/preproc @@ -0,0 +1,2 @@ + +This is ab-X-stuff. diff --git a/config/tests/ref-simple/one/some.css b/config/tests/ref-simple/one/some.css new file mode 100644 index 0000000000..a8a3ee47cc --- /dev/null +++ b/config/tests/ref-simple/one/some.css @@ -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" */ +} diff --git a/config/tests/ref-simple/three/l10nfile.txt b/config/tests/ref-simple/three/l10nfile.txt new file mode 100644 index 0000000000..7ce7909abf --- /dev/null +++ b/config/tests/ref-simple/three/l10nfile.txt @@ -0,0 +1 @@ +localized content diff --git a/config/tests/ref-simple/two/otherfile.xml b/config/tests/ref-simple/two/otherfile.xml new file mode 100644 index 0000000000..6c50abf6fc --- /dev/null +++ b/config/tests/ref-simple/two/otherfile.xml @@ -0,0 +1 @@ +<?xml version="1.0"><otherdoc/> diff --git a/config/tests/src-simple/Makefile.in b/config/tests/src-simple/Makefile.in new file mode 100644 index 0000000000..7d3065a17a --- /dev/null +++ b/config/tests/src-simple/Makefile.in @@ -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 ! diff --text -U 0 $(MY_MANIFEST) $(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 diff --git a/config/tests/src-simple/jar.mn b/config/tests/src-simple/jar.mn new file mode 100644 index 0000000000..12ed607b66 --- /dev/null +++ b/config/tests/src-simple/jar.mn @@ -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 diff --git a/config/tests/src-simple/l10n/l10nfile.txt b/config/tests/src-simple/l10n/l10nfile.txt new file mode 100644 index 0000000000..7ce7909abf --- /dev/null +++ b/config/tests/src-simple/l10n/l10nfile.txt @@ -0,0 +1 @@ +localized content diff --git a/config/tests/src-simple/moz.build b/config/tests/src-simple/moz.build new file mode 100644 index 0000000000..d988c0ff9b --- /dev/null +++ b/config/tests/src-simple/moz.build @@ -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"] diff --git a/config/tests/src-simple/thesrcdir/file.xml b/config/tests/src-simple/thesrcdir/file.xml new file mode 100644 index 0000000000..21aacb9bd6 --- /dev/null +++ b/config/tests/src-simple/thesrcdir/file.xml @@ -0,0 +1 @@ +<?xml version="1.0"><doc/> diff --git a/config/tests/src-simple/thesrcdir/preproc.in b/config/tests/src-simple/thesrcdir/preproc.in new file mode 100644 index 0000000000..16d5024182 --- /dev/null +++ b/config/tests/src-simple/thesrcdir/preproc.in @@ -0,0 +1,6 @@ +# This would be an processed out +# pretty lengthy +# license header. +# For example. + +#expand This is __AB_CD__. diff --git a/config/tests/src-simple/thesrcdir/some.css b/config/tests/src-simple/thesrcdir/some.css new file mode 100644 index 0000000000..36171b4bba --- /dev/null +++ b/config/tests/src-simple/thesrcdir/some.css @@ -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" */ +} diff --git a/config/tests/src-simple/thetopsrcdir/otherfile.xml b/config/tests/src-simple/thetopsrcdir/otherfile.xml new file mode 100644 index 0000000000..6c50abf6fc --- /dev/null +++ b/config/tests/src-simple/thetopsrcdir/otherfile.xml @@ -0,0 +1 @@ +<?xml version="1.0"><otherdoc/> diff --git a/config/tests/test.manifest.flat b/config/tests/test.manifest.flat new file mode 100644 index 0000000000..0cf9dbf3ab --- /dev/null +++ b/config/tests/test.manifest.flat @@ -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 diff --git a/config/tests/test.manifest.jar b/config/tests/test.manifest.jar new file mode 100644 index 0000000000..e2700dfbe1 --- /dev/null +++ b/config/tests/test.manifest.jar @@ -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 diff --git a/config/tests/test.manifest.symlink b/config/tests/test.manifest.symlink new file mode 100644 index 0000000000..0cf9dbf3ab --- /dev/null +++ b/config/tests/test.manifest.symlink @@ -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 diff --git a/config/tests/test_mozbuild_reading.py b/config/tests/test_mozbuild_reading.py new file mode 100644 index 0000000000..17fecf1452 --- /dev/null +++ b/config/tests/test_mozbuild_reading.py @@ -0,0 +1,104 @@ +# 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 unittest + +from mozbuild.base import MozbuildObject +from mozbuild.frontend.context import Files +from mozbuild.frontend.reader import BuildReader, EmptyConfig +from mozpack.files import FileFinder +from mozunit import main + + +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 str(e) == "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, 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 + for p in ctx.patterns: + if not pattern_exists(os.path.join(relsrcdir, p)): + self.fail( + "The pattern '%s' in a Files() entry in " + "'%s' corresponds to no files in the tree.\n" + "Please update this entry." % (p, ctx.main_path) + ) + + +if __name__ == "__main__": + main() diff --git a/config/tests/unit-mozunit.py b/config/tests/unit-mozunit.py new file mode 100644 index 0000000000..6915d86718 --- /dev/null +++ b/config/tests/unit-mozunit.py @@ -0,0 +1,87 @@ +# 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 unittest +from tempfile import mkstemp + +from mozunit import MockedOpen, main + + +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() diff --git a/config/tests/unit-nsinstall.py b/config/tests/unit-nsinstall.py new file mode 100644 index 0000000000..e9990f928c --- /dev/null +++ b/config/tests/unit-nsinstall.py @@ -0,0 +1,179 @@ +import os +import os.path +import subprocess +import sys +import time +import unittest +from shutil import rmtree +from tempfile import mkdtemp + +import mozunit +import nsinstall as nsinstall_module +import six +from nsinstall import nsinstall + +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 = six.ensure_text(self.tmpdir) + else: + tmpdir = six.ensure_text(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) + + @unittest.skipIf(sys.platform == "win32", "Windows doesn't have real file modes") + 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"))) + + @unittest.skipIf(not RUN_NON_ASCII_TESTS, "Skipping non ascii tests") + def test_nsinstall_non_ascii(self): + "Test that nsinstall handles non-ASCII files" + filename = "\u2325\u3452\u2415\u5081" + testfile = self.touch(filename) + testdir = self.mkdirs("\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)) + + # Executing nsinstall.py with python 2 is not supported. + @unittest.skipIf( + not RUN_NON_ASCII_TESTS or sys.version_info[0] == 2, "Skipping non ascii tests" + ) + def test_nsinstall_non_ascii_subprocess(self): + "Test that nsinstall as a subprocess handles non-ASCII files" + filename = "\u2325\u3452\u2415\u5081" + testfile = self.touch(filename) + testdir = self.mkdirs("\u4241\u1D04\u1414") + p = subprocess.Popen([sys.executable, NSINSTALL_PATH, testfile, testdir]) + rv = p.wait() + + 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() diff --git a/config/tests/unit-printprereleasesuffix.py b/config/tests/unit-printprereleasesuffix.py new file mode 100644 index 0000000000..cebf48883c --- /dev/null +++ b/config/tests/unit-printprereleasesuffix.py @@ -0,0 +1,79 @@ +import unittest + +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() diff --git a/config/tests/unitMozZipFile.py b/config/tests/unitMozZipFile.py new file mode 100644 index 0000000000..4965dc1df3 --- /dev/null +++ b/config/tests/unitMozZipFile.py @@ -0,0 +1,214 @@ +# 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 copy +import os +import random +import shutil +import sys +import unittest +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__), "..")) + +import zipfile + +from MozZipFile 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() |