summaryrefslogtreecommitdiffstats
path: root/config/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /config/tests
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'config/tests')
-rw-r--r--config/tests/chrome.manifest.flat4
-rw-r--r--config/tests/python.ini7
-rw-r--r--config/tests/ref-simple/one/file.xml1
-rw-r--r--config/tests/ref-simple/one/preproc2
-rw-r--r--config/tests/ref-simple/one/some.css6
-rw-r--r--config/tests/ref-simple/three/l10nfile.txt1
-rw-r--r--config/tests/ref-simple/two/otherfile.xml1
-rw-r--r--config/tests/src-simple/Makefile.in38
-rw-r--r--config/tests/src-simple/jar.mn22
-rw-r--r--config/tests/src-simple/l10n/l10nfile.txt1
-rw-r--r--config/tests/src-simple/moz.build7
-rw-r--r--config/tests/src-simple/thesrcdir/file.xml1
-rw-r--r--config/tests/src-simple/thesrcdir/preproc.in6
-rw-r--r--config/tests/src-simple/thesrcdir/some.css6
-rw-r--r--config/tests/src-simple/thetopsrcdir/otherfile.xml1
-rw-r--r--config/tests/test.manifest.flat4
-rw-r--r--config/tests/test.manifest.jar4
-rw-r--r--config/tests/test.manifest.symlink4
-rw-r--r--config/tests/test_mozbuild_reading.py104
-rw-r--r--config/tests/unit-mozunit.py87
-rw-r--r--config/tests/unit-nsinstall.py185
-rw-r--r--config/tests/unit-printprereleasesuffix.py79
-rw-r--r--config/tests/unitMozZipFile.py214
23 files changed, 785 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.ini b/config/tests/python.ini
new file mode 100644
index 0000000000..3c29f36fa9
--- /dev/null
+++ b/config/tests/python.ini
@@ -0,0 +1,7 @@
+[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..bfdf259e86
--- /dev/null
+++ b/config/tests/unit-nsinstall.py
@@ -0,0 +1,185 @@
+import os
+import os.path
+import sys
+import time
+import unittest
+from shutil import rmtree
+from tempfile import mkdtemp
+
+import mozunit
+import nsinstall as nsinstall_module
+import six
+from mozprocess import processhandler
+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 = 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))
+
+ # 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 = 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.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()