package org.rubypeople.rdt.internal.debug.ui; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.eclipse.core.resources.IProject; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStreamMonitor; import org.eclipse.debug.core.model.IStreamsProxy; import org.eclipse.debug.ui.console.IConsole; import org.eclipse.debug.ui.console.IConsoleHyperlink; import org.eclipse.jface.text.AbstractDocument; import org.eclipse.jface.text.DefaultLineTracker; import org.eclipse.jface.text.GapTextStore; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.ui.console.IOConsoleOutputStream; import org.eclipse.ui.console.IPatternMatchListener; import org.rubypeople.rdt.internal.debug.ui.console.RubyConsoleTracker; import org.rubypeople.rdt.internal.debug.ui.console.RubyStackTraceHyperlink; import org.rubypeople.rdt.internal.debug.ui.console.RubyConsoleTracker.FileExistanceChecker; public class TC_RubyConsoleTracker extends TestCase { private static final String SYNTAX_IN_REQUIRE = " /RdtTest/FooTest.rb:2:in `require': /RdtTestLib/anotherFile.rb:9: parse error (SyntaxError)"; private TestConsole console; private MockFileExistanceChecker fileChecker; public void setUp() throws Exception { fileChecker = new MockFileExistanceChecker(); console = new TestConsole(fileChecker); } public void testCorrect() throws Exception { //data/test/configFile.rb:1:in `require': No such file to load -- inifile (LoadError) // * from /data/test/configFile.rb:1 // * from /data/test/fetchmail.rb:2:in `require' fileChecker.addKnownFile("/d/t.rb"); fileChecker.addKnownFile("c:/d/abc.rb"); console.lineAppend("/d/t.rb:1:in `require': No such file to load -- inifile (LoadError)") ; console.lineAppend("\tfrom c:/d/abc.rb:99") ; console.lineAppend(" /name with from in the middle/rb.rb:123") ; console.assertLink(0, 9, "/d/t.rb", 1, 0); console.assertLink(6, 14, "c:/d/abc.rb", 99, 1); console.assertLinkCount(2); } public void testSyntaxErrorInRequire() throws Exception { fileChecker.addKnownFile("/RdtTest/FooTest.rb"); fileChecker.addKnownFile("/RdtTestLib/anotherFile.rb"); console.lineAppend(SYNTAX_IN_REQUIRE) ; console.assertLinkCount(2); console.assertLink( 1, 21, "/RdtTest/FooTest.rb", 2, 0); console.assertLink(37, 28, "/RdtTestLib/anotherFile.rb", 9, 1); } public void testSecondWithoutFirst() throws Exception { fileChecker.addKnownFile("c:/d/abc.rb"); console.lineAppend("\tfrom c:/d/abc.rb:99") ; console.assertLink(6, 14, "c:/d/abc.rb", 99, 0); } public void testInCorrect() throws Exception { fileChecker.addKnownFile("/d/t.rb"); console.lineAppend("/d/t.rb:a:in `require': No such file to load -- inifile (LoadError)") ; console.lineAppend("/d/t.rb:123 "); console.assertLinkCount(0); } /** * From http://www.aptana.com/trac/ticket/5019 * @throws Exception */ public void testBackslashesInFilePath() throws Exception { fileChecker.addKnownFile("C:\\ruby\\lib\\ruby\\gems\\1.8\\gems\\rails-1.2.3\\lib/commands/server.rb"); console.lineAppend("\tfrom C:\\ruby\\lib\\ruby\\gems\\1.8\\gems\\rails-1.2.3\\lib/commands/server.rb:1") ; console.assertLinkCount(1); console.assertLink(6, 67, "C:\\ruby\\lib\\ruby\\gems\\1.8\\gems\\rails-1.2.3\\lib/commands/server.rb", 1, 0); } public void testWorkspaceRelativeStartingWithSlash() throws Exception { fileChecker.addKnownFile("/app/controllers/tags_controller.rb"); console.lineAppend("\t/app/controllers/tags_controller.rb:5:in `index'") ; console.assertLinkCount(1); console.assertLink(1, 37, "/app/controllers/tags_controller.rb", 5, 0); } private final class MockFileExistanceChecker implements RubyConsoleTracker.FileExistanceChecker { private List knownFiles = new ArrayList(); public void addKnownFile(String filename) { knownFiles.add(filename); } public boolean fileExists(String filename) { return knownFiles.contains(filename); } } public class TestConsole implements IConsole { private class MetaLink { public RubyStackTraceHyperlink link; public int offset; public int length; } private List metaLinks = new ArrayList(); SimpleDocument doc = new SimpleDocument() ; RubyConsoleTracker tracker ; public TestConsole(FileExistanceChecker fileChecker) throws Exception { tracker = new RubyConsoleTracker(fileChecker){ @Override protected IProject getProject() { return null; } }; tracker.init(this) ; } public void assertLinkCount(int expectedLinkCount) { assertEquals(expectedLinkCount, metaLinks.size()); } public void assertLink(int expectedOffset, int expectedLength, String expectedFilename, int expectedLineNumber, int linkIndex) { try { MetaLink metaLink = (MetaLink) metaLinks.get(linkIndex); assertNotNull(metaLink); assertEquals("Offset of link["+linkIndex+"]", expectedOffset, metaLink.offset); assertEquals(expectedLength, metaLink.length); assertEquals(expectedFilename, metaLink.link.getFilename()); assertEquals(expectedLineNumber, metaLink.link.getLineNumber()); } catch (IndexOutOfBoundsException e) { fail("Link index out of bounds: (" + linkIndex + ")"); } } public void addLink(IConsoleHyperlink pLink, int pOffset, int pLength) { } public void addLink(org.eclipse.ui.console.IHyperlink pLink, int pOffset, int pLength) { MetaLink metaLink = new MetaLink(); metaLink.link = (RubyStackTraceHyperlink) pLink ; metaLink.offset = pOffset ; metaLink.length = pLength ; metaLinks.add(metaLink); } public void connect(IStreamMonitor streamMonitor, String streamIdentifer) { throw new RuntimeException("Not Implemented Exception"); } public void connect(IStreamsProxy streamsProxy) { throw new RuntimeException("Not Implemented Exception"); } public IDocument getDocument() { return doc; } public IProcess getProcess() { throw new RuntimeException("Not Implemented Exception"); } public IRegion getRegion(IConsole link) { throw new RuntimeException("Not Implemented Exception"); } public void lineAppend(String pLine) throws Exception { doc.set(pLine) ; tracker.lineAppended(doc.getLineInformationOfOffset(1)) ; } public IRegion getRegion(IConsoleHyperlink link) { // TODO Auto-generated method stub return null; } public IRegion getRegion(org.eclipse.ui.console.IHyperlink link) { // TODO Auto-generated method stub return null; } public void addPatternMatchListener(IPatternMatchListener matchListener) { // TODO Auto-generated method stub } public void removePatternMatchListener(IPatternMatchListener matchListener) { // TODO Auto-generated method stub } public IOConsoleOutputStream getStream(String streamIdentifier) { // TODO Auto-generated method stub return null; } } public class SimpleDocument extends AbstractDocument { public SimpleDocument() { // The text store is not really necessary, but there is a not null assert in AbstractDocument this.setTextStore(new GapTextStore(1,2)) ; setLineTracker(new DefaultLineTracker()); completeInitialization(); } } }