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.
This commit is contained in:
parent
afdeb189e9
commit
3f4db4a0ba
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
# Test data file to be stored within a zip file.
|
||||
FAVORITE_NUMBER = 5
|
Loading…
Reference in New Issue