@@ -70,8 +70,8 @@ def _runner(out="", err="", **kwargs):
7070 runner = klass (Context (config = Config (overrides = kwargs )))
7171 if "exits" in kwargs :
7272 runner .returncode = Mock (return_value = kwargs .pop ("exits" ))
73- out_file = BytesIO (out .encode ())
74- err_file = BytesIO (err .encode ())
73+ out_file = BytesIO (out .encode () if isinstance ( out , str ) else out )
74+ err_file = BytesIO (err .encode () if isinstance ( err , str ) else err )
7575 runner .read_proc_stdout = out_file .read
7676 runner .read_proc_stderr = err_file .read
7777 return runner
@@ -539,6 +539,23 @@ def writes_and_flushes_to_stderr(self):
539539 err .write .assert_called_once_with ("whatever" )
540540 err .flush .assert_called_once_with ()
541541
542+ def handles_incremental_decoding (self ):
543+ # 𠜎 is 4 bytes in utf-8
544+ expected_out = "𠜎" * 50
545+ runner = self ._runner (out = expected_out )
546+ # Make sure every read returns a partial character.
547+ runner .read_chunk_size = 3
548+ out = StringIO ()
549+ runner .run (_ , out_stream = out )
550+ assert out .getvalue () == expected_out
551+
552+ def handles_trailing_partial_character (self ):
553+ out = StringIO ()
554+ # Only output the first 3 out of the 4 bytes in 𠜎
555+ self ._runner (out = b"\xf0 \xa0 \x9c " ).run (_ , out_stream = out )
556+ # Should produce a single unicode replacement character
557+ assert out .getvalue () == "�"
558+
542559 class input_stream_handling :
543560 # NOTE: actual autoresponder tests are elsewhere. These just test that
544561 # stdin works normally & can be overridden.
0 commit comments