1- from io import StringIO
1+ from io import BytesIO , TextIOWrapper
22from textwrap import dedent
33from unittest .mock import Mock
44
77from streamlink_cli .console import ConsoleOutput
88
99
10+ def getvalue (output : TextIOWrapper , size : int = - 1 ):
11+ output .seek (0 )
12+
13+ return output .read (size )
14+
15+
1016class TestConsoleOutput :
1117 @pytest .fixture (autouse = True )
1218 def _isatty (self , request : pytest .FixtureRequest , monkeypatch : pytest .MonkeyPatch ):
1319 isatty = not request .function .__name__ .endswith ("_no_tty" )
1420 monkeypatch .setattr ("sys.stdin.isatty" , lambda : isatty )
1521
16- def test_msg (self ):
17- output = StringIO ()
22+ @pytest .fixture ()
23+ def output (self , request : pytest .FixtureRequest ):
24+ params = getattr (request , "param" , {})
25+ params .setdefault ("encoding" , "utf-8" )
26+ params .setdefault ("errors" , "backslashreplace" )
27+ output = TextIOWrapper (BytesIO (), ** params )
28+
29+ return output
30+
31+ @pytest .mark .parametrize (("output" , "expected" ), [
32+ pytest .param (
33+ {"encoding" : "utf-8" },
34+ "Bär: 🐻" ,
35+ id = "utf-8 encoding" ,
36+ ),
37+ pytest .param (
38+ {"encoding" : "ascii" },
39+ "B\\ xe4r: \\ U0001f43b" , # Unicode character: "Bear Face" (U+1F43B)
40+ id = "ascii encoding" ,
41+ ),
42+ ], indirect = ["output" ])
43+ def test_msg (self , output : TextIOWrapper , expected : str ):
1844 console = ConsoleOutput (output )
19- console .msg ("foo " )
45+ console .msg ("Bär: 🐻 " )
2046 console .msg_json ({"test" : 1 })
21- assert output .getvalue () == "foo\n "
22-
23- def test_msg_json (self ):
24- output = StringIO ()
47+ assert getvalue (output ) == f"{ expected } \n "
48+
49+ @pytest .mark .parametrize (("output" , "expected" ), [
50+ pytest .param (
51+ {"encoding" : "utf-8" },
52+ "Bär: 🐻" ,
53+ id = "utf-8 encoding" ,
54+ ),
55+ pytest .param (
56+ {"encoding" : "ascii" },
57+ "B\\ u00e4r: \\ ud83d\\ udc3b" , # Unicode character: "Bear Face" (U+1F43B) - UTF-16: 0xD83D 0xDC3B
58+ id = "ascii encoding" ,
59+ ),
60+ ], indirect = ["output" ])
61+ def test_msg_json (self , output : TextIOWrapper , expected : str ):
2562 console = ConsoleOutput (output , json = True )
2663 console .msg ("foo" )
27- console .msg_json ({"test" : 1 })
28- assert output . getvalue () == '{ \n "test": 1 \n }\n '
64+ console .msg_json ({"test" : "Bär: 🐻" })
65+ assert getvalue (output ) == f'{{ \n "test": " { expected } " \n } }\n '
2966
30- def test_msg_json_object (self ):
31- output = StringIO ()
67+ def test_msg_json_object (self , output : TextIOWrapper ):
3268 console = ConsoleOutput (output , json = True )
33- console .msg_json (Mock (__json__ = Mock ( return_value = {"test" : 1 })))
34- assert output . getvalue () == '{\n "test": 1 \n }\n '
69+ console .msg_json (Mock (__json__ = lambda : {"test" : "Hello world, Γειά σου Κόσμε, こんにちは世界" })) # noqa: RUF001
70+ assert getvalue (output ) == '{\n "test": "Hello world, Γειά σου Κόσμε, こんにちは世界" \n }\n ' # noqa: RUF001
3571
36- def test_msg_json_list (self ):
37- output = StringIO ()
72+ def test_msg_json_list (self , output : TextIOWrapper ):
3873 console = ConsoleOutput (output , json = True )
39- test_list = ["foo " , "bar" ]
74+ test_list = ["Hello world, Γειά σου Κόσμε, こんにちは世界 " , '"🐻"' ] # noqa: RUF001
4075 console .msg_json (test_list )
41- assert output . getvalue () == '[\n "foo ",\n "bar" \ n ]\n '
76+ assert getvalue (output ) == '[\n "Hello world, Γειά σου Κόσμε, こんにちは世界 ",\n "\\ "🐻 \\ "" \ n ]\n ' # noqa: RUF001
4277
43- def test_msg_json_merge_object (self ):
44- output = StringIO ()
78+ def test_msg_json_merge_object (self , output : TextIOWrapper ):
4579 console = ConsoleOutput (output , json = True )
4680 test_obj1 = {"test" : 1 , "foo" : "foo" }
4781 test_obj2 = Mock (__json__ = Mock (return_value = {"test" : 2 }))
4882 console .msg_json (test_obj1 , test_obj2 , ["qux" ], foo = "bar" , baz = "qux" )
49- assert output . getvalue () == dedent ("""
83+ assert getvalue (output ) == dedent ("""
5084 {
5185 "test": 2,
5286 "foo": "bar",
@@ -55,13 +89,12 @@ def test_msg_json_merge_object(self):
5589 """ ).lstrip ()
5690 assert list (test_obj1 .items ()) == [("test" , 1 ), ("foo" , "foo" )]
5791
58- def test_msg_json_merge_list (self ):
59- output = StringIO ()
92+ def test_msg_json_merge_list (self , output : TextIOWrapper ):
6093 console = ConsoleOutput (output , json = True )
6194 test_list1 = ["foo" , "bar" ]
6295 test_list2 = Mock (__json__ = Mock (return_value = {"foo" : "bar" }))
6396 console .msg_json (test_list1 , ["baz" ], test_list2 , {"foo" : "bar" }, foo = "bar" , baz = "qux" )
64- assert output . getvalue () == dedent ("""
97+ assert getvalue (output ) == dedent ("""
6598 [
6699 "foo",
67100 "bar",
@@ -80,45 +113,40 @@ def test_msg_json_merge_list(self):
80113 """ ).lstrip ()
81114 assert test_list1 == ["foo" , "bar" ]
82115
83- def test_ask (self , monkeypatch : pytest .MonkeyPatch ):
116+ def test_ask (self , monkeypatch : pytest .MonkeyPatch , output : TextIOWrapper ):
84117 monkeypatch .setattr ("builtins.input" , Mock (return_value = "hello" ))
85118
86- output = StringIO ()
87119 console = ConsoleOutput (output )
88120 assert console .ask ("test: " ) == "hello"
89- assert output . getvalue () == "test: "
121+ assert getvalue (output ) == "test: "
90122
91- def test_ask_no_tty (self , monkeypatch : pytest .MonkeyPatch ):
123+ def test_ask_no_tty (self , monkeypatch : pytest .MonkeyPatch , output : TextIOWrapper ):
92124 mock_input = Mock ()
93125 monkeypatch .setattr ("builtins.input" , mock_input )
94126
95- output = StringIO ()
96127 console = ConsoleOutput (output )
97128 assert console .ask ("test: " ) is None
98- assert output . getvalue () == ""
129+ assert getvalue (output ) == ""
99130 assert mock_input .call_args_list == []
100131
101- def test_ask_input_exception (self , monkeypatch : pytest .MonkeyPatch ):
132+ def test_ask_input_exception (self , monkeypatch : pytest .MonkeyPatch , output : TextIOWrapper ):
102133 monkeypatch .setattr ("builtins.input" , Mock (side_effect = ValueError ))
103134
104- output = StringIO ()
105135 console = ConsoleOutput (output )
106136 assert console .ask ("test: " ) is None
107- assert output . getvalue () == "test: "
137+ assert getvalue (output ) == "test: "
108138
109- def test_askpass (self , monkeypatch : pytest .MonkeyPatch ):
139+ def test_askpass (self , monkeypatch : pytest .MonkeyPatch , output : TextIOWrapper ):
110140 def getpass (prompt , stream ):
111141 stream .write (prompt )
112142 return "hello"
113143
114144 monkeypatch .setattr ("streamlink_cli.console.getpass" , getpass )
115145
116- output = StringIO ()
117146 console = ConsoleOutput (output )
118147 assert console .askpass ("test: " ) == "hello"
119- assert output . getvalue () == "test: "
148+ assert getvalue (output ) == "test: "
120149
121- def test_askpass_no_tty (self ):
122- output = StringIO ()
150+ def test_askpass_no_tty (self , output : TextIOWrapper ):
123151 console = ConsoleOutput (output )
124152 assert console .askpass ("test: " ) is None
0 commit comments