| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.xdebugger; |
| |
| import com.intellij.execution.impl.ConsoleViewImpl; |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.application.WriteAction; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Computable; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.openapi.util.Pair; |
| import com.intellij.openapi.util.Ref; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.testFramework.UsefulTestCase; |
| import com.intellij.util.ui.UIUtil; |
| import com.intellij.xdebugger.breakpoints.*; |
| import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; |
| import com.intellij.xdebugger.frame.*; |
| import com.intellij.xdebugger.frame.XNamedValue; |
| import com.intellij.xdebugger.impl.XDebugSessionImpl; |
| import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil; |
| import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl; |
| import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl; |
| import org.intellij.lang.annotations.Language; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.awt.*; |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.*; |
| import java.util.List; |
| import java.util.concurrent.Semaphore; |
| import java.util.concurrent.TimeUnit; |
| |
| import static org.junit.Assert.*; |
| |
| public class XDebuggerTestUtil { |
| private static final int TIMEOUT = 25000; |
| |
| private XDebuggerTestUtil() { |
| } |
| |
| public static <B extends XBreakpoint<?>> void assertBreakpointValidity(Project project, |
| VirtualFile file, |
| int line, |
| boolean validity, |
| String errorMessage, |
| Class<? extends XBreakpointType<B, ?>> breakpointType) { |
| XLineBreakpointType type = (XLineBreakpointType)XDebuggerUtil.getInstance().findBreakpointType(breakpointType); |
| XBreakpointManager manager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| XLineBreakpointImpl breakpoint = (XLineBreakpointImpl)manager.findBreakpointAtLine(type, file, line); |
| assertNotNull(breakpoint); |
| assertEquals(validity ? AllIcons.Debugger.Db_verified_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint, breakpoint.getIcon()); |
| assertEquals(errorMessage, breakpoint.getErrorMessage()); |
| } |
| |
| public static void toggleBreakpoint(Project project, VirtualFile file, int line) { |
| XDebuggerUtil.getInstance().toggleLineBreakpoint(project, file, line); |
| } |
| |
| public static <P extends XBreakpointProperties> XBreakpoint<P> insertBreakpoint(final Project project, |
| final P properties, |
| final Class<? extends XBreakpointType<XBreakpoint<P>, P>> typeClass) { |
| return new WriteAction<XBreakpoint<P>>() { |
| protected void run(@NotNull final Result<XBreakpoint<P>> result) { |
| result.setResult(XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpoint( |
| XBreakpointType.EXTENSION_POINT_NAME.findExtension(typeClass), properties)); |
| } |
| }.execute().getResultObject(); |
| } |
| |
| public static void removeBreakpoint(final Project project, final XBreakpoint<?> breakpoint) { |
| new WriteAction() { |
| protected void run(@NotNull final Result result) { |
| XDebuggerManager.getInstance(project).getBreakpointManager().removeBreakpoint(breakpoint); |
| } |
| }.execute(); |
| } |
| |
| public static void assertPosition(XSourcePosition pos, VirtualFile file, int line) throws IOException { |
| assertNotNull("No current position", pos); |
| assertEquals(new File(file.getPath()).getCanonicalPath(), new File(pos.getFile().getPath()).getCanonicalPath()); |
| if (line != -1) assertEquals(line, pos.getLine()); |
| } |
| |
| public static void assertCurrentPosition(XDebugSession session, VirtualFile file, int line) throws IOException { |
| assertPosition(session.getCurrentPosition(), file, line); |
| } |
| |
| public static XExecutionStack getActiveThread(@NotNull XDebugSession session) { |
| return session.getSuspendContext().getActiveExecutionStack(); |
| } |
| |
| public static List<XStackFrame> collectFrames(@NotNull XDebugSession session) throws InterruptedException { |
| return collectFrames(null, session); |
| } |
| |
| public static List<XStackFrame> collectFrames(@Nullable XExecutionStack thread, @NotNull XDebugSession session) |
| throws InterruptedException { |
| return collectStacks(thread == null ? getActiveThread(session) : thread); |
| } |
| |
| public static List<XStackFrame> collectStacks(@NotNull XExecutionStack thread) throws InterruptedException { |
| return collectStacks(thread, TIMEOUT * 2); |
| } |
| |
| public static List<XStackFrame> collectStacks(XExecutionStack thread, long timeout) throws InterruptedException { |
| XTestStackFrameContainer container = new XTestStackFrameContainer(); |
| thread.computeStackFrames(0, container); |
| return container.waitFor(timeout).first; |
| } |
| |
| public static Pair<XValue, String> evaluate(XDebugSession session, XExpression expression) { |
| return evaluate(session, expression, TIMEOUT); |
| } |
| |
| public static Pair<XValue, String> evaluate(XDebugSession session, String expression) { |
| return evaluate(session, XExpressionImpl.fromText(expression), TIMEOUT); |
| } |
| |
| public static Pair<XValue, String> evaluate(XDebugSession session, String expression, long timeout) { |
| return evaluate(session, XExpressionImpl.fromText(expression), timeout); |
| } |
| |
| private static Pair<XValue, String> evaluate(XDebugSession session, XExpression expression, long timeout) { |
| XStackFrame frame = session.getCurrentStackFrame(); |
| assertNotNull(frame); |
| XDebuggerEvaluator evaluator = frame.getEvaluator(); |
| assertNotNull(evaluator); |
| XTestEvaluationCallback callback = new XTestEvaluationCallback(); |
| evaluator.evaluate(expression, callback, session.getCurrentPosition()); |
| return callback.waitFor(timeout); |
| } |
| |
| public static void waitForSwing() throws InterruptedException, InvocationTargetException { |
| final com.intellij.util.concurrency.Semaphore s = new com.intellij.util.concurrency.Semaphore(); |
| s.down(); |
| ApplicationManager.getApplication().invokeLater(new Runnable() { |
| public void run() { |
| s.up(); |
| } |
| }); |
| s.waitForUnsafe(); |
| UIUtil.invokeAndWaitIfNeeded(new Runnable() { |
| public void run() { |
| } |
| }); |
| } |
| |
| @NotNull |
| public static XValue findVar(Collection<XValue> vars, String name) { |
| StringBuilder names = new StringBuilder(); |
| for (XValue each : vars) { |
| if (each instanceof XNamedValue) { |
| String eachName = ((XNamedValue)each).getName(); |
| if (eachName.equals(name)) return each; |
| |
| if (names.length() > 0) names.append(", "); |
| names.append(eachName); |
| } |
| } |
| throw new AssertionError("var '" + name + "' not found among " + names); |
| } |
| |
| public static XTestValueNode computePresentation(@NotNull XValue value) throws InterruptedException { |
| return computePresentation(value, TIMEOUT); |
| } |
| |
| public static XTestValueNode computePresentation(XValue value, long timeout) throws InterruptedException { |
| XTestValueNode node = new XTestValueNode(); |
| if (value instanceof XNamedValue) { |
| node.myName = ((XNamedValue)value).getName(); |
| } |
| value.computePresentation(node, XValuePlace.TREE); |
| node.waitFor(timeout); |
| return node; |
| } |
| |
| public static void assertVariable(XValue var, |
| @Nullable String name, |
| @Nullable String type, |
| @Nullable String value, |
| @Nullable Boolean hasChildren) throws InterruptedException { |
| XTestValueNode node = computePresentation(var); |
| |
| if (name != null) assertEquals(name, node.myName); |
| if (type != null) assertEquals(type, node.myType); |
| if (value != null) assertEquals(value, node.myValue); |
| if (hasChildren != null) assertEquals(hasChildren, node.myHasChildren); |
| } |
| |
| public static void assertVariableValue(XValue var, @Nullable String name, @Nullable String value) throws InterruptedException { |
| assertVariable(var, name, null, value, null); |
| } |
| |
| public static void assertVariableValue(Collection<XValue> vars, @Nullable String name, @Nullable String value) |
| throws InterruptedException { |
| assertVariableValue(findVar(vars, name), name, value); |
| } |
| |
| public static void assertVariableValueMatches(@NotNull Collection<XValue> vars, |
| @Nullable String name, |
| @Nullable @Language("RegExp") String valuePattern) throws InterruptedException { |
| assertVariableValueMatches(findVar(vars, name), name, valuePattern); |
| } |
| |
| public static void assertVariableValueMatches(@NotNull XValue var, |
| @Nullable String name, |
| @Nullable @Language("RegExp") String valuePattern) throws InterruptedException { |
| assertVariableValueMatches(var, name, null, valuePattern); |
| } |
| |
| public static void assertVariableValueMatches(@NotNull XValue var, |
| @Nullable String name, |
| @Nullable String type, |
| @Nullable @Language("RegExp") String valuePattern) throws InterruptedException { |
| XTestValueNode node = computePresentation(var); |
| if (name != null) assertEquals(name, node.myName); |
| if (type != null) assertEquals(type, node.myType); |
| if (valuePattern != null) { |
| assertTrue("Expected value" + valuePattern + " Actual value: " + node.myValue, node.myValue.matches(valuePattern)); |
| } |
| } |
| |
| public static void assertVariableTypeMatches(@NotNull Collection<XValue> vars, |
| @Nullable String name, |
| @Nullable @Language("RegExp") String typePattern) throws InterruptedException { |
| assertVariableTypeMatches(findVar(vars, name), name, typePattern); |
| } |
| |
| public static void assertVariableTypeMatches(@NotNull XValue var, |
| @Nullable String name, |
| @Nullable @Language("RegExp") String typePattern) throws InterruptedException { |
| XTestValueNode node = computePresentation(var); |
| if (name != null) { |
| assertEquals(name, node.myName); |
| } |
| if (typePattern != null) { |
| assertTrue("Expected type: " + typePattern + " Actual type: " + node.myType, node.myType.matches(typePattern)); |
| } |
| } |
| |
| public static void assertVariableFullValue(@NotNull XValue var, |
| @Nullable String value) throws InterruptedException { |
| XTestValueNode node = computePresentation(var); |
| final String[] result = new String[1]; |
| |
| node.myFullValueEvaluator.startEvaluation(new XFullValueEvaluator.XFullValueEvaluationCallback() { |
| @Override |
| public void evaluated(@NotNull String fullValue) { |
| result[0] = fullValue; |
| } |
| |
| @Override |
| public void evaluated(@NotNull String fullValue, @Nullable Font font) { |
| result[0] = fullValue; |
| } |
| |
| @Override |
| public void errorOccurred(@NotNull String errorMessage) { |
| result[0] = errorMessage; |
| } |
| |
| @Override |
| public boolean isObsolete() { |
| return false; |
| } |
| }); |
| |
| assertEquals(value, result[0]); |
| } |
| |
| public static void assertVariableFullValue(Collection<XValue> vars, @Nullable String name, @Nullable String value) |
| throws InterruptedException { |
| assertVariableFullValue(findVar(vars, name), value); |
| } |
| |
| public static void assertVariables(List<XValue> vars, String... names) throws InterruptedException { |
| List<String> expectedNames = new ArrayList<String>(Arrays.asList(names)); |
| |
| List<String> actualNames = new ArrayList<String>(); |
| for (XValue each : vars) { |
| actualNames.add(computePresentation(each).myName); |
| } |
| |
| Collections.sort(actualNames); |
| Collections.sort(expectedNames); |
| UsefulTestCase.assertOrderedEquals(actualNames, expectedNames); |
| } |
| |
| public static void assertVariablesContain(List<XValue> vars, String... names) throws InterruptedException { |
| List<String> expectedNames = new ArrayList<String>(Arrays.asList(names)); |
| |
| List<String> actualNames = new ArrayList<String>(); |
| for (XValue each : vars) { |
| actualNames.add(computePresentation(each).myName); |
| } |
| |
| expectedNames.removeAll(actualNames); |
| assertTrue("Missing variables:" + StringUtil.join(expectedNames, ", ") |
| + "\nAll Variables: " + StringUtil.join(actualNames, ", "), |
| expectedNames.isEmpty() |
| ); |
| } |
| |
| public static void assertSourcePosition(final XValue value, VirtualFile file, int offset) { |
| final XTestNavigatable n = new XTestNavigatable(); |
| ApplicationManager.getApplication().runReadAction(new Runnable() { |
| @Override |
| public void run() { |
| value.computeSourcePosition(n); |
| } |
| }); |
| assertNotNull(n.myPosition); |
| assertEquals(file, n.myPosition.getFile()); |
| assertEquals(offset, n.myPosition.getOffset()); |
| } |
| |
| public static boolean waitFor(Semaphore semaphore, long timeoutInMillis) { |
| long end = System.currentTimeMillis() + timeoutInMillis; |
| long remaining = timeoutInMillis; |
| do { |
| try { |
| return semaphore.tryAcquire(remaining, TimeUnit.MILLISECONDS); |
| } |
| catch (InterruptedException ignored) { |
| remaining = end - System.currentTimeMillis(); |
| } |
| } while (remaining > 0); |
| return false; |
| } |
| |
| public static void assertVariable(Collection<XValue> vars, |
| @Nullable String name, |
| @Nullable String type, |
| @Nullable String value, |
| @Nullable Boolean hasChildren) throws InterruptedException { |
| assertVariable(findVar(vars, name), name, type, value, hasChildren); |
| } |
| |
| @NotNull |
| public static String getConsoleText(final @NotNull ConsoleViewImpl consoleView) { |
| new WriteAction() { |
| protected void run(@NotNull Result result) throws Throwable { |
| consoleView.flushDeferredText(); |
| } |
| }.execute(); |
| |
| return consoleView.getEditor().getDocument().getText(); |
| } |
| |
| public static <T extends XBreakpointType> XBreakpoint addBreakpoint(@NotNull final Project project, |
| @NotNull final Class<T> exceptionType, |
| @NotNull final XBreakpointProperties properties) { |
| final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| XBreakpointType[] types = XBreakpointUtil.getBreakpointTypes(); |
| final Ref<XBreakpoint> breakpoint = Ref.create(null); |
| for (XBreakpointType type : types) { |
| if (exceptionType.isInstance(type)) { |
| final T breakpointType = exceptionType.cast(type); |
| new WriteAction() { |
| @Override |
| protected void run(@NotNull Result result) throws Throwable { |
| breakpoint.set(breakpointManager.addBreakpoint(breakpointType, properties)); |
| } |
| }.execute(); |
| break; |
| } |
| } |
| return breakpoint.get(); |
| } |
| |
| public static void removeAllBreakpoints(@NotNull final Project project) { |
| final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| XBreakpoint<?>[] breakpoints = getBreakpoints(breakpointManager); |
| for (final XBreakpoint b : breakpoints) { |
| new WriteAction() { |
| @Override |
| protected void run(@NotNull Result result) throws Throwable { |
| breakpointManager.removeBreakpoint(b); |
| } |
| }.execute(); |
| } |
| } |
| |
| public static XBreakpoint<?>[] getBreakpoints(final XBreakpointManager breakpointManager) { |
| return ApplicationManager.getApplication().runReadAction(new Computable<XBreakpoint<?>[]>() { |
| public XBreakpoint<?>[] compute() { |
| return breakpointManager.getAllBreakpoints(); |
| } |
| }); |
| } |
| |
| public static <B extends XBreakpoint<?>> |
| void setDefaultBreakpointEnabled(@NotNull final Project project, Class<? extends XBreakpointType<B, ?>> bpTypeClass, boolean enabled) { |
| final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| XBreakpointType<B, ?> bpType = XDebuggerUtil.getInstance().findBreakpointType(bpTypeClass); |
| XBreakpoint<?> bp = breakpointManager.getDefaultBreakpoint(bpType); |
| if (bp != null) { |
| bp.setEnabled(enabled); |
| } |
| } |
| |
| public static void setBreakpointCondition(Project project, int line, final String condition) { |
| XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| for (XBreakpoint breakpoint : getBreakpoints(breakpointManager)) { |
| if (breakpoint instanceof XLineBreakpoint) { |
| final XLineBreakpoint lineBreakpoint = (XLineBreakpoint)breakpoint; |
| |
| if (lineBreakpoint.getLine() == line) { |
| new WriteAction() { |
| @Override |
| protected void run(@NotNull Result result) throws Throwable { |
| lineBreakpoint.setCondition(condition); |
| } |
| }.execute(); |
| } |
| } |
| } |
| } |
| |
| public static void setBreakpointLogExpression(Project project, int line, final String logExpression) { |
| XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); |
| for (XBreakpoint breakpoint : getBreakpoints(breakpointManager)) { |
| if (breakpoint instanceof XLineBreakpoint) { |
| final XLineBreakpoint lineBreakpoint = (XLineBreakpoint)breakpoint; |
| |
| if (lineBreakpoint.getLine() == line) { |
| new WriteAction() { |
| @Override |
| protected void run(@NotNull Result result) throws Throwable { |
| lineBreakpoint.setLogExpression(logExpression); |
| lineBreakpoint.setLogMessage(true); |
| } |
| }.execute(); |
| } |
| } |
| } |
| } |
| |
| public static void disposeDebugSession(final XDebugSession debugSession) { |
| new WriteAction() { |
| protected void run(@NotNull Result result) throws Throwable { |
| XDebugSessionImpl session = (XDebugSessionImpl)debugSession; |
| Disposer.dispose(session.getSessionTab()); |
| Disposer.dispose(session.getConsoleView()); |
| } |
| }.execute(); |
| } |
| |
| public static void assertVariable(Pair<XValue, String> varAndErrorMessage, |
| @Nullable String name, |
| @Nullable String type, |
| @Nullable String value, |
| @Nullable Boolean hasChildren) throws InterruptedException { |
| assertNull(varAndErrorMessage.second); |
| assertVariable(varAndErrorMessage.first, name, type, value, hasChildren); |
| } |
| |
| public static String assertVariableExpression(XValue desc, String expectedExpression) { |
| String expression = desc.getEvaluationExpression(); |
| assertEquals(expectedExpression, expression); |
| return expression; |
| } |
| |
| public static class XTestStackFrameContainer extends XTestContainer<XStackFrame> implements XExecutionStack.XStackFrameContainer { |
| public void addStackFrames(@NotNull List<? extends XStackFrame> stackFrames, boolean last) { |
| addChildren(stackFrames, last); |
| } |
| |
| @Override |
| public void errorOccurred(@NotNull String errorMessage) { |
| setErrorMessage(errorMessage); |
| } |
| } |
| |
| public static class XTestNavigatable implements XNavigatable { |
| private XSourcePosition myPosition; |
| |
| @Override |
| public void setSourcePosition(@Nullable XSourcePosition sourcePosition) { |
| myPosition = sourcePosition; |
| } |
| |
| public XSourcePosition getPosition() { |
| return myPosition; |
| } |
| } |
| } |