2 * Copyright 2000-2011 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.plugins.groovy.compiler
18 import com.intellij.debugger.SourcePosition
19 import com.intellij.debugger.engine.ContextUtil
20 import com.intellij.debugger.engine.DebugProcessImpl
21 import com.intellij.debugger.engine.DebuggerUtils
22 import com.intellij.debugger.engine.SuspendContextImpl
23 import com.intellij.debugger.engine.evaluation.CodeFragmentKind
24 import com.intellij.debugger.engine.evaluation.EvaluateException
25 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
26 import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
27 import com.intellij.debugger.engine.events.DebuggerContextCommandImpl
28 import com.intellij.debugger.impl.DebuggerContextUtil
29 import com.intellij.debugger.impl.DebuggerManagerImpl
30 import com.intellij.debugger.impl.DebuggerSession
31 import com.intellij.debugger.impl.GenericDebuggerRunner
32 import com.intellij.debugger.ui.DebuggerPanelsManager
33 import com.intellij.debugger.ui.impl.watch.WatchItemDescriptor
34 import com.intellij.debugger.ui.tree.render.DescriptorLabelListener
35 import com.intellij.execution.executors.DefaultDebugExecutor
36 import com.intellij.execution.process.ProcessAdapter
37 import com.intellij.execution.runners.ProgramRunner
38 import com.intellij.openapi.Disposable
39 import com.intellij.openapi.application.ApplicationManager
40 import com.intellij.openapi.fileEditor.FileDocumentManager
41 import com.intellij.openapi.roots.ModuleRootManager
42 import com.intellij.openapi.util.Computable
43 import com.intellij.openapi.util.io.FileUtil
44 import com.intellij.openapi.util.text.StringUtil
45 import com.intellij.openapi.vfs.VirtualFile
46 import com.intellij.testFramework.builders.JavaModuleFixtureBuilder
47 import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl
48 import com.intellij.util.SystemProperties
49 import com.intellij.util.concurrency.Semaphore
54 class GroovyDebuggerTest extends GroovyCompilerTestCase {
56 protected boolean useJps() { false }
59 protected void setUp() {
62 addGroovyLibrary(myModule);
68 protected boolean runInDispatchThread() {
73 protected void invokeTestRunnable(Runnable runnable) {
78 protected void tearDown() {
83 protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) {
84 super.tuneFixture(moduleBuilder)
85 def javaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome())
86 moduleBuilder.addJdk(StringUtil.trimEnd(StringUtil.trimEnd(javaHome, '/'), '/jre'))
89 private void runDebugger(String mainClass, Closure cl) {
90 boolean trace = false//name == 'testClassOutOfSourceRoots'
93 ProgramRunner runner = ProgramRunner.PROGRAM_RUNNER_EP.extensions.find { it.class == GenericDebuggerRunner }
94 runProcess(mainClass, myModule, DefaultDebugExecutor, [onTextAvailable: { evt, type -> if (trace) print evt.text}] as ProcessAdapter, runner)
98 println "terminated1?: " + debugProcess.executionResult.processHandler.isProcessTerminated()
101 debugProcess.executionResult.processHandler.waitFor()
103 println "terminated2?: " + debugProcess.executionResult.processHandler.isProcessTerminated()
107 public void testVariableInScript() {
108 myFixture.addFileToProject("Foo.groovy", """def a = 2
110 addBreakpoint 'Foo.groovy', 1
119 public void testVariableInsideClosure() {
120 myFixture.addFileToProject("Foo.groovy", """def a = 2
127 addBreakpoint 'Foo.groovy', 3
134 public void testQualifyNames() {
135 myFixture.addFileToProject "com/Goo.groovy", '''
138 int mainConstant = 42
139 int secondConstant = 1
142 myFixture.addFileToProject("com/Foo.groovy", """
150 myFixture.addFileToProject("com/Bar.groovy", """package com
151 import static com.Goo.*
153 def lst = [new Foo()] as Set
157 addBreakpoint 'com/Bar.groovy', 4
158 runDebugger 'com.Bar', {
161 eval 'mainConstant', '42'
162 eval 'secondConstant', '1'
163 eval 'mainConstant - secondConstant', '41'
164 eval '(lst as List<Foo>)[0].field', '3'
168 public void testClassOutOfSourceRoots() {
169 def tempDir = new TempDirTestFixtureImpl()
172 disposeOnTearDown({ tempDir.tearDown() } as Disposable)
173 ApplicationManager.application.runWriteAction {
174 def model = ModuleRootManager.getInstance(myModule).modifiableModel
175 model.addContentEntry(tempDir.getFile(''))
180 VirtualFile myClass = null
186 static def foo(def a) {
194 myClass = tempDir.createFile("MyClass.groovy", mcText)
197 addBreakpoint(myClass, 5)
199 myFixture.addFileToProject("Foo.groovy", """
200 def cl = new GroovyClassLoader()
201 cl.parseClass('''$mcText''', 'MyClass.groovy').foo(2)
207 SourcePosition position = managed {
208 EvaluationContextImpl context = evaluationContext()
209 Computable<SourcePosition> a = { ContextUtil.getSourcePosition(context) } as Computable<SourcePosition>
210 SourcePosition pos = ApplicationManager.getApplication().runReadAction (a)
213 assert myClass == position.file.virtualFile
218 void testAnonymousClassInScript() {
219 myFixture.addFileToProject('Foo.groovy', '''\
227 addBreakpoint 'Foo.groovy', 2
234 private def addBreakpoint(String fileName, int line) {
235 VirtualFile file = null
237 file = myFixture.tempDirFixture.getFile(fileName)
239 addBreakpoint(file, line)
242 private def addBreakpoint(VirtualFile file, int line) {
244 DebuggerManagerImpl.getInstanceEx(project).breakpointManager.addLineBreakpoint(FileDocumentManager.instance.getDocument(file), line)
248 private def resume() {
249 debugProcess.managerThread.invoke(debugProcess.createResumeCommand(debugProcess.suspendManager.pausedContext))
252 private SuspendContextImpl waitForBreakpoint() {
254 def suspendManager = debugProcess.suspendManager
255 while (i++ < 1000 && !suspendManager.pausedContext && !debugProcess.executionResult.processHandler.processTerminated) {
259 def context = suspendManager.pausedContext
260 assert context : "too long process, terminated=$debugProcess.executionResult.processHandler.processTerminated"
264 private DebugProcessImpl getDebugProcess() {
265 return getDebugSession().process
268 private DebuggerSession getDebugSession() {
269 return DebuggerPanelsManager.getInstance(project).sessionTab.session
272 private <T> T managed(Closure cl) {
274 def ctx = DebuggerContextUtil.createDebuggerContext(debugSession, debugProcess.suspendManager.pausedContext)
275 Semaphore semaphore = new Semaphore()
277 debugProcess.managerThread.invokeAndWait(new DebuggerContextCommandImpl(ctx) {
279 void threadAction() {
284 def finished = semaphore.waitFor(20000)
285 assert finished : 'Too long debugger action'
289 private void eval(final String codeText, String expected) throws EvaluateException {
291 Semaphore semaphore = new Semaphore()
295 EvaluationContextImpl ctx
296 def item = new WatchItemDescriptor(project, new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, codeText))
298 ctx = evaluationContext()
300 item.updateRepresentation(ctx, { semaphore.up() } as DescriptorLabelListener)
302 assert semaphore.waitFor(10000): "too long evaluation: $item.label $item.evaluateException"
304 String result = managed { DebuggerUtils.getValueAsString(ctx, item.value) }
305 assert result == expected
308 private EvaluationContextImpl evaluationContext() {
309 final SuspendContextImpl suspendContext = debugProcess.suspendManager.pausedContext
310 new EvaluationContextImpl(suspendContext, suspendContext.frameProxy, suspendContext.frameProxy.thisObject())