2222"""
2323Test cases for the command line interface for tszip.
2424"""
25- import io
2625import pathlib
2726import sys
2827import tempfile
@@ -46,28 +45,30 @@ class TestException(Exception):
4645 __test__ = False
4746
4847
49- def capture_output (func , * args , ** kwargs ):
48+ def capture_output (func , * args , binary = False , ** kwargs ):
5049 """
5150 Runs the specified function and arguments, and returns the
5251 tuple (stdout, stderr) as strings.
5352 """
54- buffer_class = io .BytesIO
55- if sys .version_info [0 ] == 3 :
56- buffer_class = io .StringIO
57- stdout = sys .stdout
58- sys .stdout = buffer_class ()
59- stderr = sys .stderr
60- sys .stderr = buffer_class ()
61-
62- try :
63- func (* args , ** kwargs )
64- stdout_output = sys .stdout .getvalue ()
65- stderr_output = sys .stderr .getvalue ()
66- finally :
67- sys .stdout .close ()
68- sys .stdout = stdout
69- sys .stderr .close ()
70- sys .stderr = stderr
53+ with tempfile .TemporaryDirectory () as tmpdir :
54+ stdout_path = pathlib .Path (tmpdir ) / "stdout"
55+ stderr_path = pathlib .Path (tmpdir ) / "stderr"
56+ mode = "wb+" if binary else "w+"
57+ saved_stdout = sys .stdout
58+ saved_stderr = sys .stderr
59+ with open (stdout_path , mode ) as stdout , open (stderr_path , mode ) as stderr :
60+ try :
61+ sys .stdout = stdout
62+ sys .stderr = stderr
63+ with mock .patch ("signal.signal" ):
64+ func (* args , ** kwargs )
65+ stdout .seek (0 )
66+ stderr .seek (0 )
67+ stdout_output = stdout .read ()
68+ stderr_output = stderr .read ()
69+ finally :
70+ sys .stdout = saved_stdout
71+ sys .stderr = saved_stderr
7172 return stdout_output , stderr_output
7273
7374
@@ -85,6 +86,7 @@ def test_default_values(self):
8586 self .assertEqual (args .force , False )
8687 self .assertEqual (args .decompress , False )
8788 self .assertEqual (args .list , False )
89+ self .assertEqual (args .stdout , False )
8890 self .assertEqual (args .variants_only , False )
8991 self .assertEqual (args .suffix , ".tsz" )
9092
@@ -132,6 +134,20 @@ def run_tsunzip(self, command, mock_setup_logging):
132134 self .assertEqual (stdout , "" )
133135 self .assertTrue (mock_setup_logging .called )
134136
137+ @mock .patch ("tszip.cli.setup_logging" )
138+ def run_tszip_stdout (self , command , mock_setup_logging ):
139+ stdout , stderr = capture_output (cli .tszip_main , command , binary = True )
140+ self .assertEqual (stderr , b"" )
141+ self .assertTrue (mock_setup_logging .called )
142+ return stdout , stderr
143+
144+ @mock .patch ("tszip.cli.setup_logging" )
145+ def run_tsunzip_stdout (self , command , mock_setup_logging ):
146+ stdout , stderr = capture_output (cli .tsunzip_main , command , binary = True )
147+ self .assertEqual (stderr , b"" )
148+ self .assertTrue (mock_setup_logging .called )
149+ return stdout , stderr
150+
135151
136152class TestBadFiles (TestCli ):
137153 """
@@ -264,6 +280,16 @@ def test_bad_file_format(self):
264280 f"Error loading '{ self .trees_path } ': File not in KAS format"
265281 )
266282
283+ def test_compress_stdout (self ):
284+ self .assertTrue (self .trees_path .exists ())
285+ with mock .patch ("tszip.cli.exit" , side_effect = TestException ) as mocked_exit :
286+ with self .assertRaises (TestException ):
287+ self .run_tszip ([str (self .trees_path )] + ["-c" ])
288+ mocked_exit .assert_called_once_with (
289+ "Compressing to stdout not currently supported;"
290+ "Please see https://github.com/tskit-dev/tszip/issues/49"
291+ )
292+
267293
268294class DecompressSemanticsMixin :
269295 """
@@ -276,6 +302,14 @@ def setUp(self):
276302 self .ts = msprime .simulate (10 , mutation_rate = 10 , random_seed = 1 )
277303 self .compressed_path = pathlib .Path (self .tmpdir .name ) / "msprime.trees.tsz"
278304 tszip .compress (self .ts , self .compressed_path )
305+ self .trees_path1 = pathlib .Path (self .tmpdir .name ) / "msprime1.trees"
306+ self .trees_path2 = pathlib .Path (self .tmpdir .name ) / "msprime2.trees"
307+ self .ts1 = msprime .simulate (10 , mutation_rate = 10 , random_seed = 3 )
308+ self .ts2 = msprime .simulate (10 , mutation_rate = 5 , random_seed = 4 )
309+ self .compressed_path1 = pathlib .Path (self .tmpdir .name ) / "msprime1.trees.tsz"
310+ self .compressed_path2 = pathlib .Path (self .tmpdir .name ) / "msprime2.trees.tsz"
311+ tszip .compress (self .ts1 , self .compressed_path1 )
312+ tszip .compress (self .ts2 , self .compressed_path2 )
279313
280314 def tearDown (self ):
281315 del self .tmpdir
@@ -310,6 +344,37 @@ def test_keep(self):
310344 ts = tskit .load (str (outpath ))
311345 self .assertEqual (ts .tables , self .ts .tables )
312346
347+ def test_keep_stdout (self ):
348+ self .assertTrue (self .compressed_path .exists ())
349+ self .run_decompress_stdout ([str (self .compressed_path ), "--stdout" ])
350+ self .assertTrue (self .compressed_path .exists ())
351+ self .run_decompress_stdout ([str (self .compressed_path ), "-c" ])
352+ self .assertTrue (self .compressed_path .exists ())
353+
354+ def test_valid_stdout (self ):
355+ tmp_file = pathlib .Path (self .tmpdir .name ) / "stdout.trees"
356+ stdout , stderr = self .run_decompress_stdout (["-c" , str (self .compressed_path )])
357+ with open (tmp_file , "wb+" ) as tmp :
358+ tmp .write (stdout )
359+ ts = tskit .load (str (tmp_file ))
360+ self .assertEqual (ts .tables , self .ts .tables )
361+ self .assertTrue (self .compressed_path .exists ())
362+
363+ def test_valid_stdout_multiple (self ):
364+ tmp_file = pathlib .Path (self .tmpdir .name ) / "stdout.trees"
365+ with open (tmp_file , "wb+" ) as tmp :
366+ stdout , stderr = self .run_decompress_stdout (
367+ ["-c" , str (self .compressed_path1 ), str (self .compressed_path2 )]
368+ )
369+ tmp .write (stdout )
370+ with open (tmp_file ) as out_tmp :
371+ ts1 = tskit .load (out_tmp )
372+ ts2 = tskit .load (out_tmp )
373+ self .assertEqual (ts1 .tables , self .ts1 .tables )
374+ self .assertEqual (ts2 .tables , self .ts2 .tables )
375+ self .assertTrue (self .compressed_path1 .exists ())
376+ self .assertTrue (self .compressed_path2 .exists ())
377+
313378 def test_overwrite (self ):
314379 self .assertTrue (self .compressed_path .exists ())
315380 outpath = self .trees_path
@@ -357,11 +422,19 @@ class TestDecompressSemanticsTszip(DecompressSemanticsMixin, TestCli):
357422 def run_decompress (self , args ):
358423 self .run_tszip (["-d" ] + args )
359424
425+ def run_decompress_stdout (self , args ):
426+ x = self .run_tszip_stdout (["-d" ] + args )
427+ return x
428+
360429
361430class TestDecompressSemanticsTsunzip (DecompressSemanticsMixin , TestCli ):
362431 def run_decompress (self , args ):
363432 self .run_tsunzip (args )
364433
434+ def run_decompress_stdout (self , args ):
435+ x = self .run_tsunzip_stdout (args )
436+ return x
437+
365438
366439class TestList (unittest .TestCase ):
367440 """
0 commit comments