summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorGregory P. Smith <greg@krypto.org>2019-09-10 16:14:11 (GMT)
committerT. Wouters <thomas@python.org>2019-09-10 16:14:11 (GMT)
commit3f4db4a0bab073b768fae958e93288bd5d24eadd (patch)
treebc1758c4cb751641531f1440e8ff6177cbd31754 /Lib
parentafdeb189e97033b54cef44a7490d89d2013cb4e5 (diff)
downloadcpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.zip
cpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.tar.gz
cpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.tar.bz2
bpo-28494: Test existing zipfile working behavior. (GH-15853)
Add unittests for executables with a zipfile appended to test_zipfile, as zipfile.is_zipfile and zipfile.ZipFile work properly on these today.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_zipfile.py40
-rw-r--r--Lib/test/ziptestdata/README.md35
-rwxr-xr-xLib/test/ziptestdata/exe_with_z64bin0 -> 978 bytes
-rwxr-xr-xLib/test/ziptestdata/exe_with_zipbin0 -> 990 bytes
-rwxr-xr-xLib/test/ziptestdata/header.sh24
-rw-r--r--Lib/test/ziptestdata/testdata_module_inside_zip.py2
6 files changed, 101 insertions, 0 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index f9ee740..99d599e 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -5,6 +5,8 @@ import os
import pathlib
import posixpath
import struct
+import subprocess
+import sys
import time
import unittest
import zipfile
@@ -2470,6 +2472,44 @@ def build_alpharep_fixture():
return zf
+class TestExecutablePrependedZip(unittest.TestCase):
+ """Test our ability to open zip files with an executable prepended."""
+
+ def setUp(self):
+ self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata')
+ self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata')
+
+ def _test_zip_works(self, name):
+ # bpo-28494 sanity check: ensure is_zipfile works on these.
+ self.assertTrue(zipfile.is_zipfile(name),
+ f'is_zipfile failed on {name}')
+ # Ensure we can operate on these via ZipFile.
+ with zipfile.ZipFile(name) as zipfp:
+ for n in zipfp.namelist():
+ data = zipfp.read(n)
+ self.assertIn(b'FAVORITE_NUMBER', data)
+
+ def test_read_zip_with_exe_prepended(self):
+ self._test_zip_works(self.exe_zip)
+
+ def test_read_zip64_with_exe_prepended(self):
+ self._test_zip_works(self.exe_zip64)
+
+ @unittest.skipUnless(sys.executable, 'sys.executable required.')
+ @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
+ 'Test relies on #!/bin/bash working.')
+ def test_execute_zip2(self):
+ output = subprocess.check_output([self.exe_zip, sys.executable])
+ self.assertIn(b'number in executable: 5', output)
+
+ @unittest.skipUnless(sys.executable, 'sys.executable required.')
+ @unittest.skipUnless(os.access('/bin/bash', os.X_OK),
+ 'Test relies on #!/bin/bash working.')
+ def test_execute_zip64(self):
+ output = subprocess.check_output([self.exe_zip64, sys.executable])
+ self.assertIn(b'number in executable: 5', output)
+
+
class TestPath(unittest.TestCase):
def setUp(self):
self.fixtures = contextlib.ExitStack()
diff --git a/Lib/test/ziptestdata/README.md b/Lib/test/ziptestdata/README.md
new file mode 100644
index 0000000..6b9147d
--- /dev/null
+++ b/Lib/test/ziptestdata/README.md
@@ -0,0 +1,35 @@
+# Test data for `test_zipfile`
+
+The test executables in this directory are created manually from header.sh and
+the `testdata_module_inside_zip.py` file. You must have infozip's zip utility
+installed (`apt install zip` on Debian).
+
+## Purpose
+
+These are used to test executable files with an appended zipfile, in a scenario
+where the executable is _not_ a Python interpreter itself so our automatic
+zipimport machinery (that'd look for `__main__.py`) is not being used.
+
+## Updating the test executables
+
+If you update header.sh or the testdata_module_inside_zip.py file, rerun the
+commands below. These are expected to be rarely changed, if ever.
+
+### Standard old format (2.0) zip file
+
+```
+zip -0 zip2.zip testdata_module_inside_zip.py
+cat header.sh zip2.zip >exe_with_zip
+rm zip2.zip
+```
+
+### Modern format (4.5) zip64 file
+
+Redirecting from stdin forces infozip's zip tool to create a zip64.
+
+```
+zip -0 <testdata_module_inside_zip.py >zip64.zip
+cat header.sh zip64.zip >exe_with_z64
+rm zip64.zip
+```
+
diff --git a/Lib/test/ziptestdata/exe_with_z64 b/Lib/test/ziptestdata/exe_with_z64
new file mode 100755
index 0000000..82b03cf
--- /dev/null
+++ b/Lib/test/ziptestdata/exe_with_z64
Binary files differ
diff --git a/Lib/test/ziptestdata/exe_with_zip b/Lib/test/ziptestdata/exe_with_zip
new file mode 100755
index 0000000..c833cdf
--- /dev/null
+++ b/Lib/test/ziptestdata/exe_with_zip
Binary files differ
diff --git a/Lib/test/ziptestdata/header.sh b/Lib/test/ziptestdata/header.sh
new file mode 100755
index 0000000..52dc91a
--- /dev/null
+++ b/Lib/test/ziptestdata/header.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+INTERPRETER_UNDER_TEST="$1"
+if [[ ! -x "${INTERPRETER_UNDER_TEST}" ]]; then
+ echo "Interpreter must be the command line argument."
+ exit 4
+fi
+EXECUTABLE="$0" exec "${INTERPRETER_UNDER_TEST}" -E - <<END_OF_PYTHON
+import os
+import zipfile
+
+namespace = {}
+
+filename = os.environ['EXECUTABLE']
+print(f'Opening {filename} as a zipfile.')
+with zipfile.ZipFile(filename, mode='r') as exe_zip:
+ for file_info in exe_zip.infolist():
+ data = exe_zip.read(file_info)
+ exec(data, namespace, namespace)
+ break # Only use the first file in the archive.
+
+print('Favorite number in executable:', namespace["FAVORITE_NUMBER"])
+
+### Archive contents will be appended after this file. ###
+END_OF_PYTHON
diff --git a/Lib/test/ziptestdata/testdata_module_inside_zip.py b/Lib/test/ziptestdata/testdata_module_inside_zip.py
new file mode 100644
index 0000000..6f8dcd6
--- /dev/null
+++ b/Lib/test/ziptestdata/testdata_module_inside_zip.py
@@ -0,0 +1,2 @@
+# Test data file to be stored within a zip file.
+FAVORITE_NUMBER = 5