package org.robotframework.ide.eclipse.main.plugin.tableeditor.source.colouring;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.Token;
import org.junit.Test;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.source.RobotDocument;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.source.colouring.ISyntaxColouringRule.PositionedTextToken;
import org.robotframework.red.jface.text.rules.IRedTokenScanner;
public class RedCachingScannerTest {
@Test
public void whenStoreIsEmpty_tokensAreScannedUsingInternalScanner_1() {
final RedTokensStore store = new RedTokensStore();
final IRedTokenScanner internalScanner = createInternalScanner(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5),
new PositionedTextToken(Token.EOF, 15, 0));
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 0, 15);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
assertThat(tokens).containsExactlyElementsOf(expected);
assertThat(store.getTokens()).containsExactlyElementsOf(expected);
}
@Test
public void whenStoreIsEmpty_tokensAreScannedUsingInternalScanner_2() {
final RedTokensStore store = new RedTokensStore();
final IRedTokenScanner internalScanner = createInternalScanner(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5),
new PositionedTextToken(Token.EOF, 15, 0));
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 1, 9);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4));
assertThat(tokens).containsExactlyElementsOf(expected);
assertThat(store.getTokens()).containsExactlyElementsOf(expected);
}
@Test
public void whenStoreHasPreviousSectionOnly_nextSectionIsScannedUsingInternalScanner() {
final RedTokensStore store = new RedTokensStore();
store.insert(0, 1, new Token("t1"));
store.insert(1, 2, new Token("t2"));
store.insert(3, 3, new Token("t3"));
store.insert(6, 0, Token.EOF);
final IRedTokenScanner internalScanner = createInternalScanner(
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5),
new PositionedTextToken(Token.EOF, 15, 0));
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 6, 9);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
assertThat(tokens).containsExactlyElementsOf(expected);
assertThat(store.getTokens()).containsExactly(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(Token.EOF, 6, 0),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
}
@Test
public void whenStoreHasTokensCached_theyAreReturnedWithoutUsingInternalScanner() {
final RedTokensStore store = new RedTokensStore();
store.insert(0, 1, new Token("t1"));
store.insert(1, 2, new Token("t2"));
store.insert(3, 3, new Token("t3"));
store.insert(6, 4, new Token("t4"));
store.insert(10, 5, new Token("t5"));
store.insert(15, 0, Token.EOF);
final IRedTokenScanner internalScanner = mock(IRedTokenScanner.class);
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 0, 15);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
assertThat(tokens).containsExactlyElementsOf(expected);
verify(internalScanner, never()).nextToken();
}
@Test
public void whenStoreHasTokensCachedAndNewSectionIsScanned_itIsReturnedFromCacheCorrectly() {
final RedTokensStore store = new RedTokensStore();
store.insert(0, 1, new Token("t1"));
store.insert(1, 2, new Token("t2"));
store.insert(3, 3, new Token("t3"));
store.insert(6, 0, Token.EOF);
store.insert(6, 4, new Token("t4"));
store.insert(10, 5, new Token("t5"));
store.insert(15, 0, Token.EOF);
final IRedTokenScanner internalScanner = mock(IRedTokenScanner.class);
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 6, 9);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
assertThat(tokens).containsExactlyElementsOf(expected);
verify(internalScanner, never()).nextToken();
}
@Test
public void whenOnlyPartOfSectionIsCached_theRestIsProperlyReturnedUsingInternalScanner() {
final RedTokensStore store = new RedTokensStore();
store.insert(0, 1, new Token("t1"));
store.insert(1, 2, new Token("t2"));
store.insert(3, 3, new Token("t3"));
final IRedTokenScanner internalScanner = createInternalScanner(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5),
new PositionedTextToken(Token.EOF, 15, 0));
final RedCachingScanner cachingScanner = new RedCachingScanner(internalScanner, store);
final List<PositionedTextToken> tokens = readTokens(cachingScanner, 0, 15);
final List<PositionedTextToken> expected = newArrayList(
new PositionedTextToken(new Token("t1"), 0, 1),
new PositionedTextToken(new Token("t2"), 1, 2),
new PositionedTextToken(new Token("t3"), 3, 3),
new PositionedTextToken(new Token("t4"), 6, 4),
new PositionedTextToken(new Token("t5"), 10, 5));
assertThat(tokens).containsExactlyElementsOf(expected);
assertThat(store.getTokens()).containsExactlyElementsOf(expected);
}
private static List<PositionedTextToken> readTokens(final ITokenScanner scanner, final int offset,
final int length) {
final List<PositionedTextToken> result = new ArrayList<>();
scanner.setRange(mock(RobotDocument.class), offset, length);
IToken token = scanner.nextToken();
while (!token.isEOF()) {
result.add(new PositionedTextToken(token, scanner.getTokenOffset(), scanner.getTokenLength()));
token = scanner.nextToken();
}
return result;
}
private static IRedTokenScanner createInternalScanner(final PositionedTextToken... tokensToReturn) {
return new IRedTokenScanner() {
private final List<PositionedTextToken> tokens = newArrayList(tokensToReturn);
private Position lastPosition;
private int current;
@Override
public void setRange(final IDocument document, final int offset, final int length) {
lastPosition = null;
current = 0;
for (final PositionedTextToken token : tokensToReturn) {
if (token.getPosition().includes(offset)) {
break;
}
current++;
}
}
@Override
public IToken nextToken() {
final PositionedTextToken token = tokens.get(current++);
this.lastPosition = token.getPosition();
return token.getToken();
}
@Override
public int getTokenOffset() {
return lastPosition.getOffset();
}
@Override
public int getTokenLength() {
return lastPosition.getLength();
}
@Override
public void resetPosition() {
lastPosition = null;
}
};
}
}