mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 23:31:05 +07:00
When a user calls `Previous Entry in Console History` action, move the caret to the end of the first line IJ-CR-111281 GitOrigin-RevId: a351f264722b74c89692963ead0467250ac01a68
435 lines
13 KiB
Java
435 lines
13 KiB
Java
// 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 com.jetbrains.env.debug;
|
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.collect.Sets;
|
|
import com.intellij.execution.console.ConsoleHistoryController;
|
|
import com.intellij.openapi.actionSystem.AnAction;
|
|
import com.intellij.openapi.application.ApplicationManager;
|
|
import com.intellij.openapi.command.WriteCommandAction;
|
|
import com.intellij.openapi.editor.ex.EditorEx;
|
|
import com.intellij.testFramework.EdtTestUtil;
|
|
import com.intellij.testFramework.TestActionEvent;
|
|
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
|
|
import com.jetbrains.env.PyEnvTestCase;
|
|
import com.jetbrains.python.console.PyConsoleOptions;
|
|
import com.jetbrains.python.console.PyConsoleOptionsConfigurable;
|
|
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
|
|
import com.jetbrains.python.debugger.PyDebugValue;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.junit.Assert;
|
|
import org.junit.Test;
|
|
|
|
import javax.swing.tree.TreeNode;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.function.Predicate;
|
|
|
|
import static com.intellij.testFramework.UsefulTestCase.assertContainsElements;
|
|
import static com.jetbrains.env.debug.PyBaseDebuggerTask.findCompletionVariantByName;
|
|
import static com.jetbrains.env.debug.PyBaseDebuggerTask.findDebugValueByName;
|
|
import static com.jetbrains.python.PyParameterInfoTest.checkParameters;
|
|
import static org.junit.Assert.*;
|
|
|
|
public class PythonConsoleTest extends PyEnvTestCase {
|
|
@Test
|
|
public void testConsolePrint() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = 96");
|
|
exec("x = x + 1");
|
|
exec("print(x)");
|
|
waitForOutput("97");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteMultiline() { //PY-4329
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("""
|
|
if True:
|
|
x = 1
|
|
y = x + 100
|
|
for i in range(1):
|
|
print(y)
|
|
""");
|
|
waitForOutput("101");
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public Set<String> getTags() {
|
|
return Sets.newHashSet("-jython"); //jython doesn't support multiline execution: http://bugs.jython.org/issue2106
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testInterruptAsync() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("import time");
|
|
execNoWait("""
|
|
for i in range(10000):
|
|
print(i)
|
|
time.sleep(0.1)""");
|
|
waitForOutput("3\n4\n5");
|
|
Assert.assertFalse(canExecuteNow());
|
|
interrupt();
|
|
waitForFinish();
|
|
waitForReady();
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public Set<String> getTags() {
|
|
return Sets.newHashSet("-iron", "-jython");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testLineByLineInput() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = 96");
|
|
exec("x = x + 1");
|
|
exec("""
|
|
if True:
|
|
print(x)
|
|
""");
|
|
waitForOutput("97");
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
@Test
|
|
public void testVariablesView() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = 1");
|
|
exec("print(x)");
|
|
waitForOutput("1");
|
|
|
|
assertTrue("Variable has wrong value",
|
|
hasValue("x", "1"));
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testCompoundVariable() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = [1, 2, 3]");
|
|
exec("print(x)");
|
|
waitForOutput("[1, 2, 3]");
|
|
|
|
List<String> values = getCompoundValueChildren(getValue("x"));
|
|
Collections.sort(values);
|
|
assertContainsElements(values, "1", "2", "3", "3");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testChangeVariable() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = 1");
|
|
exec("print(x)");
|
|
waitForOutput("1");
|
|
|
|
setValue("x", "2");
|
|
|
|
exec("print(x)");
|
|
|
|
waitForOutput("2");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testConsoleActionsReflectedInVariableView() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
|
|
private static final int TIMEOUT = 3000;
|
|
private static final int NUMBER_OF_ATTEMPTS = 10;
|
|
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("foo = 'bar'");
|
|
waitForConditionIsTrue("`foo` is not in the console variable tree", (root) -> {
|
|
for(TreeNode child : root.getChildren()) {
|
|
XDebuggerTreeNode node = (XDebuggerTreeNode) child;
|
|
if (node.toString().equals("foo")) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
|
|
exec("foo = 'baz'");
|
|
waitForConditionIsTrue("`foo` value hasn't changed to 'baz'", (root) -> {
|
|
for(TreeNode child : root.getChildren()) {
|
|
XDebuggerTreeNode node = (XDebuggerTreeNode) child;
|
|
if (node.toString().equals("foo") && node.getText().toString().contains("'baz'")) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
});
|
|
|
|
exec("del foo");
|
|
waitForConditionIsTrue("`foo` is still in the console variable tree", (root) -> {
|
|
for (TreeNode child : root.getChildren()) {
|
|
XDebuggerTreeNode node = (XDebuggerTreeNode)child;
|
|
if (node.toString().equals("foo")) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
private void waitForConditionIsTrue(String message, @NotNull Predicate<XDebuggerTreeNode> pred) throws InterruptedException {
|
|
final long startedAt = System.currentTimeMillis();
|
|
do {
|
|
if (pred.test(getConsoleView().getDebuggerTreeRootNode())) return;
|
|
Thread.sleep(TIMEOUT / NUMBER_OF_ATTEMPTS);
|
|
}
|
|
while (startedAt + TIMEOUT > System.currentTimeMillis());
|
|
Assert.fail(message);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testCollectionsShapes() {
|
|
runPythonTest(new PyConsoleTask("/debug") {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("from test_shapes import *");
|
|
waitForOutput("Executed");
|
|
|
|
final List<PyDebugValue> frameVariables = loadFrame();
|
|
PyDebugValue var = findDebugValueByName(frameVariables, "list1");
|
|
assertEquals("120", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "dict1");
|
|
assertEquals("2", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "custom");
|
|
assertEquals("5", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "df1");
|
|
assertEquals("(3, 6)", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "n_array");
|
|
assertEquals("(3, 2)", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "series");
|
|
assertEquals("(5,)", var.getShape());
|
|
|
|
var = findDebugValueByName(frameVariables, "custom_shape");
|
|
assertEquals("(3,)", var.getShape());
|
|
var = findDebugValueByName(frameVariables, "custom_shape2");
|
|
assertEquals("(2, 3)", var.getShape());
|
|
}
|
|
|
|
@NotNull
|
|
@Override
|
|
public Set<String> getTags() {
|
|
return ImmutableSet.of("pandas");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testCompletionMethods() {
|
|
runPythonTest(new PyConsoleTask("/debug") {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("a = \"aaa\"");
|
|
exec("a");
|
|
waitForOutput("aaa");
|
|
|
|
List<PydevCompletionVariant> completions = getCompletions("a.");
|
|
assertFalse("Completion variants list is empty", completions.isEmpty());
|
|
PydevCompletionVariant compVariant = findCompletionVariantByName(completions, "center");
|
|
assertNotNull("Completion variant `center` is missing", compVariant);
|
|
|
|
assertEquals(2, compVariant.getType());
|
|
assertTrue("Missing completion argument `width` in `str.center()`", compVariant.getArgs().contains("width"));
|
|
assertFalse("Documentation is empty for `str.center()`", compVariant.getDescription().isEmpty());
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testCompletionDoNotEvaluateProperty() {
|
|
runPythonTest(new PyConsoleTask("/debug") {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("""
|
|
class Bar:
|
|
@property
|
|
def prop(self):
|
|
x = 238
|
|
print(x + 1)
|
|
return "bar"
|
|
\s
|
|
""");
|
|
exec("bar = Bar()");
|
|
exec("print(\"Hey\")");
|
|
waitForOutput("Hey");
|
|
|
|
List<PydevCompletionVariant> completions = getCompletions("bar.");
|
|
assertFalse("Completion variants list is empty", completions.isEmpty());
|
|
|
|
// Just to make sure that output is updated
|
|
exec("print('Hello')");
|
|
waitForOutput("Hello");
|
|
|
|
PydevCompletionVariant compVariant = findCompletionVariantByName(completions, "prop");
|
|
assertNotNull("Completion variant `prop` is missing", compVariant);
|
|
|
|
assertEquals(3, compVariant.getType());
|
|
String currentOutput = output();
|
|
assertFalse("Property was called for completion", currentOutput.contains("239"));
|
|
}
|
|
|
|
@Override
|
|
public @NotNull Set<String> getTags() {
|
|
return ImmutableSet.of("-python3.8", "-python3.9", "-python3.10", "-python3.11", "-python3.12");
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testParameterInfo() {
|
|
runPythonTest(new PyConsoleTask("/debug") {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("from os import getenv");
|
|
exec("print(\"Hi\")");
|
|
waitForOutput("Hi");
|
|
addTextToEditor("getenv()");
|
|
ApplicationManager.getApplication().runReadAction(() -> {
|
|
checkParameters(7, getConsoleFile(), "key, default=None", new String[]{"key, "});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testCheckForThreadLeaks() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("x = 42");
|
|
exec("print(x)");
|
|
waitForOutput("42");
|
|
}
|
|
|
|
@Override
|
|
public boolean reportThreadLeaks() {
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testStaticCodeInside() {
|
|
runPythonTest(new PyConsoleTask() {
|
|
@Override
|
|
public void before() {
|
|
PyConsoleOptions.getInstance(getProject()).setCodeCompletionOption(PyConsoleOptionsConfigurable.CodeCompletionOption.STATIC);
|
|
}
|
|
|
|
@Override
|
|
public void testing() throws Exception {
|
|
exec("def foo():\n" +
|
|
" pass");
|
|
exec("x = 42");
|
|
exec("s = 'str'");
|
|
|
|
getStaticCompletion("x", "foo", "s");
|
|
}
|
|
|
|
private void getStaticCompletion(String... completionVariants) {
|
|
myFixture.configureFromExistingVirtualFile(getConsoleView().getVirtualFile());
|
|
myFixture.completeBasic();
|
|
List<String> completions = myFixture.getLookupElementStrings();
|
|
for (String variant : completionVariants) {
|
|
assertTrue(completions.contains(variant));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Test
|
|
public void testConsoleHistoryNavigation() {
|
|
runPythonTest(new PyConsoleTask("/debug") {
|
|
@Override
|
|
public void testing() {
|
|
addToHistory("a = 1");
|
|
addToHistory("""
|
|
def foo():
|
|
x = 1
|
|
y = 2
|
|
return x + y""");
|
|
|
|
runHistoryAction(true);
|
|
checkCaretPosition(true);
|
|
|
|
runHistoryAction(true);
|
|
checkCaretPosition(true);
|
|
|
|
runHistoryAction(false);
|
|
checkCaretPosition(false);
|
|
}
|
|
|
|
private void addToHistory(String command) {
|
|
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
|
|
ConsoleHistoryController.getController(getConsoleView()).addToHistory(command);
|
|
});
|
|
}
|
|
|
|
private void runHistoryAction(boolean isNext) {
|
|
ConsoleHistoryController controller = ConsoleHistoryController.getController(getConsoleView());
|
|
EdtTestUtil.runInEdtAndWait(() -> {
|
|
AnAction action = isNext ? controller.getHistoryNext() : controller.getHistoryPrev();
|
|
action.actionPerformed(TestActionEvent.createTestEvent());
|
|
});
|
|
}
|
|
|
|
private void checkCaretPosition(boolean isNext) {
|
|
EditorEx consoleEditor = getConsoleView().getConsoleEditor();
|
|
|
|
ApplicationManager.getApplication().runReadAction(() -> {
|
|
int offset = consoleEditor.getCaretModel().getOffset();
|
|
int caretLine = consoleEditor.getDocument().getLineNumber(offset);
|
|
int linesCount = consoleEditor.getDocument().getLineCount();
|
|
if (linesCount > 1) {
|
|
if (isNext) {
|
|
assertEquals(0, caretLine);
|
|
}
|
|
else {
|
|
assertEquals(linesCount - 1, caretLine);
|
|
}
|
|
} else {
|
|
assertEquals(0, caretLine);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|