terminal: replace BaseShellTerminalIntegrationTest with TestShellSession

* Ensures that terminal is not instantiated on Windows
* Allows to add a terminal test even if the test must inherit from a particular class due to requirement of a subsystem.

GitOrigin-RevId: 5b665f122fea206c0fc850cdce87c3e7875902d3
This commit is contained in:
Sergey Simonchik
2020-08-30 20:15:15 +00:00
committed by intellij-monorepo-bot
parent ee75bc34ef
commit 71b12899d6
4 changed files with 149 additions and 135 deletions
@@ -1,129 +0,0 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.terminal;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import com.jediterm.pty.PtyProcessTtyConnector;
import com.jediterm.terminal.Terminal;
import com.jediterm.terminal.TtyConnector;
import com.jediterm.terminal.model.TerminalLine;
import com.jediterm.terminal.model.TerminalModelListener;
import com.jediterm.terminal.model.TerminalTextBuffer;
import com.pty4j.PtyProcess;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
public abstract class BaseShellTerminalIntegrationTest extends BasePlatformTestCase {
public ShellTerminalWidget myWidget;
public TerminalBufferWatcher myWatcher;
@Override
public void setUp() throws Exception {
super.setUp();
LocalTerminalDirectRunner runner = LocalTerminalDirectRunner.createTerminalRunner(getProject());
PtyProcess process = runner.createProcess(getProject().getBasePath());
TtyConnector connector = new PtyProcessTtyConnector(process, StandardCharsets.UTF_8);
myWidget = new ShellTerminalWidget(getProject(), new JBTerminalSystemSettingsProvider(), getTestRootDisposable());
myWidget.start(connector);
myWatcher = new TerminalBufferWatcher(myWidget.getTerminalTextBuffer(), myWidget.getTerminal());
}
@Override
public void tearDown() throws Exception {
try {
myWidget.close();
}
catch (Throwable e) {
addSuppressedException(e);
}
finally {
super.tearDown();
}
}
public static class TerminalBufferWatcher {
private final TerminalTextBuffer myBuffer;
private final Terminal myTerminal;
TerminalBufferWatcher(@NotNull TerminalTextBuffer buffer, @NotNull Terminal terminal) {
myBuffer = buffer;
myTerminal = terminal;
}
@SuppressWarnings("SameParameterValue")
private @NotNull List<String> getScreenLines(boolean aboveCursorLine) {
List<String> screenLines = new ArrayList<>();
myBuffer.lock();
try {
int cursorLineInd = myTerminal.getCursorY() - 1;
for (int row = 0; row < myBuffer.getHeight(); row++) {
if (!aboveCursorLine || row < cursorLineInd) {
TerminalLine line = myBuffer.getLine(row);
screenLines.add(line.getText());
}
}
}
finally {
myBuffer.unlock();
}
return screenLines;
}
public void awaitScreenLinesAre(@NotNull List<String> expectedScreenLines, long timeoutMillis) {
boolean ok = awaitBuffer(() -> expectedScreenLines.equals(getScreenLines(true)), timeoutMillis);
if (!ok) {
Assert.assertEquals(expectedScreenLines, getScreenLines(true));
Assert.fail("Unexpected failure");
}
}
public void awaitScreenLinesEndWith(@NotNull List<String> expectedScreenLines, long timeoutMillis) {
boolean ok = awaitBuffer(() -> checkScreenLinesEndWith(expectedScreenLines), timeoutMillis);
if (!ok) {
Assert.assertEquals(expectedScreenLines, getScreenLines(true));
Assert.fail("Unexpected failure");
}
}
public boolean awaitBuffer(@NotNull BooleanSupplier awaitCondition, long timeoutMillis) {
if (awaitCondition.getAsBoolean()) return true;
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean ok = new AtomicBoolean(false);
TerminalModelListener listener = new TerminalModelListener() {
@Override
public void modelChanged() {
if (awaitCondition.getAsBoolean()) {
ok.set(true);
latch.countDown();
}
}
};
myBuffer.addModelListener(listener);
try {
latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
throw new AssertionError(e);
}
finally {
myBuffer.removeModelListener(listener);
}
return ok.get();
}
public boolean checkScreenLinesEndWith(@NotNull List<String> expectedScreenLines) {
List<String> actualLines = getScreenLines(true);
if (actualLines.size() < expectedScreenLines.size()) return false;
List<String> lastActualLines = actualLines.subList(actualLines.size() - expectedScreenLines.size(), actualLines.size());
return expectedScreenLines.equals(lastActualLines);
}
}
}
@@ -2,20 +2,24 @@
package org.jetbrains.plugins.terminal;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.plugins.terminal.fixture.TestShellSession;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
public class BasicShellTerminalIntegrationTest extends BaseShellTerminalIntegrationTest {
public class BasicShellTerminalIntegrationTest extends BasePlatformTestCase {
public void testEchoAndClear() throws IOException {
public void testEchoAndClear() throws IOException, ExecutionException {
if (!SystemInfo.isUnix) {
return;
}
myWidget.executeCommand("_MY_FOO=test; echo -e \"1\n2\n3\n$_MY_FOO\"");
myWatcher.awaitScreenLinesEndWith(ContainerUtil.newArrayList("1", "2", "3", "test"), 10000);
myWidget.executeCommand("clear");
myWatcher.awaitScreenLinesAre(Collections.emptyList(), 10000);
TestShellSession session = new TestShellSession(getProject(), getTestRootDisposable());
session.executeCommand("_MY_FOO=test; echo -e \"1\n2\n3\n$_MY_FOO\"");
session.awaitScreenLinesEndWith(ContainerUtil.newArrayList("1", "2", "3", "test"), 10000);
session.executeCommand("clear");
session.awaitScreenLinesAre(Collections.emptyList(), 10000);
}
}
@@ -0,0 +1,45 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.terminal.fixture;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
import com.jediterm.pty.PtyProcessTtyConnector;
import com.jediterm.terminal.TtyConnector;
import com.pty4j.PtyProcess;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.terminal.JBTerminalSystemSettingsProvider;
import org.jetbrains.plugins.terminal.LocalTerminalDirectRunner;
import org.jetbrains.plugins.terminal.ShellTerminalWidget;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class TestShellSession {
public final ShellTerminalWidget myWidget;
public final TestTerminalBufferWatcher myWatcher;
public TestShellSession(@NotNull Project project, @NotNull Disposable parentDisposable) throws ExecutionException {
LocalTerminalDirectRunner runner = LocalTerminalDirectRunner.createTerminalRunner(project);
PtyProcess process = runner.createProcess(project.getBasePath());
TtyConnector connector = new PtyProcessTtyConnector(process, StandardCharsets.UTF_8);
myWidget = new ShellTerminalWidget(project, new JBTerminalSystemSettingsProvider(), parentDisposable);
myWidget.start(connector);
myWatcher = new TestTerminalBufferWatcher(myWidget.getTerminalTextBuffer(), myWidget.getTerminal());
}
public void executeCommand(@NotNull @NonNls String shellCommand) throws IOException {
myWidget.executeCommand(shellCommand);
}
public void awaitScreenLinesEndWith(@NonNls List<String> expectedScreenLines, int timeoutMillis) {
myWatcher.awaitScreenLinesEndWith(expectedScreenLines, timeoutMillis);
}
public void awaitScreenLinesAre(@NonNls List<String> expectedScreenLines, int timeoutMillis) {
myWatcher.awaitScreenLinesAre(expectedScreenLines, timeoutMillis);
}
}
@@ -0,0 +1,94 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.terminal.fixture;
import com.jediterm.terminal.Terminal;
import com.jediterm.terminal.model.TerminalLine;
import com.jediterm.terminal.model.TerminalModelListener;
import com.jediterm.terminal.model.TerminalTextBuffer;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BooleanSupplier;
public class TestTerminalBufferWatcher {
private final TerminalTextBuffer myBuffer;
private final Terminal myTerminal;
TestTerminalBufferWatcher(@NotNull TerminalTextBuffer buffer, @NotNull Terminal terminal) {
myBuffer = buffer;
myTerminal = terminal;
}
@SuppressWarnings("SameParameterValue")
private @NotNull List<String> getScreenLines(boolean aboveCursorLine) {
List<String> screenLines = new ArrayList<>();
myBuffer.lock();
try {
int cursorLineInd = myTerminal.getCursorY() - 1;
for (int row = 0; row < myBuffer.getHeight(); row++) {
if (!aboveCursorLine || row < cursorLineInd) {
TerminalLine line = myBuffer.getLine(row);
screenLines.add(line.getText());
}
}
}
finally {
myBuffer.unlock();
}
return screenLines;
}
public void awaitScreenLinesAre(@NotNull List<String> expectedScreenLines, long timeoutMillis) {
boolean ok = awaitBuffer(() -> expectedScreenLines.equals(getScreenLines(true)), timeoutMillis);
if (!ok) {
Assert.assertEquals(expectedScreenLines, getScreenLines(true));
Assert.fail("Unexpected failure");
}
}
public void awaitScreenLinesEndWith(@NotNull List<String> expectedScreenLines, long timeoutMillis) {
boolean ok = awaitBuffer(() -> checkScreenLinesEndWith(expectedScreenLines), timeoutMillis);
if (!ok) {
Assert.assertEquals(expectedScreenLines, getScreenLines(true));
Assert.fail("Unexpected failure");
}
}
public boolean awaitBuffer(@NotNull BooleanSupplier awaitCondition, long timeoutMillis) {
if (awaitCondition.getAsBoolean()) return true;
CountDownLatch latch = new CountDownLatch(1);
AtomicBoolean ok = new AtomicBoolean(false);
TerminalModelListener listener = new TerminalModelListener() {
@Override
public void modelChanged() {
if (awaitCondition.getAsBoolean()) {
ok.set(true);
latch.countDown();
}
}
};
myBuffer.addModelListener(listener);
try {
latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
throw new AssertionError(e);
}
finally {
myBuffer.removeModelListener(listener);
}
return ok.get();
}
public boolean checkScreenLinesEndWith(@NotNull List<String> expectedScreenLines) {
List<String> actualLines = getScreenLines(true);
if (actualLines.size() < expectedScreenLines.size()) return false;
List<String> lastActualLines = actualLines.subList(actualLines.size() - expectedScreenLines.size(), actualLines.size());
return expectedScreenLines.equals(lastActualLines);
}
}