66import org .junit .contrib .java .lang .system .ProvideSystemProperty ;
77import org .junit .contrib .java .lang .system .RestoreSystemProperties ;
88import org .junit .rules .TestRule ;
9+
10+ import picocli .CommandLine .Help ;
911import picocli .CommandLine .Model .ArgSpec ;
1012import picocli .CommandLine .Option ;
1113import picocli .CommandLine .Parameters ;
@@ -37,11 +39,13 @@ static class Streams {
3739 PrintStream out = System .out ;
3840 PrintStream err = System .err ;
3941 InputStream in = System .in ;
42+ Boolean isTTY = Help .Ansi .tty ;
4043
4144 void reset () {
4245 System .setOut (out );
4346 System .setOut (err );
4447 System .setIn (in );
48+ Help .Ansi .tty = isTTY ;
4549 }
4650 }
4751
@@ -54,8 +58,13 @@ static class Capture {
5458 }
5559
5660 Capture (String input ) {
61+ this (input , true );
62+ }
63+
64+ Capture (String input , boolean isTTY ) {
5765 System .setOut (new PrintStream (baos ));
5866 System .setErr (new PrintStream (errBaos ));
67+ Help .Ansi .tty = isTTY ;
5968 if (input != null ) {
6069 System .setIn (new ByteArrayInputStream (input .getBytes ()));
6170 }
@@ -131,6 +140,44 @@ class App {
131140 }
132141 }
133142
143+ @ Test
144+ public void testInteractiveOptionReadsFromStdInNoTTY () {
145+ org .junit .Assume .assumeTrue (System .getProperty ("java.version" ).compareTo ("22" ) < 0 );
146+ class App {
147+ @ Option (names = "-x" , description = {"Pwd" , "line2" }, interactive = true ) int x ;
148+ @ Option (names = "-z" ) int z ;
149+ }
150+
151+ Streams streams = new Streams ();
152+ System .setProperty ("picocli.trace" , "DEBUG" );
153+ try {
154+ Capture capture = new Capture ("1234567890" , false );
155+
156+ App app = new App ();
157+ CommandLine cmd = new CommandLine (app );
158+ ParseResult result = cmd .parseArgs ("-x" );
159+ ArgSpec specX = result .matchedArgs ().get (0 );
160+ assertThat (specX .toString (), containsString ("App.x" ));
161+
162+ assertEquals ("" , capture .out ());
163+ assertEquals (1234567890 , app .x );
164+ assertEquals (0 , app .z );
165+
166+ String trace = capture .err ();
167+ assertThat (trace , containsString ("User entered 10 characters" ));
168+ assertThat (trace , containsString (
169+ "Setting " + specX .toString () + " to *****(masked) (interactive value)" ));
170+ assertThat (trace , not (containsString ("1234567890" )));
171+
172+ cmd .parseArgs ("-z" , "678" );
173+
174+ assertEquals (0 , app .x );
175+ assertEquals (678 , app .z );
176+ } finally {
177+ streams .reset ();
178+ }
179+ }
180+
134181 @ Test
135182 public void testInteractiveOptionReadsFromStdInWithEchoing () {
136183 class App {
@@ -162,6 +209,37 @@ class App {
162209 }
163210 }
164211
212+ @ Test
213+ public void testInteractiveOptionReadsFromStdInWithEchoingNoTTY () {
214+ class App {
215+ @ Option (names = "-x" , description = {"Pwd" , "line2" }, interactive = true , echo = true ) int x ;
216+ }
217+
218+ Streams streams = new Streams ();
219+ System .setProperty ("picocli.trace" , "DEBUG" );
220+ try {
221+ Capture capture = new Capture ("1234567890" , false );
222+
223+ App app = new App ();
224+ CommandLine cmd = new CommandLine (app );
225+ ParseResult result = cmd .parseArgs ("-x" );
226+ ArgSpec specX = result .matchedArgs ().get (0 );
227+ assertThat (specX .toString (), containsString ("App.x" ));
228+
229+ assertEquals ("" , capture .out ());
230+ assertEquals (1234567890 , app .x );
231+
232+ String trace = capture .err ();
233+ assertThat (trace , containsString ("User entered 1234567890" ));
234+ assertThat (trace , containsString (
235+ "Setting " + specX .toString () + " to 1234567890" ));
236+ assertThat (trace , not (containsString ("10 characters" )));
237+ assertThat (trace , not (containsString ("***" )));
238+ } finally {
239+ streams .reset ();
240+ }
241+ }
242+
165243 @ Test
166244 public void testInteractiveOptionWithoutDescriptionStandardPrompt () {
167245 org .junit .Assume .assumeTrue (System .getProperty ("java.version" ).compareTo ("22" ) < 0 );
0 commit comments