blob: 389df60f996d2605c3c1d8d4a52a2c3ade290c22 [file] [log] [blame]
/*
* Copyright 2000-2011 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.openapi.editor.impl;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import static java.util.Arrays.asList;
import static org.junit.Assert.*;
/**
* @author Denis Zhdanov
* @since 03/02/2011
*/
public class TextChangesStorageTest {
private TextChangesStorage myStorage;
@Before
public void setUp() {
myStorage = new TextChangesStorage();
}
@Test
public void clear() {
assertTrue(myStorage.isEmpty());
insert("abc", 2);
assertFalse(myStorage.isEmpty());
assertEquals(1, myStorage.getChanges().size());
myStorage.clear();
assertTrue(myStorage.isEmpty());
assertTrue(myStorage.getChanges().isEmpty());
}
@Test
public void singleInsert() {
insert("abc", 2);
checkChanges(c("abc", 2));
}
@Test
public void singleLongInsert() {
String text = "this is a relatively long text";
insert(text, 2);
checkChanges(c(text, 2));
}
@Test
public void disconnectedInserts() {
insert("abc", 2);
insert("def", 6);
insert("ghi", 11);
checkChanges(c("abc", 2), c("def", 3), c("ghi", 5));
}
@Test
public void disconnectedInsertsFromTailToStart() {
insert("abc", 10);
insert("def", 1);
checkChanges(c("def", 1), c("abc", 10));
}
@Test
public void adjacentInserts() {
insert("abc", 2);
insert("def", 5);
insert("ghi", 8);
checkChanges(c("abcdefghi", 2));
}
@Test
public void nestedInserts() {
insert("abc", 2);
insert("XY", 3);
insert("1234", 4);
checkChanges(c("aX1234Ybc", 2));
}
@Test
public void singleDelete() {
delete(2, 3);
checkChanges(c("", 2, 3));
}
@Test
public void disconnectedDeletes() {
delete(2, 3);
delete(3, 4);
delete(5, 6);
checkChanges(c("", 2, 3), c("", 4, 5), c("", 7, 8));
}
@Test
public void adjacentDeletes() {
delete(2, 3);
delete(2, 3);
delete(2, 3);
checkChanges(c("", 2, 5));
}
@Test
public void adjacentDeletesFromEndToStart() {
delete(5, 6);
delete(4, 5);
checkChanges(c("", 4, 6));
}
@Test
public void singleReplace() {
replace("abc", 3, 4);
checkChanges(c("abc", 3, 4));
}
@Test
public void disconnectedReplaces() {
replace("abc", 3, 4);
replace("de", 7, 8);
replace("fghi", 10, 11);
checkChanges(c("abc", 3, 4), c("de", 5, 6), c("fghi", 7, 8));
}
@Test
public void disconnectedUnorderedReplaces() {
replace("abc", 1, 4);
replace("def", 10, 13);
replace("ghi", 6, 9);
checkChanges(c("abc", 1, 4), c("ghi", 6, 9), c("def", 10, 13));
}
@Test
public void adjacentReplaces() {
replace("abc", 3, 4);
replace("de", 6, 9);
replace("fghi", 8, 9);
checkChanges(c("abcdefghi", 3, 8));
}
@Test
public void intersectedReplaces() {
replace("abc", 3, 4);
replace("defg", 5, 6);
replace("hi", 8, 11);
checkChanges(c("abdefhi", 3, 6));
}
@Test
public void intersectedReplacesFromEndToStart() {
replace("abcd", 5, 6);
replace("ef", 4, 7);
replace("g", 1, 5);
checkChanges(c("gfcd", 1, 6));
}
@Test
public void nestedReplaces() {
replace("abcdef", 3, 5);
replace("gh", 4, 7);
replace("i", 5, 6);
checkChanges(c("agief", 3, 5));
}
@Test
public void exactMultipleReplace() {
replace("abc", 3, 4);
replace("cde", 3, 6);
replace("fg", 3, 6);
checkChanges(c("fg", 3, 4));
}
@Test
public void insertAndExactDelete() {
insert("abc", 3);
delete(3, 6);
checkChanges();
}
@Test
public void insertAndDeleteInTheMiddle() {
insert("abc", 3);
delete(4, 6);
checkChanges(c("a", 3));
}
@Test
public void insertAndWiderDelete() {
insert("abc", 3);
delete(2, 7);
checkChanges(c("", 2, 4));
}
@Test
public void insertAndDeleteFromLeft() {
insert("abc", 3);
delete(2, 5);
checkChanges(c("c", 2, 3));
}
@Test
public void insertAndDeleteFromRight() {
insert("abc", 3);
delete(4, 7);
checkChanges(c("a", 3, 4));
}
@Test
public void disconnectedInsertsAndExactLinkingDelete() {
insert("a", 1);
insert("bcd", 3);
insert("efg", 8);
delete(3, 11);
checkChanges(c("a", 1), c("", 2, 4));
}
@Test
public void disconnectedInsertsAndWiderLinkingDelete() {
insert("abc", 3);
insert("def", 8);
delete(2, 13);
checkChanges(c("", 2, 7));
}
@Test
public void disconnectedInsertsAndNarrowLinkingDelete() {
insert("abc", 3);
insert("def", 8);
delete(4, 9);
checkChanges(c("aef", 3, 5));
}
@Test
public void replaceAndDeleteWholeTextFromItsStart() {
delete(72, 79);
insert("a", 72);
delete(72, 73);
delete(64, 71);
delete(51, 62);
insert("a", 54);
insert("a", 53);
insert("a", 51);
delete(56, 57);
insert("b", 56);
checkChanges(c("a", 51, 62), c("a", 64, 71), c("b", 72, 79));
}
@Test
public void exactRemoveOfPreviousInsert() {
insert("a", 1);
insert("bcd", 3);
insert("efg", 7);
delete(3, 6);
checkChanges(c("a", 1), c("efg", 3));
}
@Test
public void removeAdjacentToInsert() {
insert("a", 1);
insert("bc", 3);
delete(2, 3);
checkChanges(c("abc", 1, 2));
}
private void checkChanges(TextChangeImpl ... changes) {
assertEquals(asList(changes), myStorage.getChanges());
assertEquals(changes.length > 0, !myStorage.isEmpty());
if (changes.length <= 0) {
return;
}
int length = changes[changes.length - 1].getEnd() + 2;
char[] input = new char[length];
char c = 'A';
for (int i = 0; i < input.length; i++) {
input[i] = c++;
}
char[] output = BulkChangesMerger.INSTANCE.mergeToCharArray(input, input.length, asList(changes));
// charAt().
for (int i = 0; i < output.length; i++) {
if (output[i] != myStorage.charAt(input, i)) {
fail(String.format(
"Detected incorrect charAt() processing. Original text: '%s', changes: %s, index: %d, expected: %c, actual: %c",
new String(input), Arrays.asList(changes), i, output[i], myStorage.charAt(input, i)
));
}
}
// substring().
for (int start = 0; start < output.length; start++) {
for( int end = start; end < output.length; end++) {
String expected = new String(output, start, end - start);
String actual = myStorage.substring(input, start, end).toString();
if (!expected.equals(actual)) {
fail(String.format(
"Detected incorrect substring() processing. Original text: '%s', changes: %s, client text: '%s', range: %d-%d, "
+ "expected: '%s', actual: '%s'", new String(input), Arrays.asList(changes), new String(output), start, end, expected, actual
));
}
}
}
}
private static TextChangeImpl c(@NotNull String text, int startOffset) {
return c(text, startOffset, startOffset);
}
private static TextChangeImpl c(@NotNull String text, int startOffset, int endOffset) {
return new TextChangeImpl(text, startOffset, endOffset);
}
private void insert(@NotNull String text, int offset) {
myStorage.store(c(text, offset));
}
private void delete(int start, int end) {
myStorage.store(c("", start, end));
}
private void replace(@NotNull String text, int start, int end) {
myStorage.store(c(text, start, end));
}
}