/* * Copyright 2000-2010 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.intellij.formatting; import com.intellij.openapi.editor.impl.BulkChangesMerger; import com.intellij.openapi.editor.impl.TextChangeImpl; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestWatcher; import org.junit.runner.Description; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; import static org.junit.Assert.assertEquals; /** * @author Denis Zhdanov * @since 12/22/2010 */ public class BulkChangesMergerTest { @Rule public TestWatcher configReader = new TestWatcher() { @Override protected void starting(Description description) { Config config = description.getAnnotation(Config.class); if (config != null) { myConfig = config; } else { try { myConfig = BulkChangesMergerTest.class.getMethod("dummy").getAnnotation(Config.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } } }; @Config public static void dummy() { } private Config myConfig; private BulkChangesMerger myMerger; @Before public void setUp() { myMerger = new BulkChangesMerger(); } @Test public void simpleReplaceInTheMiddle() { doTest("abcd", "a123d", c("123", 1, 3)); } @Test public void disjointInserts() { doTest("abcd", "a1b2c3d45", c("1", 1), c("2", 2), c("3", 3), c("45", 4)); } @Config(initialTextLength = 4) @Test public void interestedSymbolsNumberLessThanAvailable() { doTest("abcdefg", "a12bc3d", c("12", 1), c("3", 3)); } @Config(inplace = true) @Test public void inplaceZeroGroups() { doTest("0123456789", "a2bc4defg8", c("a", 0, 2), c("bc", 3, 4), c("defg", 5, 8), c("", 9, 10)); } @Config(inplace = true) @Test public void inplaceGrowingGroupsWithLastPositive() { doTest("abcdefghijklmnopqrst", "acABdCjkDEFGHIJKLMpqrst", c("", 1, 2), c("AB", 3), c("C", 4, 9), c("DEFGHIJKLM", 11, 15)); } @Config(inplace = true) @Test public void inplaceGrowingGroupsWithLastNegative() { doTest("abcdefghijk", "acABdCjk", c("", 1, 2), c("AB", 3), c("C", 4, 9)); } @Config(inplace = true) @Test public void onlyGrowing() { doTest("0123456789", "0ab2c3defg67hijk9", c("ab", 1, 2), c("c", 3), c("defg", 4, 6), c("hijk", 8, 9)); } @Config(inplace = true) @Test public void onlyShrinking() { doTest("0123456789", "0a35b9", c("a", 1, 3), c("", 4, 5), c("b", 6, 9)); } @Config(inplace = true, dataArrayLength = 4) @Test(expected = IllegalArgumentException.class) public void insufficientLengthForInplaceMerge() { doTest("0123", "", c("", 1, 3), c("abc", 4)); } @Config(inplace = true) @Test public void overlapWithPositiveGroupOnStart() { doTest("0123456789ABC", "0abc1358d9eBC", c("abc", 1), c("", 2, 3), c("", 4, 5), c("", 6, 8), c("d", 9), c("e", 10, 11)); } @Test public void updateOffset() { doTestUpdateOffset(5, 5, c("a", 6)); doTestUpdateOffset(5, 6, c("a", 3)); doTestUpdateOffset(5, 5, c("a", 6, 7)); doTestUpdateOffset(5, 5, c("a", 3, 4)); doTestUpdateOffset(5, 4, c("", 3, 4)); doTestUpdateOffset(5, 5, c("", 6, 7)); doTestUpdateOffset(5, 2, c("", 0, 1), c("", 2, 3), c("", 3, 4)); } //@Config(inplace = true) //@Test //public void client() { // int arrayLength = 31486; // int dataLength = 9552; // char[] initial = new char[arrayLength]; // List<int[]> rawChanges = new ArrayList<int[]>(); // rawChanges.add(new int[] {6609, 8209, 14634}); // // List<TextChangeImpl> changes = new ArrayList<TextChangeImpl>(); // for (int[] rawChange : rawChanges) { // changes.add(new TextChangeImpl(StringUtil.repeatSymbol('a', rawChange[0]), rawChange[1], rawChange[2])); // } // myMerger.mergeInPlace(initial, dataLength, changes); //} private static TextChangeImpl c(String text, int offset) { return c(text, offset, offset); } private static TextChangeImpl c(String text, int start, int end) { return new TextChangeImpl(text, start, end); } private void doTest(String initial, String expected, TextChangeImpl ... changes) { if (myConfig.inplace()) { int diff = 0; for (TextChangeImpl change : changes) { diff += change.getDiff(); } int outputUsefulLength = initial.length() + diff; int dataLength = myConfig.dataArrayLength(); if (dataLength < 0) { dataLength = Math.max(outputUsefulLength, initial.length()); } char[] data = new char[dataLength]; System.arraycopy(initial.toCharArray(), 0, data, 0, initial.length()); myMerger.mergeInPlace(data, initial.length(), Arrays.asList(changes)); assertEquals(expected, new String(data, 0, outputUsefulLength)); } else { int interestedSymbolsNumber = myConfig.initialTextLength(); if (interestedSymbolsNumber < 0) { interestedSymbolsNumber = initial.length(); } CharSequence actual = myMerger.mergeToCharSequence(initial.toCharArray(), interestedSymbolsNumber, Arrays.asList(changes)); assertEquals(expected, actual.toString()); } } private void doTestUpdateOffset(int initialOffset, int expectedOffset, TextChangeImpl... changes) { assertEquals(expectedOffset, myMerger.updateOffset(initialOffset, Arrays.asList(changes))); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) private @interface Config { boolean inplace() default false; int dataArrayLength() default -1; int initialTextLength() default -1; } }