99import zipapp
1010import zipfile
1111
12+ from unittest .mock import patch
1213
1314class ZipAppTest (unittest .TestCase ):
1415
@@ -28,6 +29,15 @@ def test_create_archive(self):
2829 zipapp .create_archive (str (source ), str (target ))
2930 self .assertTrue (target .is_file ())
3031
32+ def test_create_archive_with_pathlib (self ):
33+ # Test packing a directory using Path objects for source and target.
34+ source = self .tmpdir / 'source'
35+ source .mkdir ()
36+ (source / '__main__.py' ).touch ()
37+ target = self .tmpdir / 'source.pyz'
38+ zipapp .create_archive (source , target )
39+ self .assertTrue (target .is_file ())
40+
3141 def test_create_archive_with_subdirs (self ):
3242 # Test packing a directory includes entries for subdirectories.
3343 source = self .tmpdir / 'source'
@@ -184,6 +194,18 @@ def test_write_shebang_to_fileobj(self):
184194 zipapp .create_archive (str (target ), new_target , interpreter = 'python2.7' )
185195 self .assertTrue (new_target .getvalue ().startswith (b'#!python2.7\n ' ))
186196
197+ def test_read_from_pathobj (self ):
198+ # Test that we can copy an archive using an pathlib.Path object
199+ # for the source.
200+ source = self .tmpdir / 'source'
201+ source .mkdir ()
202+ (source / '__main__.py' ).touch ()
203+ target1 = self .tmpdir / 'target1.pyz'
204+ target2 = self .tmpdir / 'target2.pyz'
205+ zipapp .create_archive (source , target1 , interpreter = 'python' )
206+ zipapp .create_archive (target1 , target2 , interpreter = 'python2.7' )
207+ self .assertEqual (zipapp .get_interpreter (target2 ), 'python2.7' )
208+
187209 def test_read_from_fileobj (self ):
188210 # Test that we can copy an archive using an open file object.
189211 source = self .tmpdir / 'source'
@@ -246,5 +268,82 @@ def test_no_shebang_is_not_executable(self):
246268 self .assertFalse (target .stat ().st_mode & stat .S_IEXEC )
247269
248270
271+ class ZipAppCmdlineTest (unittest .TestCase ):
272+
273+ """Test zipapp module command line API."""
274+
275+ def setUp (self ):
276+ tmpdir = tempfile .TemporaryDirectory ()
277+ self .addCleanup (tmpdir .cleanup )
278+ self .tmpdir = pathlib .Path (tmpdir .name )
279+
280+ def make_archive (self ):
281+ # Test that an archive with no shebang line is not made executable.
282+ source = self .tmpdir / 'source'
283+ source .mkdir ()
284+ (source / '__main__.py' ).touch ()
285+ target = self .tmpdir / 'source.pyz'
286+ zipapp .create_archive (source , target )
287+ return target
288+
289+ def test_cmdline_create (self ):
290+ # Test the basic command line API.
291+ source = self .tmpdir / 'source'
292+ source .mkdir ()
293+ (source / '__main__.py' ).touch ()
294+ args = [str (source )]
295+ zipapp .main (args )
296+ target = source .with_suffix ('.pyz' )
297+ self .assertTrue (target .is_file ())
298+
299+ def test_cmdline_copy (self ):
300+ # Test copying an archive.
301+ original = self .make_archive ()
302+ target = self .tmpdir / 'target.pyz'
303+ args = [str (original ), '-o' , str (target )]
304+ zipapp .main (args )
305+ self .assertTrue (target .is_file ())
306+
307+ def test_cmdline_copy_inplace (self ):
308+ # Test copying an archive in place fails.
309+ original = self .make_archive ()
310+ target = self .tmpdir / 'target.pyz'
311+ args = [str (original ), '-o' , str (original )]
312+ with self .assertRaises (SystemExit ) as cm :
313+ zipapp .main (args )
314+ # Program should exit with a non-zero returm code.
315+ self .assertTrue (cm .exception .code )
316+
317+ def test_cmdline_copy_change_main (self ):
318+ # Test copying an archive doesn't allow changing __main__.py.
319+ original = self .make_archive ()
320+ target = self .tmpdir / 'target.pyz'
321+ args = [str (original ), '-o' , str (target ), '-m' , 'foo:bar' ]
322+ with self .assertRaises (SystemExit ) as cm :
323+ zipapp .main (args )
324+ # Program should exit with a non-zero returm code.
325+ self .assertTrue (cm .exception .code )
326+
327+ @patch ('sys.stdout' , new_callable = io .StringIO )
328+ def test_info_command (self , mock_stdout ):
329+ # Test the output of the info command.
330+ target = self .make_archive ()
331+ args = [str (target ), '--info' ]
332+ with self .assertRaises (SystemExit ) as cm :
333+ zipapp .main (args )
334+ # Program should exit with a zero returm code.
335+ self .assertEqual (cm .exception .code , 0 )
336+ self .assertEqual (mock_stdout .getvalue (), "Interpreter: <none>\n " )
337+
338+ def test_info_error (self ):
339+ # Test the info command fails when the archive does not exist.
340+ target = self .tmpdir / 'dummy.pyz'
341+ args = [str (target ), '--info' ]
342+ with self .assertRaises (SystemExit ) as cm :
343+ zipapp .main (args )
344+ # Program should exit with a non-zero returm code.
345+ self .assertTrue (cm .exception .code )
346+
347+
249348if __name__ == "__main__" :
250349 unittest .main ()
0 commit comments