org.dsource.ddt.lang.text.LangAutoEditStragetyTest.java Source code

Java tutorial

Introduction

Here is the source code for org.dsource.ddt.lang.text.LangAutoEditStragetyTest.java

Source

/*******************************************************************************
 * Copyright (c) 2010, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Bruno Medeiros - initial API and implementation
 *******************************************************************************/
package org.dsource.ddt.lang.text;

import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import mmrnmhrm.tests.ui.DeeUITests;

import org.eclipse.dltk.ui.CodeFormatterConstants;
import org.eclipse.dltk.ui.PreferenceConstants;
import org.eclipse.dltk.ui.text.util.TabStyle;
import org.eclipse.jface.preference.PreferenceStore;
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.jface.text.IRegion;
import org.eclipse.swt.SWT;
import org.junit.Test;

public class LangAutoEditStragetyTest extends Scanner_BaseTest {

    public static final String GENERIC_CODE = DeeUITests.readResource("common/samplecode.d");
    public static final String NEUTRAL_SRCX = GENERIC_CODE;

    public static final String PENDING_WS1 = "  ";
    public static final String PENDING_WS2 = "\t ";
    public static final String PENDING_TXT = "\tpending";

    protected LangAutoEditStrategy autoEditStrategy;

    protected LangAutoEditStrategy getAutoEditStrategy() {
        if (autoEditStrategy == null) {
            PreferenceStore prefStore = createPreferenceStore();
            autoEditStrategy = new LangAutoEditStrategy(prefStore, null) {
                @Override
                protected BlockHeuristicsScannner createBlockHeuristicsScanner(IDocument doc) {
                    return Scanner_BaseTest.createBlockHeuristicScannerWithSamplePartitioning(doc);
                };
            };
        }
        return autoEditStrategy;
    }

    protected PreferenceStore createPreferenceStore() {
        PreferenceStore prefStore = new PreferenceStore();
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_SMART_INDENT, true);
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_SMART_DEINDENT, true);
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_PARENTHESES_AS_BLOCKS, true);
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_CLOSE_BRACES, true);
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_CLOSE_BRACKETS, true);
        prefStore.setValue(LangAutoEditPreferenceConstants.AE_CLOSE_STRINGS, true);
        prefStore.setValue(PreferenceConstants.EDITOR_SMART_PASTE, true);

        prefStore.setValue(CodeFormatterConstants.FORMATTER_TAB_SIZE, 4);
        prefStore.setValue(CodeFormatterConstants.FORMATTER_TAB_CHAR, TabStyle.TAB.getName());
        return prefStore;
    }

    protected DocumentCommand createDocumentCommand(int start, int length, String text) {
        DocumentCommand documentCommand = new DocumentCommand() {
        };
        documentCommand.doit = true;
        documentCommand.text = text;

        documentCommand.offset = start;
        documentCommand.length = length;

        documentCommand.owner = null;
        documentCommand.caretOffset = -1;
        documentCommand.shiftsCaret = true;
        return documentCommand;
    }

    @Test
    public void testSmartIndentBasic() {
        testEnterAutoEdit("void main(){}", "blah", NL); // balance 0 : 0

        testEnterAutoEdit("void main(){", NL + "}", NL + TAB); // balance 0 : 1 (closed)
        testEnterAutoEdit("void main(){", "}", NL + TAB);
    }

    @Test
    public void testSmartIndentBasic2() {
        String dNL = getDocument().getDefaultLineDelimiter();
        // balance 0 : 1(unclosed)
        testEnterAutoEdit("void main{", "", NL + TAB, dNL + "}");
        testEnterAutoEdit("void main(", NL + "func(){}" + NL + "blah();", NL + TAB, NL + ")");
        testEnterAutoEdit("vo() main{", "  " + NL + "func(){}" + NL + "blah();", NL + TAB, NL + "}");
        // balance 0 : 1(unclosed but don't close due to pending text)
        testEnterAutoEdit("void main(){", "func(){}" + NL + "blah();", NL + TAB);
    }

    @Test
    public void testSmartIndentBasic3() {
        String s;

        s = line("func{") + TAB + "abc}"; // balance -1 : 0
        testEnterAutoEdit(s, "}" + NEUTRAL_SRC1, NL);

        s = line("func{{") + TAB + "abc}}"; // balance -2 : 0
        testEnterAutoEdit(s, "}" + NEUTRAL_SRC1, NL);

        s = line(TAB + "func((") + TAB + "abc))"; // balance -2 : 0    '('
        testEnterAutoEdit(s, NEUTRAL_SRC1 + ")", NL + TAB);
    }

    protected final void testEnterAutoEdit(String sourceBefore, String sourceAfter, String expectedEdit) {
        dotestEnterAutoEdit(sourceBefore, sourceAfter, expectedEdit, -1);
    }

    protected void testEnterAutoEdit(String textBefore, String textAfter, String expInsert, String expInsertAfter) {
        dotestEnterAutoEdit(textBefore, textAfter, expInsert + expInsertAfter, expInsert.length());
    }

    protected void dotestEnterAutoEdit(String textBefore, String textAfter, String expectedInsert,
            int offsetDelta) {
        Document document = setupDocument(textBefore, textAfter);
        int keypressOffset = textBefore.length();
        DocumentCommand docCommand = createDocumentCommand(keypressOffset, 0, NL);
        getAutoEditStrategy().customizeDocumentCommand(document, docCommand);
        int caretOffset = (offsetDelta == -1) ? -1 : textBefore.length() + offsetDelta;
        int replaceLength = 0;
        checkCommand(docCommand, expectedInsert, keypressOffset, replaceLength, caretOffset);
    }

    protected Document setupDocument(String textBefore, String textAfter) {
        Document document = getDocument();
        document.set(textBefore + textAfter);
        return document;
    }

    protected void checkCommand(DocumentCommand documentCommand, String text, int offset, int length) {
        checkCommand(documentCommand, text, offset, length, -1);
    }

    protected void checkCommand(DocumentCommand documentCommand, String text, int offset, int length,
            int caretOffset) {
        assertEquals(documentCommand.text, text);
        assertTrue(documentCommand.offset == offset);
        assertTrue(documentCommand.length == length);
        assertTrue(documentCommand.caretOffset == caretOffset);
        assertTrue(documentCommand.shiftsCaret == (caretOffset == -1));
    }

    @Test
    public void testSmartIndent() throws Exception {
        testSmartIndent$();
    }

    public void testSmartIndent$() throws Exception {
        int indent = 0;
        String s;

        s = mkline(indent, "func(") + mklast(indent, "abc{"); // test 0 : 1
        testEnterAutoEdit(s, NL + "})" + NEUTRAL_SRC1, expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, "}abc{"); // test -1 : 1
        testEnterAutoEdit(s, PENDING_WS1 + NL + "}" + NEUTRAL_SRC1, expectInd(indent + 1));

        indent = 1;

        s = mkline(indent, "func{") + mklast(indent, "\t\t "); // test all WhiteSpace   
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRCX, expectInd(indent + 2) + " ");

        s = mkline(indent, "func{") + mklast(indent, "\t\t "); // test all WhiteSpace with pending WhiteSpace   
        testEnterAutoEdit(s, PENDING_WS2 + NL + ")" + NEUTRAL_SRCX, expectInd(indent + 2) + " ");

        s = mkline(indent, "func{") + mklast(indent, "}blah("); // test another -1 : 1   
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRCX, expectInd(indent + 1));

        s = mkline(indent, "func({") + mklast(indent, "abc("); // test potential close (go outside dominating block?)
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRC1 + "}", expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, "abc("); // test potential close (unclosed dominating block)
        testEnterAutoEdit(s, NL + ")", expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, "abc("); // test potential close (pending text)
        testEnterAutoEdit(s, PENDING_TXT + NL + ")", expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, "}blah("); // test close, -1 : 1, right=(_
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1, expectInd(indent + 1), expectClose(indent + 1, ")"));

        s = mkline(indent, "func{") + mklast(indent, "}blah{{"); // test close, -1 : 2, right={{_
        testEnterAutoEdit(s, PENDING_WS2 + NL, expectInd(indent + 2), expectClose(indent + 2, "}"));

        s = mkline(indent, "func{") + mklast(indent, "}}blah{"); // test close, -2 : 1, right={_..
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1, expectInd(indent + 1), expectClose(indent + 1, "}"));

        s = mkline(indent, "func{") + mklast(indent, "}}blah{{"); // test close, -2 : 1, right= {{_..}     
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1 + "}", expectInd(indent + 2), expectClose(indent + 2, "}"));

        s = mkline(indent, "}}blah{") + mkline(indent, "{func{") + mkline(indent + 2, NEUTRAL_SRC1)
                + mklast(indent, "}blah{"); // test close, -2 : 1, right=}} {{..}{_..}     
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1 + mkline(indent, "}"), expectInd(indent + 1),
                expectClose(indent + 1, "}"));

        indent = 0;

        s = mkline(indent, "func{{{") + mklast(indent, TAB + "abc}}}"); // test -3 : 0
        testEnterAutoEdit(s, NL + NEUTRAL_SRCX, expectInd(indent + 0));

        s = mkline(indent + 7, "func({{{") + // start block still has : 2 open block
                mklast(indent, TAB + "abc}}"); // test -2 : 0
        testEnterAutoEdit(s, NL + NEUTRAL_SRCX, expectInd(indent + 7 + 2));

        indent = 0;
        s = mkline(indent, "func") + mklast(indent, TAB + "abc}}}"); // test -3 : 0 with zero indent
        testEnterAutoEdit(s, NL + NEUTRAL_SRCX, expectInd(indent + 0));

        s = mkline(indent, "func") + mklast(indent, "abc}}}"); // test -3 : 0 with zero indent
        testEnterAutoEdit(s, NL + NEUTRAL_SRCX, expectInd(indent + 0));

        s = mkline(indent, "func{{{") + mkline(indent + 4, "func{()}") + // test interim lines with irregular ident
                mklast(indent, TAB + "abc}}"); // -2 : 0
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1, expectInd(indent + 1));

        indent = 2;
        s = mkline(indent, NEUTRAL_SRC1) + // more lines
                mkline(indent, "}}func{{{") + // matching start block is -2 : 3
                mkline(indent, NEUTRAL_SRC1) + // more lines
                mkline(indent - 2, "func{()}") + // interim lines with irregular ident (negative)
                mklast(indent, TAB + "abc(blah{}) blah}}"); // -2 : 0
        testEnterAutoEdit(s, NL + NEUTRAL_SRCX, expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(0, ""); // test empty line   
        testEnterAutoEdit(s, "){" + NL + ")", expectInd(0));
    }

    @Test
    public void testSmartIdent_Boundary() throws Exception {
        testSmartIdent_Boundary$();
    }

    public void testSmartIdent_Boundary$() throws Exception {
        String s;
        s = "("; // test potential close
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRC1 + "}", expectInd(1));

        s = "}("; // test potential close
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRC1 + "}", expectInd(1));

        s = "{" + NL + "("; // test potential close
        testEnterAutoEdit(s, NL + "){", expectInd(1));
    }

    @Test
    public void testSmartIndent_xPartitioning() throws Exception {
        testSmartIndent_xPartitioning$();
    }

    public void testSmartIndent_xPartitioning$() throws Exception {
        assertContains(getDocument().getPartitionings(), SamplePartitionScanner.LANG_PARTITIONING);

        int indent = 1; // Needs to be greater than 1
        String s;

        s = mkline(indent, "func()") + mklast(0, "//" + TAB + "abc"); // test with line comment
        testEnterAutoEdit(s, NL + "})" + NEUTRAL_SRC1, expectInd(indent));

        s = mkline(indent, "func(") + mklast(0, "//" + TAB + "abc)"); // test with line comment, with +1 indent
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRC1, expectInd(indent + 1));

        s = mkline(indent, "func{") + mkline(indent + 1, "blah}") + mklast(0, "//" + TAB + "abc)"); // test with line comment, with -1 indent
        testEnterAutoEdit(s, NL + ")" + NEUTRAL_SRC1, expectInd(indent));

        s = mkline(indent, "{func(") + mklast(0, "//" + TAB + "abc"); // test with line comment, characters after
        testEnterAutoEdit(s, ")" + NL + NEUTRAL_SRC1, expectInd(indent + 2));

        s = mkline(indent, "func({") + mklast(0, "/**/"); // test with block comment, with +2 indent Close
        testEnterAutoEdit(s, NL + "blah" + NEUTRAL_SRC1, expectInd(indent + 2), expectClose(indent + 2, "}"));

        s = mkline(indent, "func(((") + mklast(indent, "// blah"); // test line comment with whitespace before, (This-Line)
        testEnterAutoEdit(s, NL + "}}}" + NEUTRAL_SRC1, expectInd(indent));
        s = mkline(indent, "func(((") + mklast(indent, "/**/"); // test block comment with whitespace before, (This-Line)
        testEnterAutoEdit(s, NL + "}}}" + NEUTRAL_SRC1, expectInd(indent));

        s = mkline(indent, "func(") + mklast(0, "/* */" + TAB + "abc{{{"); // test block comment with characters after, (This-Line)
        testEnterAutoEdit(s, NL + "}}})" + NEUTRAL_SRC1, expectInd(0 + 3));

        s = mklast(0, "//abc{"); // test line comment, no valid line before
        testEnterAutoEdit(s, NL + "})" + NEUTRAL_SRC1, expectInd(0));
        s = mklast(0, "/*abc{*/"); // test block comment, no valid line before
        testEnterAutoEdit(s, NL + "})" + NEUTRAL_SRC1, expectInd(0));

        s = mkline(indent, "func((()))") + mklast(0, "/**/"); // test block comment at EOF 
        testEnterAutoEdit(s, "", expectInd(indent));

        /* ------- */

        // we don't consider the after-edit text in the edit-line for block balance in any case
        // if this changes, we need to review these two test cases

        s = mkline(indent, "{func(") + mklast(0, "// foobar"); // test line comment, characters after that afect block balance
        testEnterAutoEdit(s, "afterEdit)}" + NL + NEUTRAL_SRC1,
                expectInd(indent + 2)/*, expectClose(indent+2, ")")*/);

        s = mkline(indent, "{func(") + mklast(0, "// foobar{"); // test line comment, characters after that afect block balance
        testEnterAutoEdit(s, "afterEdit)" + NL + NEUTRAL_SRC1,
                expectInd(indent + 2)/*, expectClose(indent+2, ")")*/);

        s = mkline(indent, "(func{") + mklast(indent, "/* foobar"); // test edit inside block comment
        testEnterAutoEdit(s, NL + "})*/})" + NEUTRAL_SRC1, expectInd(indent));

        s = mkline(indent, "{func(") + mklast(0, "/* foobar"); // test edit inside block comment
        testEnterAutoEdit(s, NL + ")}*/" + NEUTRAL_SRC1, expectInd(indent + 2), expectClose(indent + 2, ")"));

        s = mkline(indent, "{func}") + mklast(indent, "{func{/* foobar}"); // test edit inside block comment
        testEnterAutoEdit(s, NL + "}}*/}" + NEUTRAL_SRC1, expectInd(indent + 2), expectClose(indent + 2, "}"));

    }

    protected String mkline(int indent, String string) {
        return line(TABn(indent) + string);
    }

    protected String mklast(int indent, String string) {
        return TABn(indent) + string;
    }

    protected static String TABn(int indent) {
        return LangAutoEditsPreferencesAdapter.stringNTimes(TAB, indent);
    }

    protected static String expectInd(int indent) {
        return expectInd(NL, indent);
    }

    private static String expectInd(String nl, int indent) {
        return nl + TABn(indent);
    }

    protected static String expectClose(int indent, String close) {
        return NL + TABn(indent - 1) + close;
    }

    @Test
    public void testSmartIdent_SyntaxErrors() throws Exception {
        testSmartIdent_SyntaxErrors$();
    }

    public void testSmartIdent_SyntaxErrors$() throws Exception {
        String s;
        int indent = 0;

        s = mkline(indent, "func") + mklast(indent, "abc{"); // test 0 : 1 (with syntax error)
        testEnterAutoEdit(s, NL + "})" + NEUTRAL_SRC1, expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, TAB + "{ab(c}"); // test 0 : 0 (corrected)
        testEnterAutoEdit(s, PENDING_WS1 + NL + "}" + NEUTRAL_SRCX, expectInd(1 + indent));

        s = mkline(indent, "func{") + mklast(indent, TAB + "{ab)c}"); // test 0 : 0 (corrected)
        testEnterAutoEdit(s, NL + "}" + NEUTRAL_SRC3, expectInd(1 + indent));

        indent = 1;
        s = mkline(indent, "func{") + mklast(indent, TAB + "(ab{c)"); // test 0 : 2 (corrected)
        testEnterAutoEdit(s, NL + "}" + NEUTRAL_SRC1 + "}", expectInd(1 + indent + 2));

        s = mkline(indent, "func{") + mklast(indent, TAB + "(ab}c)"); // test -1 : 0 (corrected)
        testEnterAutoEdit(s, PENDING_WS2 + NL + "}" + NEUTRAL_SRCX, expectInd(indent));

        s = mkline(indent, "func{") + mklast(indent, "}blah{)"); // test -1 : 1 (corrected)
        testEnterAutoEdit(s, NL + "}" + NEUTRAL_SRC3, expectInd(indent + 1));

        s = mkline(indent, "func{") + mklast(indent, "}blah{)"); // test -1 : 1 with close, right={)_..   
        testEnterAutoEdit(s, NL + /*}*/ NEUTRAL_SRC1, expectInd(indent + 1), expectClose(indent + 1, "}"));

        s = mkline(indent, "func{") + mklast(indent, "}blah{)"); // test -1 : 1 with close, right={)_({..(}
        testEnterAutoEdit(s, NL + /*}*/ "({" + NEUTRAL_SRC1 + "(}", expectInd(indent + 1),
                expectClose(indent + 1, "}"));

        s = mkline(indent, "func{") + mkline(indent + 4, "func{()}") + // test interim lines with irregular ident
                mklast(indent + 1, "}blah("); // test close, -1 : 1, right=(_..} 
        testEnterAutoEdit(s, PENDING_WS2 + NL + NEUTRAL_SRC1 + "}", expectInd(indent + 2),
                expectClose(indent + 2, ")"));

        s = mkline(indent, "func{{){") + // (corrected)
                mklast(indent, TAB + "abc}}(}"); // test -3 : 0 (corrected)
        testEnterAutoEdit(s, PENDING_TXT + NL + NEUTRAL_SRCX, expectInd(indent + 0));

        s = mkline(indent, "func{({") + // (corrected on EOF)
                mklast(indent, TAB + "aaa}})"); // test -3 : 0
        testEnterAutoEdit(s, NL + NEUTRAL_SRC3, expectInd(indent + 0));

        s = mkline(indent, "func(") + // decoy
                mkline(indent + 7, "{func{") + // (corrected on '{' superblock )
                mklast(indent, "aaa})");
        testEnterAutoEdit(s, NL + NEUTRAL_SRC1, expectInd(indent + 7 + 1));
    }

    /* ---------------------------------------*/

    @Test
    public void testSmartDeIndent() throws Exception {
        testSmartDeIndent$();
    }

    public void testSmartDeIndent$() throws Exception {
        testSmartDeIndent$(NL);
        testSmartDeIndent$("\n");
    }

    protected void testSmartDeIndent$(String pNL) {
        String s;
        int indent = 0;

        s = mklast(0, "void main() {");
        testDeIndentAutoEdit(s, NL + TAB, pNL + "}");

        indent = 1;
        s = NEUTRAL_SRC1 + mklast(indent, "void main{} (");
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 1), pNL + ")");

        s = NEUTRAL_SRC1 + mklast(indent, "void main{({");
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 3), "{{" + NL + TABn(indent + 3 + 2));

        s = NEUTRAL_SRC1 + mklast(indent, "void main{({"); // Less indent than expected
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 1), "|{{", false);

        s = mkline(0, "") + mklast(indent, "\t\t"); // Test all Whitespace
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 2), PENDING_WS1 + pNL + ")");

        s = NEUTRAL_SRC1 + mklast(0, ""); // Test empty line
        testDeIndentAutoEdit(s, expectInd(pNL, 0), PENDING_WS2 + pNL + ")");

        s = NEUTRAL_SRC1 + mkline(indent + 0, "void func{({") + mklast(indent + 1, "void main()"); // test with 0 : 0 balance
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 1), PENDING_TXT + pNL + "}");

        s = NEUTRAL_SRC3 + mklast(indent, "void main{{)(");
        testDeIndentAutoEdit(s, expectInd(pNL, indent + 3), "");

        // Some boundary cases
        testDeIndentAutoEdit("", pNL + "", "");
        testDeIndentAutoEdit(TAB, pNL + "", "", false);
        testDeIndentAutoEdit(TAB + "func{", pNL + TAB, "", false);

        testBackSpaceCommandWithNoEffect(TAB, ""); // backspace on first line
        testBackSpaceCommandWithNoEffect(TAB, "{");
        testBackSpaceCommandWithNoEffect(" ", " {");
        testBackSpaceCommandWithNoEffect(pNL + TAB, TAB + "{");
        testBackSpaceCommandWithNoEffect(TAB + pNL + TAB + TAB, "");

        testDeleteCommandWithNoEffect("", pNL);
        testDeleteCommandWithNoEffect("", " ");
        testDeleteCommandWithNoEffect(TAB, pNL);
        testDeleteCommandWithNoEffect(NEUTRAL_SRC1, pNL);

        testArtificialNoopCommand("", ""); // Extreme boundary case
        testArtificialNoopCommand("", NL);
        testArtificialNoopCommand("", TAB);
        testArtificialNoopCommand(TAB, NL);
    }

    protected void testDeIndentAutoEdit(String srcPre, String srcIndent, String sourceAfter) {
        testDeIndentAutoEdit(srcPre, srcIndent, sourceAfter, true);
    }

    protected void testDeIndentAutoEdit(String srcPre, String srcIndent, String sourceAfter,
            boolean indentNotSmaller) {
        testBackSpaceDeindent(srcPre, srcIndent, sourceAfter);

        testDeleteDeindent(srcPre, srcIndent, sourceAfter);

        if (indentNotSmaller) {
            testBackSpaceCommandWithNoEffect(srcPre + srcIndent + TAB, sourceAfter);
        }

        String pureIndent = srcIndent.replaceFirst("(\r)?\n", "");
        if (pureIndent.length() == 0) {
            return; // There is no middle of indent available for further tests
        }

        // AutoEdit should not apply in the middle of indent element, test that
        String srcPre2 = srcPre + srcIndent.substring(0, srcIndent.length() - 1);
        String srcAfter2 = srcIndent.substring(srcIndent.length() - 1, srcIndent.length()) + sourceAfter;
        testBackSpaceCommandWithNoEffect(srcPre2, srcAfter2);

        int nlSize = srcIndent.length() - pureIndent.length();
        String srcPre3 = srcPre + srcIndent.substring(0, nlSize);
        String srcAfter3 = srcIndent.substring(nlSize, srcIndent.length()) + sourceAfter;
        testDeleteCommandWithNoEffect(srcPre3, srcAfter3);
    }

    protected void testDeleteDeindent(String srcPre, String srcIndent, String sourceAfter) {
        DocumentCommand delCommand = applyDelCommand(srcPre, srcIndent + sourceAfter);
        getAutoEditStrategy().customizeDocumentCommand(getDocument(), delCommand);
        checkCommand(delCommand, "", srcPre.length(), srcIndent.length());
    }

    protected void testBackSpaceDeindent(String srcPre, String srcIndent, String sourceAfter) {
        DocumentCommand bsCommand = applyBackSpaceCommand(srcPre + srcIndent, sourceAfter);
        getAutoEditStrategy().customizeDocumentCommand(getDocument(), bsCommand);
        checkCommand(bsCommand, "", srcPre.length(), srcIndent.length());
    }

    protected DocumentCommand applyBackSpaceCommand(String srcPre, String sourceAfter) {
        getDocument().set(srcPre + sourceAfter);
        int keypressOffset = srcPre.length();
        int length;
        try {
            IRegion lineInfo = getDocument().getLineInformationOfOffset(keypressOffset);
            int lineLimit = lineInfo.getOffset();
            int line = getDocument().getLineOfOffset(keypressOffset);
            length = (keypressOffset == lineLimit) ? getDocument().getLineDelimiter(line - 1).length() : 1;
        } catch (BadLocationException e) {
            throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
        }
        getAutoEditStrategy().lastKeyEvent.character = SWT.BS;
        DocumentCommand docCommand = createDocumentCommand(keypressOffset - length, length, "");
        return docCommand;
    }

    protected DocumentCommand applyDelCommand(String sourcePre, String sourceAfter) {
        getDocument().set(sourcePre + sourceAfter);
        int keypressOffset = sourcePre.length();
        int length;
        try {
            IRegion lineInfo = getDocument().getLineInformationOfOffset(keypressOffset);
            int lineEnd = lineInfo.getOffset() + lineInfo.getLength();
            int line = getDocument().getLineOfOffset(keypressOffset);
            length = (keypressOffset == lineEnd) ? getDocument().getLineDelimiter(line).length() : 1;
        } catch (BadLocationException e) {
            throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
        }
        getAutoEditStrategy().lastKeyEvent.character = SWT.DEL;
        DocumentCommand docCommand = createDocumentCommand(keypressOffset, length, "");
        return docCommand;
    }

    protected void testBackSpaceCommandWithNoEffect(String sourcePre, String sourceAfter) {
        DocumentCommand bsCommand = applyBackSpaceCommand(sourcePre, sourceAfter);
        testCommandWithNoEffect(bsCommand);
    }

    protected void testDeleteCommandWithNoEffect(String sourcePre, String sourceAfter) {
        DocumentCommand delCommand = applyDelCommand(sourcePre, sourceAfter);
        testCommandWithNoEffect(delCommand);
    }

    protected void testCommandWithNoEffect(DocumentCommand bsCommand) {
        int length = bsCommand.length;
        int offset = bsCommand.offset;
        String text = bsCommand.text;
        getAutoEditStrategy().customizeDocumentCommand(getDocument(), bsCommand);
        checkCommand(bsCommand, text, offset, length);
    }

    protected void testArtificialNoopCommand(String sourcePre, String sourceAfter) {
        String text = sourcePre + sourceAfter;
        getDocument().set(text);
        testCommandWithNoEffect(createDocumentCommand(sourcePre.length(), 0, ""));
        testCommandWithNoEffect(createDocumentCommand(sourceAfter.length(), 0, ""));
        testCommandWithNoEffect(createDocumentCommand(text.length(), 0, ""));
    }

}