package org.rubypeople.rdt.debug.core.tests; import java.io.File; import org.eclipse.core.runtime.IStatus; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.internal.debug.core.SuspensionPoint; import org.rubypeople.rdt.internal.debug.core.commands.AbstractDebuggerConnection; import org.rubypeople.rdt.internal.debug.core.commands.ClassicDebuggerConnection; import org.rubypeople.rdt.internal.debug.core.model.RubyVariable; import org.rubypeople.rdt.internal.debug.core.model.ThreadInfo; import org.rubypeople.rdt.internal.launching.LaunchingPlugin; public class FTC_ClassicDebuggerCommunicationTest extends FTC_AbstractDebuggerCommunicationTest { public static junit.framework.TestSuite suite() { junit.framework.TestSuite suite = new junit.framework.TestSuite(); //suite.addTest(new FTC_DebuggerCommunicationTest("testBreakpointOnFirstLine")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testBreakpointAddAndRemove")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testSimpleCycleSteppingWorks")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testStoppingonOneLineTwice")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableLocal")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableArray")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableArrayEmpty")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableHash")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableHashWithObjectKeys")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableHashWithStringKeys")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariableWithXmlContent")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testThreadIdsAndResume")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testThreadFramesAndVariables")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testFrames")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testThreads")); // suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testVariablesInFrames")); //suite.addTest(new TC_DebuggerCommunicationTest("testConstants")); //suite.addTest(new TC_DebuggerCommunicationTest("testConstantDefinedInBothClassAndSuperclass")); //suite.addTest(new TC_DebuggerCommunicationTest("testVariablesInFrames")); //suite.addTest(new TC_DebuggerCommunicationTest("testFramesWhenThreadSpawned")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testThreadIdsAndResume")); //suite.addTest(new TC_DebuggerCommunicationTest("testThreadsAndFrames")); //suite.addTest(new TC_DebuggerCommunicationTest("testStepOver")); //suite.addTest(new TC_DebuggerCommunicationTest("testVariableNil")); //suite.addTest(new TC_DebuggerCommunicationTest("testVariableInstanceNested")); //suite.addTest(new TC_DebuggerCommunicationTest("testStaticVariableInstanceNested")); //suite.addTest(new TC_DebuggerCommunicationTest("testNameError")); //suite.addTest(new TC_DebuggerCommunicationTest("testVariablesInObject")); //suite.addTest(new TC_DebuggerCommunicationTest("testStaticVariables")); //suite.addTest(new TC_DebuggerCommunicationTest("testSingletonStaticVariables")); //suite.addTest(new TC_DebuggerCommunicationTest("testVariableString")); // suite.addTest(new TC_DebuggerCommunicationTest("testInspect")); //suite.addTest(new TC_DebuggerCommunicationTest("testInspectError")); suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testReloadAndInspect")) ; suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testReloadWithException")) ; suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testReloadAndStep")) ; suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testReloadInRequire")) ; suite.addTest(new FTC_ClassicDebuggerCommunicationTest("testReloadInStackFrame")) ; // suite.addTest(new TC_DebuggerCommunicationTest("testIgnoreException")); // suite.addTest(new TC_DebuggerCommunicationTest("testExceptionHierarchy")); // suite.addTest(new TC_DebuggerCommunicationTest("testException")); return suite; } public FTC_ClassicDebuggerCommunicationTest(String arg0) { super(arg0); } public void startRubyProcess() throws Exception { String cmd = FTC_ClassicDebuggerCommunicationTest.RUBY_INTERPRETER + " -I" + createIncludeDir() + " -I" + getTmpDir().replace('\\', '/') + " -rclassic-debug-verbose.rb " + getRubyTestFilename(); System.out.println("Starting: " + cmd); process = Runtime.getRuntime().exec(cmd); rubyStderrRedirectorThread = new OutputRedirectorThread(process.getErrorStream()); rubyStderrRedirectorThread.start(); rubyStdoutRedirectorThread = new OutputRedirectorThread(process.getInputStream()); rubyStdoutRedirectorThread.start(); } private String createIncludeDir() { String includeDir; if (LaunchingPlugin.getDefault() != null) { // being run as JUnit Plug-in Test, Eclipse is running includeDir = RubyCore.getOSDirectory(LaunchingPlugin.getDefault()) + "ruby" ; } else { // being run as "pure" JUnit Test without Eclipse running // getResource delivers a URL, so we get slashes as Fileseparator includeDir = getClass().getResource("/").getFile(); includeDir += "../../org.rubypeople.rdt.launching/ruby" ; // if on windows, remove a leading slash if (includeDir.startsWith("/") && File.separatorChar == '\\') { includeDir = includeDir.substring(1); } } // the ruby interpreter on linux does not like quotes, so we use them only if really necessary if (includeDir.indexOf(" ") == -1) { return includeDir ; } else { return '"' + includeDir + '"'; } } public void testThreads() throws Exception { createSocket(new String[] { "Thread.new {", "puts 'a'", "}", "Thread.pass", "puts 'b'" }); sendRuby("b test.rb:2"); sendRuby("b test.rb:5"); sendRuby("cont"); SuspensionPoint point1 = getSuspensionReader().readSuspension(); sendRuby("th l"); ThreadInfo[] threadInfos = getThreadInfoReader().readThreads(); assertEquals(2, threadInfos.length); sendRuby("cont"); SuspensionPoint point2 = getSuspensionReader().readSuspension(); sendRuby("th l"); threadInfos = getThreadInfoReader().readThreads(); assertEquals(1, threadInfos.length); assertNotSame(Integer.valueOf(point1.getThreadId()), Integer.valueOf(point2.getThreadId())); } public void testThreadIdsAndResume() throws Exception { createSocket(new String[] { "threads=[]", "threads << Thread.new {", "puts 'a'", "}", "threads << Thread.new{", "puts 'b'", "}", "puts 'c'", "threads.each{|t| t.join()}" }); sendRuby("b test.rb:3"); sendRuby("b test.rb:6"); sendRuby("b test.rb:8"); sendRuby("cont"); getSuspensionReader().readSuspension(); getSuspensionReader().readSuspension(); getSuspensionReader().readSuspension(); sendRuby("th l"); ThreadInfo[] threads = getThreadInfoReader().readThreads(); assertEquals(3, threads.length); int threadId1 = threads[0].getId(); int threadId2 = threads[1].getId(); int threadId3 = threads[2].getId(); sendRuby("th " + threadId2 + " ; cont"); sendRuby("th l"); threads = getThreadInfoReader().readThreads(); assertEquals(2, threads.length); assertEquals(threadId1, threads[0].getId()); assertEquals(threadId3, threads[1].getId()); sendRuby("th " + threadId3 + " ; cont"); sendRuby("th l"); threads = getThreadInfoReader().readThreads(); assertEquals(1, threads.length); assertEquals(threadId1, threads[0].getId()); } public void testReloadAndInspect() throws Exception { String[] lines = new String[] { "class Test", "def calc(a)", "a = a*2", "return a", "end", "end", "test=Test.new()" }; createSocket(lines); runToLine(7); // test variable value in stack 1 (top stack frame) lines[2] = "a=a*4"; writeFile("test.rb", lines); sendRuby("load " + getTmpDir() + "test.rb"); IStatus loadResult = this.getLoadResultReader() .readLoadResult(); assertTrue("No Exception from load", loadResult.isOK()); sendRuby("v inspect Test.new.calc(2)"); RubyVariable[] variables = getVariableReader().readVariables( createStackFrame()); assertEquals("There is one variable returned.", 1, variables.length); assertEquals("Result is 8", "8", variables[0].getValue() .getValueString()); } public void testReloadAndStep() throws Exception { String[] lines = new String[] { "puts 'a'", "puts 'b'", "puts 'c'" }; createSocket(lines); runToLine(2); lines = new String[] { "puts 'd'", "puts 'e'", "puts 'f'" }; writeFile("test.rb", lines); sendRuby("load " + getTmpDir() + "test.rb"); this.getLoadResultReader().readLoadResult(); sendRuby("next"); SuspensionPoint info = getSuspensionReader().readSuspension(); assertEquals(3, info.getLine()); } public void testReloadWithException() throws Exception { createSocket(new String[] { "puts 'a'" }); runToLine(1); // test variable value in stack 1 (top stack frame) String[] lines = new String[] { "classs A;end" }; writeFile("test.rb", lines); sendRuby("load " + getTmpDir() + "test.rb"); IStatus loadResult = this.getLoadResultReader() .readLoadResult(); assertFalse("Exception from load", loadResult.isOK()); assertTrue(loadResult.getMessage().startsWith("SyntaxError")); } public void testReloadInRequire() throws Exception { // Deadlock String[] lines = new String[] { "def endless", "sleep 0.1", "end" }; writeFile("content file.rb", lines); createSocket(new String[] { "require 'content file'", "while true", "endless()", "end" }); sendRuby("cont"); // test variable value in stack 1 (top stack frame) lines[1] = "exit 0"; writeFile("content file.rb", lines); sendRuby("load " + getTmpDir() + "content file.rb"); IStatus loadResult = this.getLoadResultReader() .readLoadResult(); assertTrue("No Exception from load", loadResult.isOK()); } public void testReloadInStackFrame() throws Exception { String[] lines = new String[] { "class Test", "def calc(a)", "a = a*2", "return a", "end", "end", "result = Test.new.calc(2)", "result = Test.new.calc(2)", "puts result" }; createSocket(lines); runToLine(3); // a has not yet been calculated ... sendRuby("v local"); RubyVariable[] localVariables = getVariableReader().readVariables( createStackFrame()); assertEquals("2", localVariables[0].getValue().getValueString()); // now change the code ... lines[2] = "a=a*4"; writeFile("test.rb", lines); sendRuby("load " + getTmpDir() + "test.rb"); IStatus loadResult = this.getLoadResultReader() .readLoadResult(); assertTrue("No Exception from load", loadResult.isOK()); runToLine(4); // now a is calculated and the result is 4. That means that ruby does // not change the code which // currently being executed in a stack frame, Java would have reset the // instruction pointer and the // result would be 8 sendRuby("v local"); localVariables = getVariableReader().readVariables(createStackFrame()); assertEquals("4", localVariables[0].getValue().getValueString()); // Now check that the new code is executed with the next call to calc runToLine(3); runToLine(4); sendRuby("v local"); localVariables = getVariableReader().readVariables(createStackFrame()); assertEquals("8", localVariables[0].getValue().getValueString()); } @Override protected AbstractDebuggerConnection createDebuggerConnection() { return new ClassicDebuggerConnection(1098) ; } }