package com.redhat.ceylon.eclipse.ui.test.headless; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_ANGLES; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_BACKTICKS; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_BRACKETS; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_PARENS; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_QUOTES; import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.CLOSE_BRACES; import static org.junit.Assert.assertEquals; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IDocument; import org.eclipse.swt.graphics.Point; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import com.redhat.ceylon.eclipse.code.editor.CeylonAutoEditStrategy; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; public class AutoEditTests { @BeforeClass public static void setupPreferences() { String[] FENCES = { CLOSE_BRACES, CLOSE_QUOTES, CLOSE_BACKTICKS, CLOSE_ANGLES, CLOSE_PARENS, CLOSE_BRACKETS}; IPreferenceStore store = CeylonPlugin.getPreferences(); for (String closeSetting : FENCES) { store.setValue(closeSetting, true); store.setDefault(closeSetting, true); } } @Test public void testCorrectIndentation1() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\n\nvoid method(){\n\nfor (x in xs){}\n\n}\n\n}", "class Test()\n\t\textends Super(){\n\t\n\tvoid method(){\n\t\t\n\t\tfor (x in xs){}\n\t\t\n\t}\n\t\n}"); } @Test public void testCorrectIndentation2() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\n\nvoid method(){}\n\n}", "class Test()\n\t\textends Super(){\n\t\n\tvoid method(){}\n\t\n}"); } @Test public void testCorrectIndentation3() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\n\n\t\tvoid method(){}\n\t\n}", "class Test()\n\t\textends Super(){\n\t\n\tvoid method(){}\n\t\n}"); } @Test public void testCorrectIndentation4() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\nvoid method(){}\n}", "class Test()\n\t\textends Super(){\n\tvoid method(){}\n}"); } @Test public void testCorrectIndentation5() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\nvoid method(){\nfor (x in xs){}\n}\n}", "class Test()\n\t\textends Super(){\n\tvoid method(){\n\t\tfor (x in xs){}\n\t}\n}"); } @Test public void testCorrectIndentation6() { checkForCorrectIndentation( "class Test()\n\t\textends Super(){\n\t\tvoid method(){}\n}", "class Test()\n\t\textends Super(){\n\tvoid method(){}\n}"); } @Test public void testCorrectIndentation7() { checkForCorrectIndentation( "class Test()\nextends Super(){\n\nvoid method(){}\n\n}", "class Test()\n\t\textends Super(){\n\t\n\tvoid method(){}\n\t\n}"); } @Test public void testCorrectIndentation8() { checkForCorrectIndentation( "class Test() extends Super(){\n\nvoid method(){}\n\t\n}", "class Test() extends Super(){\n\t\n\tvoid method(){}\n\t\n}"); } @Test public void testCorrectIndentation9() { checkForCorrectIndentation( "class Test()\n\t\textends Super()\n{\n\nvoid method(){}\n\t\n}", "class Test()\n\t\textends Super()\n{\n\t\n\tvoid method(){}\n\t\n}"); } @Test public void testCorrectIndentation10() { checkForCorrectIndentation( "\tclass Test()\n\t\textends Super(){\n\nvoid method(){\n}\n\t\n}", "class Test()\n\t\textends Super(){\n\t\n\tvoid method(){\n\t}\n\t\n}"); } @Test public void testCorrectIndentation11() { checkForCorrectIndentation( "void x(){\n\tclass Test()\n\t\textends Super(){\n\nvoid method(){\n}\n\t\n}", "void x(){\n\tclass Test()\n\t\t\textends Super(){\n\t\t\n\t\tvoid method(){\n\t\t}\n\t\t\n\t}"); } @Test public void testCorrectIndentation12() { checkForCorrectIndentation( "void x(){\n\tclass Test()\n\t\textends Super(){\nvoid method(){\n}\n}\n", "void x(){\n\tclass Test()\n\t\t\textends Super(){\n\t\tvoid method(){\n\t\t}\n\t}\n"); } @Test public void testCorrectIndentation13() { checkForCorrectIndentation( "void x(){\n\tclass Test()\n\t\textends Super(){//foo\nvoid method(){//bar\n}//baz\n}\n", "void x(){\n\tclass Test()\n\t\t\textends Super(){//foo\n\t\tvoid method(){//bar\n\t\t}//baz\n\t}\n"); } @Test public void testCorrectIndentation14() { checkForCorrectIndentation( "doc (\"Hello\n\t World\n\t !\")\nvoid hello(){}", "doc (\"Hello\n World\n !\")\nvoid hello(){}"); } @Test public void testCorrectIndentation15() { checkForCorrectIndentation( "\"Hello\n World\n !\"\nvoid hello(){}", "\"Hello\n World\n !\"\nvoid hello(){}"); } @Test public void testCorrectIndentation16() { checkForCorrectIndentation( "\"\"\"Hello\n World\n !\"\"\"\nvoid hello(){}", "\"\"\"Hello\n World\n !\"\"\"\nvoid hello(){}"); } @Test public void testCorrectIndentation17() { checkForCorrectIndentation( "void x(){\n\t\"\"\"Hello\n\t World\n\t !\"\"\"\n\tvoid hello(){}", "void x(){\n\t\"\"\"Hello\n\t World\n\t !\"\"\"\n\tvoid hello(){}"); } @Test @Ignore("This test fails, but that is more of a conceptual\n" + "problem with how the whole concept of correct\n" + "indentation works") public void testCorrectIndentation18() { //Note: this test fails, but that is more of a conceptual // problem with how the whole concept of correct // indentation works! checkForCorrectIndentation( "\t\"\"\"Hello\n\t World\n\t !\"\"\"\n\tvoid hello(){}", "\"\"\"Hello\n World\n !\"\"\"\nvoid hello(){}"); } @Test public void testCorrectIndentation19() { checkForCorrectIndentation( "String x()\n=>\"hello\";", "String x()\n\t\t=>\"hello\";"); } @Test public void testCorrectIndentation20() { checkForCorrectIndentation( "String x()\n\t=>\"hello\";", "String x()\n\t\t=>\"hello\";"); } @Test public void testCorrectIndentation21() { checkForCorrectIndentation( "String x()\n\t\t=>\"hello\";", "String x()\n\t\t=>\"hello\";"); } @Test public void testCorrectIndentation22() { checkForCorrectIndentation( "void x(){\n\tString x()\n\t\t\t=>\"hello\";", "void x(){\n\tString x()\n\t\t\t=>\"hello\";"); } @Test public void testCorrectIndentation23() { checkForCorrectIndentation( "\tString x()\n\t\t\t=>\"hello\";", "String x()\n\t\t=>\"hello\";"); } @Test public void testCorrectIndentation24() { checkForCorrectIndentation( "class X()\nextends Y()", "class X()\n\t\textends Y()"); } @Test public void testCorrectIndentation25() { checkForCorrectIndentation( "class X()\n\textends Y()", "class X()\n\t\textends Y()"); } @Test public void testCorrectIndentation26() { checkForCorrectIndentation( "class X()\n\t\textends Y()", "class X()\n\t\textends Y()"); } @Test public void testCorrectIndentation27() { checkForCorrectIndentation( "void x(){\n\tclass X()\n\t\t\textends Y()", "void x(){\n\tclass X()\n\t\t\textends Y()"); } @Test public void testCorrectIndentation28() { checkForCorrectIndentation( "class X()\nextends Y()\nsatisfies Z", "class X()\n\t\textends Y()\n\t\tsatisfies Z"); } @Test public void testCorrectIndentation29() { checkForCorrectIndentation( "class X()\n\textends Y()\n\tsatisfies Z", "class X()\n\t\textends Y()\n\t\tsatisfies Z"); } @Test public void testCorrectIndentation30() { checkForCorrectIndentation( "class X()\n\t\textends Y()\n\t\tsatisfies Z", "class X()\n\t\textends Y()\n\t\tsatisfies Z"); } @Test public void testCorrectIndentation31() { checkForCorrectIndentation( "void x(){\n\tclass X()\n\t\t\textends Y()\n\t\t\tsatisfies Z", "void x(){\n\tclass X()\n\t\t\textends Y()\n\t\t\tsatisfies Z"); } @Test public void testCorrectIndentation32() { checkForCorrectIndentation( "\tclass X()\n\t\t\textends Y()\n\t\t\tsatisfies Z", "class X()\n\t\textends Y()\n\t\tsatisfies Z"); } @Test public void testCorrectIndentation33() { checkForCorrectIndentation( "void x(){\n\t//comment\n", "void x(){\n\t//comment\n"); } @Test public void testCorrectIndentation34() { checkForCorrectIndentation( "void x(){\n//comment\n", "void x(){\n\t//comment\n"); } @Test public void testCorrectIndentation35() { checkForCorrectIndentation( "void x(){\n\t\t//comment\n", "void x(){\n\t//comment\n"); } @Test public void testCorrectIndentation36() { checkForCorrectIndentation( "\t//comment\n", "//comment\n"); } @Test public void testCorrectIndentation37() { checkForCorrectIndentation( "\t\t//comment\n", "//comment\n"); } @Test public void testCorrectIndentation38() { checkForCorrectIndentation( "\t/*\n\tcomment\n\t*/\n", "/*\n comment\n */\n"); } @Test public void testCorrectIndentation39() { checkForCorrectIndentation( "\t\t/*\n\tcomment\n\t*/\n", "/*\n comment\n */\n"); } @Test public void testNewLine1() { checkForNewLine( "x=1;", "x=1;\n"); } @Test public void testNewLine2() { checkForNewLine( "x=1; ", "x=1; \n"); } @Test public void testNewLine3() { checkForNewLine( "void x(){\n\tx=1;", "void x(){\n\tx=1;\n\t"); } @Test public void testNewLine4() { checkForNewLine( "void x(){\n\tx=1; //foo", "void x(){\n\tx=1; //foo\n\t"); } @Test public void testNewLine5() { checkForNewLine( "void x(){\nvoid y(){\n\t\tx=1; //foo", "void x(){\nvoid y(){\n\t\tx=1; //foo\n\t\t"); } @Test public void testNewLine6() { checkForNewLine( "\tx=1; //foo", "\tx=1; //foo\n\t"); } @Test public void testNewLine7() { checkForNewLine( "\t\tx=1; //foo", "\t\tx=1; //foo\n\t\t"); } @Test public void testNewLine8() { checkForNewLine( "Integer x {", "Integer x {\n\t\n}"); } @Test public void testNewLine9() { checkForNewLine( "Integer x { ", "Integer x { \n\t\n}"); } @Test public void testNewLine10() { checkForNewLine( "\tInteger x {", "\tInteger x {\n\t\t\n\t}"); } @Test public void testNewLine11() { checkForNewLine( "\tInteger x { //foo", "\tInteger x { //foo\n\t\t\n\t}"); } @Test public void testNewLine12() { checkForNewLine( "\t\tInteger x { //foo", "\t\tInteger x { //foo\n\t\t\t\n\t\t}"); } @Test public void testNewLine13() { checkForNewLine( "//hello", "//hello\n"); } @Test public void testNewLine14() { checkForNewLine( "//hello ", "//hello \n"); } @Test public void testNewLine15() { checkForNewLine( "\t//hello", "\t//hello\n\t"); } @Test public void testNewLine16() { checkForNewLine( "\t//hello ", "\t//hello \n\t"); } @Test public void testNewLine17() { checkForNewLine( "\t\t//hello", "\t\t//hello\n\t\t"); } @Test public void testNewLine18() { checkForNewLine( "//hello\n", "//hello\n\n"); } @Test public void testNewLine19() { checkForNewLine( "\t//hello\n", "\t//hello\n\n\t"); } @Test public void testNewLine20() { checkForNewLine( "\t//hello\n\t", "\t//hello\n\t\n\t"); } @Test public void testNewLine21() { checkForNewLine( "//hello \n ", "//hello \n \n"); } @Test public void testNewLine22() { checkForNewLine( "//hello \n\t", "//hello \n\t\n"); } @Test public void testNewLine23() { checkForNewLine( "\t//hello \n\t", "\t//hello \n\t\n\t"); } @Test public void testNewLine24() { checkForNewLine( "\t//hello\n\t", "\t//hello\n\t\n\t"); } @Test public void testNewLine25() { checkForNewLine( "\t//hello \n\t", "\t//hello \n\t\n\t"); } @Test public void testNewLine26() { checkForNewLine( "/*hello", "/*hello\n \n */"); } @Test public void testNewLine27() { checkForNewLine( "\t/*hello", "\t/*hello\n\t \n\t */"); } @Test public void testNewLine28() { checkForNewLine( "\t/*\n\thello", "\t/*\n\thello\n\t "); } @Test public void testNewLine29() { checkForNewLine( "void x() {}", "void x() {}\n"); } @Test public void testNewLine30() { checkForNewLine( "void x() {} ", "void x() {} \n"); } @Test public void testNewLine31() { checkForNewLine( "\tvoid x() {}", "\tvoid x() {}\n\t"); } @Test public void testNewLine32() { checkForNewLine( "\tvoid x() {} //foo", "\tvoid x() {} //foo\n\t"); } @Test public void testNewLine33() { checkForNewLine( "x=1;\n", "x=1;\n\n"); } @Test public void testNewLine34() { checkForNewLine( "x=1; \n ", "x=1; \n \n "); //do we really want the space at the end here? } @Test public void testNewLine35() { checkForNewLine( "\tx=1;\n\t", "\tx=1;\n\t\n\t"); } @Test public void testNewLine36() { checkForNewLine( "\tx=1; //foo\n\t", "\tx=1; //foo\n\t\n\t"); } @Test public void testNewLine37() { checkForNewLine( "\t\tx=1; //foo\n\t\t", "\t\tx=1; //foo\n\t\t\n\t\t"); } @Test public void testNewLine38() { checkForNewLine( "Integer x {\n\t", "Integer x {\n\t\n\t"); } @Test public void testNewLine39() { checkForNewLine( "Integer x { \n\t", "Integer x { \n\t\n\t"); } @Test public void testNewLine40() { checkForNewLine( "\tInteger x {\n\t\t", "\tInteger x {\n\t\t\n\t\t"); } @Test public void testNewLine41() { checkForNewLine( "\tInteger x { //foo\n\t\t", "\tInteger x { //foo\n\t\t\n\t\t"); } @Test public void testNewLine42() { checkForNewLine( "\t\tInteger x { //foo\n\t\t\t", "\t\tInteger x { //foo\n\t\t\t\n\t\t\t"); } @Test public void testNewLine43() { checkForNewLine( "void x() {}\n", "void x() {}\n\n"); } @Test public void testNewLine44() { checkForNewLine( "void x() {} \n ", "void x() {} \n \n "); //do we really want the space } @Test public void testNewLine45() { checkForNewLine( "\tvoid x() {}\n\t", "\tvoid x() {}\n\t\n\t"); } @Test public void testNewLine46() { checkForNewLine( "\tvoid x() {} //foo\n\t", "\tvoid x() {} //foo\n\t\n\t"); } @Test public void testNewLine47() { checkForNewLine( "String greeting = \"hello", "String greeting = \"hello\n "); } @Test public void testNewLine48() { checkForNewLine( "\tString greeting = \"hello", "\tString greeting = \"hello\n\t "); } @Test public void testNewLine49() { checkForNewLine( "String greeting = \"hello\n world", "String greeting = \"hello\n world\n "); } @Test public void testNewLine50() { checkForNewLine( "\tString greeting = \"hello\n\t world", "\tString greeting = \"hello\n\t world\n\t "); } @Test public void testNewLine51() { checkForNewLine( "String greeting = \"\"\"hello", "String greeting = \"\"\"hello\n "); } @Test public void testNewLine52() { checkForNewLine( "\tString greeting = \"\"\"hello", "\tString greeting = \"\"\"hello\n\t "); } @Test public void testNewLine53() { checkForNewLine( "String greeting = \"\"\"hello\n world", "String greeting = \"\"\"hello\n world\n "); } @Test public void testNewLine54() { checkForNewLine( "\tString greeting = \"\"\"hello\n\t world", "\tString greeting = \"\"\"hello\n\t world\n\t "); } @Test public void testNewLine55() { checkForNewLine( "String x()\n=>\"hello\" +", "String x()\n=>\"hello\" +\n\t\t"); } @Test public void testNewLine56() { //What should this one really do? Not well-defined checkForNewLine( "String x()\n\t=>\"hello\" +", "String x()\n\t=>\"hello\" +\n\t\t"); } @Test public void testNewLine57() { checkForNewLine( "String x()\n\t\t=>\"hello\" +", "String x()\n\t\t=>\"hello\" +\n\t\t"); } @Test public void testNewLine58() { checkForNewLine( "\tString x()\n\t\t\t=>\"hello\" +", "\tString x()\n\t\t\t=>\"hello\" +\n\t\t\t"); } @Test public void testNewLine59() { checkForNewLine( "String x()\n=>\"hello\";", "String x()\n=>\"hello\";\n"); } @Test public void testNewLine60() { checkForNewLine( "String x()\n\t=>\"hello\";", "String x()\n\t=>\"hello\";\n"); } @Test public void testNewLine61() { checkForNewLine( "String x()\n\t\t=>\"hello\";", "String x()\n\t\t=>\"hello\";\n"); } @Test public void testNewLine62() { checkForNewLine( "\tString x()\n\t\t\t=>\"hello\";", "\tString x()\n\t\t\t=>\"hello\";\n\t"); } @Test public void testClosingBrace1() { checkForClosingBrace( "void x() {\n\t", "void x() {\n}"); } @Test public void testClosingBrace2() { checkForClosingBrace( "\tvoid x() {\n\t\t", "\tvoid x() {\n\t}"); } @Test public void testClosingBrace3() { checkForClosingBrace( "void x() {\n\tprint(\"hello\");\n\t", "void x() {\n\tprint(\"hello\");\n}"); } @Test public void testClosingBrace4() { checkForClosingBrace( "void x() {\n\tprint(\"hello\");\n\t//bye\n\t", "void x() {\n\tprint(\"hello\");\n\t//bye\n}"); } private void doNewline(IDocument doc) { try { DocumentCommand cmd= new DocumentCommand() { }; cmd.offset= doc.getLength(); cmd.length= 0; cmd.text= Character.toString('\n'); cmd.doit= true; cmd.shiftsCaret= true; new CeylonAutoEditStrategy().customizeDocumentCommand(doc, cmd); doc.replace(cmd.offset, cmd.length, cmd.text); } catch (BadLocationException e) { System.err.println("Correct Indentation command failed " + e.getMessage()); } } private void doClosingBrace(IDocument doc) { try { DocumentCommand cmd= new DocumentCommand() { }; cmd.offset= doc.getLength(); cmd.length= 0; cmd.text= Character.toString('}'); cmd.doit= true; cmd.shiftsCaret= true; new CeylonAutoEditStrategy().customizeDocumentCommand(doc, cmd); doc.replace(cmd.offset, cmd.length, cmd.text); } catch (BadLocationException e) { System.err.println("Correct Indentation command failed " + e.getMessage()); } } private void checkForCorrectIndentation(String before, String expectedIndentation) { Document doc = new Document(before); doCorrectIndentation(doc); assertEquals(expectedIndentation, doc.get()); } private void checkForNewLine(String before, String expectedIndentation) { Document doc = new Document(before); doNewline(doc); assertEquals(expectedIndentation, doc.get()); } private void checkForClosingBrace(String before, String expectedIndentation) { Document doc = new Document(before); doClosingBrace(doc); assertEquals(expectedIndentation, doc.get()); } void doCorrectIndentation(IDocument doc) { Point p = new Point(0, doc.getLength()); try { final int selStart= p.x; final int selLen= p.y; final int selEnd= selStart + selLen; final int startLine= doc.getLineOfOffset(selStart); int endLine= doc.getLineOfOffset(selEnd); // If the selection extends just to the beginning of the next line, don't indent that one too if (selLen > 0 && lookingAtLineEnd(doc, selEnd)) { endLine--; } // Indent each line using the AutoEditStrategy for(int line= startLine; line <= endLine; line++) { int lineStartOffset= doc.getLineOffset(line); // Replace the existing indentation with the desired indentation. // Use the language-specific AutoEditStrategy, which requires a DocumentCommand. DocumentCommand cmd= new DocumentCommand() { }; cmd.offset= lineStartOffset; cmd.length= 0; cmd.text= Character.toString('\t'); cmd.doit= true; cmd.shiftsCaret= false; // boolean saveMode= fAutoEditStrategy.setFixMode(true); new CeylonAutoEditStrategy().customizeDocumentCommand(doc, cmd); // fAutoEditStrategy.setFixMode(saveMode); doc.replace(cmd.offset, cmd.length, cmd.text); } } catch (BadLocationException e) { System.err.println("Correct Indentation command failed " + e.getMessage()); } } boolean lookingAtLineEnd(IDocument doc, int pos) { String[] legalLineTerms= doc.getLegalLineDelimiters(); try { for(String lineTerm: legalLineTerms) { int len= lineTerm.length(); if (pos > len && doc.get(pos - len, len).equals(lineTerm)) { return true; } } } catch (BadLocationException e) { //System.err.println("Error examining document for line termination", e); } return false; } }