@@ -30,6 +30,17 @@ def test_find_token_indices_tracks_true_dollars_and_operators() -> None:
3030 }
3131
3232
33+ def test_find_token_indices_ignores_non_redirect_dollars () -> None :
34+ tokens = tokenize ('select 1 $ $> output.txt' )
35+
36+ assert hybrid_redirection .find_token_indices (tokens ) == {
37+ 'raw_dollar' : [2 , 3 ],
38+ 'true_dollar' : [3 ],
39+ 'angle_bracket' : [4 ],
40+ 'pipe' : [],
41+ }
42+
43+
3344# todo there are still corner cases combining custom delimiters and redirection
3445def test_find_sql_part_handles_valid_parse_custom_delimiter_and_invalid_sql (reset_hybrid_redirection ) -> None :
3546 hybrid_redirection .delimiter_command ._delimiter = '$$'
@@ -74,10 +85,27 @@ def test_assemble_tokens_quotes_identifier_and_string() -> None:
7485 assert hybrid_redirection .assemble_tokens (string_tokens ) == "'printf'"
7586
7687
88+ @pytest .mark .parametrize (
89+ ('file_part' , 'expected' ),
90+ [
91+ (None , None ),
92+ ('out.txt' , 'out.txt' ),
93+ (r'C:\Users\alice\output.csv' , r'C:\Users\alice\output.csv' ),
94+ ("'two words.txt'" , 'two words.txt' ),
95+ ('"two words.txt"' , 'two words.txt' ),
96+ ('two words.txt' , None ),
97+ ("'missing quote" , None ),
98+ ('' , None ),
99+ ],
100+ )
101+ def test_parse_redirect_filename (file_part : str | None , expected : str | None ) -> None :
102+ assert hybrid_redirection .parse_redirect_filename (file_part ) == expected
103+
104+
77105@pytest .mark .parametrize (
78106 ('file_part' , 'command_part' , 'expected' ),
79107 [
80- ('two words.txt' , None , True ),
108+ ('two words.txt' , None , False ),
81109 ('bad>file.txt' , None , True ),
82110 (None , None , True ),
83111 ('out.txt' , None , False ),
@@ -101,6 +129,24 @@ def test_get_redirect_components_valid_paths_and_logging() -> None:
101129 '>' ,
102130 'out.txt' ,
103131 )
132+ assert hybrid_redirection .get_redirect_components ('select 1 $> "two words.txt"' ) == (
133+ 'select 1' ,
134+ None ,
135+ '>' ,
136+ 'two words.txt' ,
137+ )
138+ assert hybrid_redirection .get_redirect_components ("select 1 $>> 'two words.txt'" ) == (
139+ 'select 1' ,
140+ None ,
141+ '>>' ,
142+ 'two words.txt' ,
143+ )
144+ assert hybrid_redirection .get_redirect_components (r'select 1 $> C:\Users\alice\output.csv' ) == (
145+ 'select 1' ,
146+ None ,
147+ '>' ,
148+ r'C:\Users\alice\output.csv' ,
149+ )
104150
105151
106152def test_get_redirect_components_returns_none_on_token_error (monkeypatch ) -> None :
@@ -116,7 +162,9 @@ def test_get_redirect_components_rejects_invalid_forms() -> None:
116162 assert hybrid_redirection .get_redirect_components ('select 1 $> out.txt $> other.txt' ) == (None , None , None , None )
117163 assert hybrid_redirection .get_redirect_components ('select 1 $> out.txt $| cat' ) == (None , None , None , None )
118164 assert hybrid_redirection .get_redirect_components ('select from $> out.txt' ) == (None , None , None , None )
119- assert hybrid_redirection .get_redirect_components ('select 1 $> "two words.txt"' ) == (None , None , None , None )
165+ assert hybrid_redirection .get_redirect_components ('select 1 $> two words.txt' ) == (None , None , None , None )
166+ assert hybrid_redirection .get_redirect_components ("select 1 $> 'missing quote" ) == (None , None , None , None )
167+ assert hybrid_redirection .get_redirect_components ('select 1 $> "bad>file.txt"' ) == (None , None , None , None )
120168
121169
122170def test_get_redirect_components_rejects_multiple_pipes_on_windows (monkeypatch ) -> None :
0 commit comments