Skip to content

Commit 38ce784

Browse files
authored
Capturing CTRL+D EOF to exit the shell
* Capturing CTRL+D (EOF) to exit the shell * replace junit to assertj * fix hang on testing
1 parent 3556352 commit 38ce784

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

spring-shell-core/src/main/java/org/springframework/shell/jline/InteractiveShellRunner.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.shell.jline;
1818

19+
import org.jline.reader.EndOfFileException;
1920
import org.jline.reader.LineReader;
2021
import org.jline.reader.UserInterruptException;
2122
import org.jline.utils.AttributedString;
@@ -101,6 +102,9 @@ public Input readInput() {
101102
return Input.EMPTY;
102103
}
103104
}
105+
catch (EndOfFileException e) {
106+
throw new ExitRequest(1);
107+
}
104108
return new ParsedLineInput(lineReader.getParsedLine());
105109
}
106110
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package org.springframework.shell.jline;
2+
3+
import org.jline.reader.LineReader;
4+
import org.jline.reader.LineReaderBuilder;
5+
import org.jline.terminal.Attributes;
6+
import org.jline.terminal.impl.ExternalTerminal;
7+
import org.jline.utils.AttributedString;
8+
import org.jline.utils.AttributedStyle;
9+
import org.junit.jupiter.api.Test;
10+
import org.springframework.shell.ExitRequest;
11+
12+
import static org.assertj.core.api.Assertions.*;
13+
14+
import java.io.ByteArrayOutputStream;
15+
import java.io.PipedInputStream;
16+
import java.io.PipedOutputStream;
17+
import java.nio.charset.StandardCharsets;
18+
import java.util.concurrent.CountDownLatch;
19+
20+
public class InteractiveShellRunnerTests {
21+
22+
private PipedOutputStream outIn;
23+
private InteractiveShellRunner.JLineInputProvider jLineInputProvider;
24+
25+
26+
private PromptProvider dummyPromptProvider() {
27+
return () -> new AttributedString("dummy-shell:>", AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW));
28+
}
29+
30+
private void initForShortcutKeyTest() throws Exception {
31+
PipedInputStream in = new PipedInputStream();
32+
outIn = new PipedOutputStream(in);
33+
ByteArrayOutputStream out = new ByteArrayOutputStream();
34+
ExternalTerminal terminal = new ExternalTerminal("foo", "ansi", in, out, StandardCharsets.UTF_8);
35+
Attributes attributes = terminal.getAttributes();
36+
attributes.setLocalFlag(Attributes.LocalFlag.ISIG, true);
37+
attributes.setControlChar(Attributes.ControlChar.VINTR, 3);
38+
terminal.setAttributes(attributes);
39+
LineReaderBuilder builder =
40+
LineReaderBuilder.builder()
41+
.terminal(terminal);
42+
43+
LineReader lineReader = builder.build();
44+
jLineInputProvider = new InteractiveShellRunner.JLineInputProvider(lineReader, dummyPromptProvider());
45+
}
46+
47+
@Test
48+
public void testClearWithCtrlC() throws Exception {
49+
50+
initForShortcutKeyTest();
51+
52+
CountDownLatch startLatch = new CountDownLatch(1);
53+
CountDownLatch endLatch = new CountDownLatch(1);
54+
Thread writeThread = new Thread(() -> {
55+
try {
56+
startLatch.await();
57+
outIn.write('a');
58+
outIn.write(3);
59+
endLatch.await();
60+
} catch (Exception e) {
61+
e.printStackTrace();
62+
}
63+
});
64+
Thread readThread = new Thread(() -> {
65+
assertThatNoException().isThrownBy(() -> assertThat(jLineInputProvider.readInput().rawText()).isEqualTo(""));
66+
endLatch.countDown();
67+
});
68+
readThread.start();
69+
startLatch.countDown();
70+
writeThread.start();
71+
72+
readThread.join();
73+
writeThread.join();
74+
}
75+
76+
77+
@Test
78+
public void testExitWithCtrlC() throws Exception {
79+
80+
initForShortcutKeyTest();
81+
82+
CountDownLatch startLatch = new CountDownLatch(1);
83+
CountDownLatch endLatch = new CountDownLatch(1);
84+
Thread writeThread = new Thread(() -> {
85+
try {
86+
startLatch.await();
87+
outIn.write(3);
88+
endLatch.await();
89+
} catch (Exception e) {
90+
e.printStackTrace();
91+
}
92+
});
93+
Thread readThread = new Thread(() -> {
94+
assertThatThrownBy(jLineInputProvider::readInput).isInstanceOf(ExitRequest.class);
95+
endLatch.countDown();
96+
});
97+
readThread.start();
98+
startLatch.countDown();
99+
writeThread.start();
100+
101+
readThread.join();
102+
writeThread.join();
103+
}
104+
105+
@Test
106+
public void testExitWithCtrlD() throws Exception {
107+
108+
initForShortcutKeyTest();
109+
110+
CountDownLatch startLatch = new CountDownLatch(1);
111+
CountDownLatch endLatch = new CountDownLatch(1);
112+
Thread writeThread = new Thread(() -> {
113+
try {
114+
startLatch.await();
115+
outIn.write(4);
116+
endLatch.await();
117+
} catch (Exception e) {
118+
e.printStackTrace();
119+
}
120+
});
121+
Thread readThread = new Thread(() -> {
122+
assertThatThrownBy(jLineInputProvider::readInput).isInstanceOf(ExitRequest.class);
123+
endLatch.countDown();
124+
});
125+
readThread.start();
126+
startLatch.countDown();
127+
writeThread.start();
128+
129+
readThread.join();
130+
writeThread.join();
131+
}
132+
}

0 commit comments

Comments
 (0)