/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.google.dart.tools.ui.internal.text.dart;
import com.google.dart.engine.EngineTestCase;
import com.google.dart.tools.core.formatter.DefaultCodeFormatterConstants;
import com.google.dart.tools.internal.corext.refactoring.util.ReflectionUtils;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.text.DartPartitions;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import static org.fest.assertions.Assertions.assertThat;
public class DartAutoIndentStrategyTest extends EngineTestCase {
private static final String EOL = System.getProperty("line.separator", "\n");
private static final String USE_SPACES = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SPACES_FOR_TABS;
private static final String TAB_CHAR = DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR;
private static void assert_customizeDocumentCommand(String initial, String newText,
String expected) {
int initialOffset = initial.indexOf('!');
int expectedOffset = expected.indexOf('!');
assertTrue("No cursor position in initial: " + initial, initialOffset != -1);
assertTrue("No cursor position in expected: " + expected, expectedOffset != -1);
initial = StringUtils.remove(initial, '!');
expected = StringUtils.remove(expected, '!');
// force "smart mode"
DartAutoIndentStrategy_NEW strategy = new DartAutoIndentStrategy_NEW(
DartPartitions.DART_PARTITIONING,
null) {
@Override
protected boolean computeSmartMode() {
return true;
}
};
// prepare document
IDocument document = new Document(initial);
// handle command
DocumentCommand command = new DocumentCommand() {
};
command.caretOffset = -1;
command.doit = true;
command.offset = initialOffset;
command.text = newText;
strategy.customizeDocumentCommand(document, command);
// update document
ReflectionUtils.invokeMethod(command, "execute(org.eclipse.jface.text.IDocument)", document);
// check new content
String actual = document.get();
assertEquals(expected, actual);
// check caret offset
int actualOffset = command.caretOffset;
if (actualOffset == -1) {
actualOffset = initialOffset + command.text.length();
}
assertThat(actualOffset).isEqualTo(expectedOffset);
}
private static void assertSmartInsertAfterNewLine(String initial, String expected) {
assert_customizeDocumentCommand(initial, EOL, expected);
}
private static void assertSmartPaste(String initial, String newText, String expected) {
assert_customizeDocumentCommand(initial, newText, expected);
}
public void test_afterConditional_withInvocation() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" var v = true ?",
" ''.length() : 0;!",
"}"), createSource(//
"main() {",
" var v = true ?",
" ''.length() : 0;",
" !",
"}"));
}
public void test_afterFor_withBody() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" for (var x = 0; x < 10; x++) print(x);!",
"}"), createSource(//
"main() {",
" for (var x = 0; x < 10; x++) print(x);",
" !",
"}"));
}
public void test_afterForIn_noBody() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" for (var x in [1, 2, 3])!",
"}"), createSource(//
"main() {",
" for (var x in [1, 2, 3])",
" !",
"}"));
}
public void test_afterForIn_withBody() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" for (var x in [1, 2, 3]) print(x);!",
"}"), createSource(//
"main() {",
" for (var x in [1, 2, 3]) print(x);",
" !",
"}"));
}
public void test_inMapLiteral_inList() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" [{'A': 0,",
" 'B': 0},",
" {'A': 1,! 'B': 1}];",
"}"), createSource(//
"main() {",
" [{'A': 0,",
" 'B': 0},",
" {'A': 1,",
" !'B': 1}];",
"}"));
}
public void test_smartIndentAfterNewLine_afterClassPrologue() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"class A {!",
"main() {}"), createSource(//
"class A {",
" !",
"}",
"main() {}"));
}
public void test_smartIndentAfterNewLine_afterClassPrologue_withExtends() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"class A extends Object implements B, C, D {!",
"main() {}"), createSource(//
"class A extends Object implements B, C, D {",
" !",
"}",
"main() {}"));
}
public void test_smartIndentAfterNewLine_afterLBrace_beforeAnd() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" if (true) {! && false) {",
" print(42);",
" }",
"}"), createSource(//
"main() {",
" if (true) {",
" !&& false) {",
" print(42);",
" }",
"}"));
}
public void test_smartIndentAfterNewLine_afterMethod() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"class A {",
" m();!",
"}"), createSource(//
"class A {",
" m();",
" !",
"}"));
}
public void test_smartIndentAfterNewLine_block_closed_betweenBraces() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" {!}",
"}"), createSource(//
"main() {",
" {",
" !",
" }",
"}"));
}
public void test_smartIndentAfterNewLine_block_noClosed() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" {!",
"}"), createSource(//
"main() {",
" {",
" !",
" }",
"}"));
}
/**
* <p>
* https://code.google.com/p/dart/issues/detail?id=16899
*/
public void test_smartIndentAfterNewLine_blockAfterWrappedArgumentList() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" f(",
" 111,",
" 222).then(() {!",
" });",
"}"), createSource(//
"main() {",
" f(",
" 111,",
" 222).then(() {",
" !",
" });",
"}"));
}
public void test_smartIndentAfterNewLine_class_closed_hasEOLC() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"class A {!",
"// this comment used to cause a problem",
"}",
""), createSource(//
"class A {",
" !",
"// this comment used to cause a problem",
"}",
""));
}
public void test_smartIndentAfterNewLine_class_noClosed() throws Exception {
assertSmartInsertAfterNewLine("class A {!", createSource(//
"class A {",
" !",
"}").trim());
}
public void test_smartIndentAfterNewLine_class_noClosed_leadingEOLC() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"// this comment used to cause a problem",
"class A {!",
""), createSource(//
"// this comment used to cause a problem",
"class A {",
" !",
"}",
""));
}
public void test_smartIndentAfterNewLine_closure_closed() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" print((_) {!});",
"}"), createSource(//
"main() {",
" print((_) {",
" !",
" });",
"}"));
}
public void test_smartIndentAfterNewLine_closure_notClosed_beforeComma() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" print((_) {!, 42);",
"}"), createSource(//
"main() {",
" print((_) {",
" !",
" }, 42);",
"}"));
}
public void test_smartIndentAfterNewLine_closure_notClosed_beforeRBracket() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" print([(_) {!]);",
"}"), createSource(//
"main() {",
" print([(_) {",
" !",
" }]);",
"}"));
}
public void test_smartIndentAfterNewLine_closure_notClosed_beforeRParen() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" print((_) {!);",
"}"), createSource(//
"main() {",
" print((_) {",
" !",
" });",
"}"));
}
public void test_smartIndentAfterNewLine_function_hasClosed() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {!}"),
createSource(//
"main() {",
" !",
"}"));
}
public void test_smartIndentAfterNewLine_function_hasClosed_hasStatement() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {!",
" print(0);",
"}"), createSource(//
"main() {",
" !",
" print(0);",
"}"));
}
/**
* We don't wrap the expression into {} as per discussion in
* https://code.google.com/p/dart/issues/detail?id=17046
*/
public void test_smartIndentAfterNewLine_function_hasExpression_sameLine() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {!42;"),
createSource(//
"main() {",
" !42;"));
}
public void test_smartIndentAfterNewLine_function_noClosed() throws Exception {
assertSmartInsertAfterNewLine("main() {!", createSource(//
"main() {",
" !",
"}").trim());
}
/**
* <p>
* https://code.google.com/p/dart/issues/detail?id=21893
*/
public void test_smartIndentAfterNewLine_listLiteral() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" var aaaaaaaaaaaa = [!",
" ];",
"}"), createSource(//
"main() {",
" var aaaaaaaaaaaa = [",
" !",
" ];",
"}"));
}
/**
* <p>
* https://code.google.com/p/dart/issues/detail?id=21893
*/
public void test_smartIndentAfterNewLine_mapLiteral() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" var mmmmmmmmm = {!",
" };",
"}"), createSource(//
"main() {",
" var mmmmmmmmm = {",
" !",
" };",
"}"));
}
public void test_smartIndentAfterNewLine_method_hasClosed() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"class A {",
" m() {!}",
"}"), createSource(//
"class A {",
" m() {",
" !",
" }",
"}"));
}
/**
* We don't wrap the statement into {} as per discussion in
* https://code.google.com/p/dart/issues/detail?id=17046
*/
public void test_smartIndentAfterNewLine_wrapIntoBlock() throws Exception {
assertSmartInsertAfterNewLine(createSource(//
"main() {",
" if (true) {!print();",
"}"), createSource(//
"main() {",
" if (true) {",
" !print();",
"}"));
}
public void test_smartPaste_cascade_afterCascade() throws Exception {
assertSmartPaste(createSource(//
"main() {",
" a",
" ..b = 100",
"! ..c()",
" ..d();",
"}"), "..x()" + EOL, createSource(//
"main() {",
" a",
" ..b = 100",
" ..x()",
"! ..c()",
" ..d();",
"}"));
}
public void test_smartPaste_cascade_afterTarget() throws Exception {
assertSmartPaste(createSource(//
"main() {",
" a",
"! ..b = 100",
" ..c()",
" ..d();",
"}"), "..x()" + EOL, createSource(//
"main() {",
" a",
" ..x()",
"! ..b = 100",
" ..c()",
" ..d();",
"}"));
}
/**
* We should keep original difference between first and following lines.
*/
public void test_smartPaste_cascade_complete_onlyAssignments() throws Exception {
assertSmartPaste(createSource(//
"main() {",
"!}"), createSource(//
" aaa",
" ..bbb = 1",
" ..ccc = 2;"), createSource(//
"main() {",
" aaa",
" ..bbb = 1",
" ..ccc = 2;",
"!}"));
}
/**
* We should keep original difference between first and following lines.
*/
public void test_smartPaste_cascade_complete_withInvocation() throws Exception {
assertSmartPaste(createSource(//
"main() {",
"!}"), createSource(//
" aaa",
" ..bbb()",
" ..ccc = 2;"), createSource(//
"main() {",
" aaa",
" ..bbb()",
" ..ccc = 2;",
"!}"));
}
public void test_smartPaste_multiLineString_doubleQuote() throws Exception {
assertSmartPaste(createSource(//
"main() {",
" var a = !;",
"}"), "\"\"\"" + EOL + "000" + EOL + " 111" + EOL + "\"\"\"", createSource(//
"main() {",
" var a = \"\"\"",
"000",
" 111",
"\"\"\"!;",
"}"));
}
public void test_smartPaste_multiLineString_singleQuote() throws Exception {
assertSmartPaste(createSource(//
"main() {",
" var a = !;",
"}"), "'''" + EOL + "000" + EOL + " 111" + EOL + "'''", createSource(//
"main() {",
" var a = '''",
"000",
" 111",
"'''!;",
"}"));
}
public void test_smartPaste_preventNegativeIndent() throws Exception {
assertSmartPaste(createSource(//
"main() {",
"!}"), createSource(//
" var a;",
"var b;"), createSource(//
"main() {",
" var a;",
"var b;",
"!}"));
}
public void test_useTabs() throws Exception {
// We have 1000 and one listener for preferences that expect that we run them in UI.
// Just make them happy...
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
IPreferenceStore preferenceStore = DartToolsPlugin.getDefault().getPreferenceStore();
try {
preferenceStore.setValue(USE_SPACES, false);
preferenceStore.setValue(TAB_CHAR, "tab");
assertSmartInsertAfterNewLine(createSource(//
"main() {!",
"}"), createSource(//
"main() {",
"\t!",
"}"));
} finally {
preferenceStore.setToDefault(USE_SPACES);
preferenceStore.setToDefault(TAB_CHAR);
}
}
});
}
}