/*
* Copyright 2016 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.ide.eclipse.main.plugin.tableeditor.source;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Map;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import org.robotframework.ide.eclipse.main.plugin.RedPreferences;
import org.robotframework.ide.eclipse.main.plugin.RedPreferences.FoldableElements;
import org.robotframework.ide.eclipse.main.plugin.mockdocument.Document;
import org.robotframework.ide.eclipse.main.plugin.mockmodel.RobotSuiteFileCreator;
import org.robotframework.red.junit.ShellProvider;
import org.robotframework.red.swt.StyledTextWrapper;
public class SuiteSourceEditorFoldingSupportTest {
@Rule
public ShellProvider shellProvider = new ShellProvider();
@Test
public void sectionsPositionsAreProperlyCalculated() {
final RedPreferences preferences = mock(RedPreferences.class);
when(preferences.getFoldingLineLimit()).thenReturn(1);
when(preferences.getFoldableElements()).thenReturn(EnumSet.of(FoldableElements.SECTIONS));
final RobotSuiteFileCreator builder = createFileBuilder();
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(preferences, null, null);
final Collection<Position> foldingPositions = support.calculateFoldingPositions(builder.build(),
new Document(builder.getContent()));
assertThat(foldingPositions).containsOnly(new Position(0, 17), new Position(17, 18), new Position(35, 19),
new Position(54, 17), new Position(71, 30), new Position(101, 28), new Position(129, 111),
new Position(240, 103), new Position(343, 76), new Position(419, 44));
}
@Test
public void testCasesPositionsAreProperlyCalculated() {
final RedPreferences preferences = mock(RedPreferences.class);
when(preferences.getFoldingLineLimit()).thenReturn(1);
when(preferences.getFoldableElements()).thenReturn(EnumSet.of(FoldableElements.CASES));
final RobotSuiteFileCreator builder = createFileBuilder();
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(preferences, null, null);
final Collection<Position> foldingPositions = support.calculateFoldingPositions(builder.build(),
new Document(builder.getContent()));
assertThat(foldingPositions).containsOnly(new Position(148, 7), new Position(155, 32), new Position(187, 53));
}
@Test
public void keywordsPositionsAreProperlyCalculated() {
final RedPreferences preferences = mock(RedPreferences.class);
when(preferences.getFoldingLineLimit()).thenReturn(1);
when(preferences.getFoldableElements()).thenReturn(EnumSet.of(FoldableElements.KEYWORDS));
final RobotSuiteFileCreator builder = createFileBuilder();
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(preferences, null, null);
final Collection<Position> foldingPositions = support.calculateFoldingPositions(builder.build(),
new Document(builder.getContent()));
assertThat(foldingPositions).containsOnly(new Position(257, 5), new Position(262, 30), new Position(292, 51));
}
@Test
public void documentationPositionsAreProperlyCalculated() {
final RedPreferences preferences = mock(RedPreferences.class);
when(preferences.getFoldingLineLimit()).thenReturn(1);
when(preferences.getFoldableElements()).thenReturn(EnumSet.of(FoldableElements.DOCUMENTATION));
final RobotSuiteFileCreator builder = createFileBuilder();
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(preferences, null, null);
final Collection<Position> foldingPositions = support.calculateFoldingPositions(builder.build(),
new Document(builder.getContent()));
assertThat(foldingPositions).containsOnly(new Position(164, 23), new Position(196, 44), new Position(269, 23),
new Position(299, 44), new Position(360, 36));
}
@Test
public void positionsAreProperlyCalculatedWithChangedLineSpan() {
final RedPreferences preferences = mock(RedPreferences.class);
when(preferences.getFoldingLineLimit()).thenReturn(3);
when(preferences.getFoldableElements()).thenReturn(EnumSet.allOf(FoldableElements.class));
final RobotSuiteFileCreator builder = createFileBuilder();
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(preferences, null, null);
final Collection<Position> foldingPositions = support.calculateFoldingPositions(builder.build(),
new Document(builder.getContent()));
assertThat(foldingPositions).containsOnly(new Position(129, 111), new Position(240, 103), new Position(343, 76),
new Position(419, 44), new Position(187, 53), new Position(292, 51));
}
@Test
public void allAnnotationsAreAddedInitially() {
final StyledTextWrapper textControl = new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(2), arrayOfSize(0));
verifyNoMoreInteractions(annotationsModel);
}
@Test
public void whenNoFoldingPositionAppearsOrDissappears_theAnnotationsAreSendAsChanged() {
final StyledTextWrapper textControl = new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(2), arrayOfSize(0));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(0), arrayOfSize(2));
verifyNoMoreInteractions(annotationsModel);
}
@Test
public void whenNewFoldingPositionAppears_itIsSendAsAddedWhileOtherAreChanged() {
final StyledTextWrapper textControl = new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10), new Position(30, 10)));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(2), arrayOfSize(0));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(1), arrayOfSize(2));
verifyNoMoreInteractions(annotationsModel);
}
@Test
public void whenFoldingPositionDissappears_itIsSendAsRemovedWhileOtherAreChanged() {
final StyledTextWrapper textControl = new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
support.updateFoldingStructure(newArrayList(new Position(0, 10)));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(2), arrayOfSize(0));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(1),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(0), arrayOfSize(1));
verifyNoMoreInteractions(annotationsModel);
}
@Test
public void whenFoldingPositionIsChanged_ItIsRemovedAndNewIsAdded() {
final StyledTextWrapper textControl = new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
// this simulates situation in which the position is being modified by some source change listeners
// deep in eclipse. In such situation the Position objects gets modified; but we're using them
// as keys in map thus resulting in objects lying in wrong map bucket after modification is done
final Position positionToModify = new Position(20, 10);
support.updateFoldingStructure(newArrayList(new Position(0, 10), positionToModify));
positionToModify.setLength(15);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 15)));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(0),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(2), arrayOfSize(0));
verify(annotationsModel, times(1)).modifyAnnotations(arrayOfSize(1),
SuiteSourceEditorFoldingSupportTest.<Annotation, Position> mapOfSize(1), arrayOfSize(1));
verifyNoMoreInteractions(annotationsModel);
}
@Test
public void textViewerRevealsSelection_whenAnnotationModelIsUpdated() {
final StyledTextWrapper textControl = spy(
new StyledTextWrapper(new StyledText(shellProvider.getShell(), SWT.NONE)));
final ProjectionAnnotationModel annotationsModel = mock(ProjectionAnnotationModel.class);
final SuiteSourceEditorFoldingSupport support = new SuiteSourceEditorFoldingSupport(textControl,
annotationsModel);
support.updateFoldingStructure(newArrayList(new Position(0, 10), new Position(20, 10)));
verify(textControl, times(1)).showSelection();
}
private static RobotSuiteFileCreator createFileBuilder() {
return new RobotSuiteFileCreator().appendLine("*** Settings ***")
.appendLine("*** Variables ***")
.appendLine("*** Test Cases ***")
.appendLine("*** Keywords ***")
.appendLine("*** Settings ***")
.appendLine("Library lib")
.appendLine("*** Variables ***")
.appendLine("${var} 1")
.appendLine("*** Test Cases ***")
.appendLine("case 1")
.appendLine("case 2")
.appendLine(" [Documentation] doc 1")
.appendLine("case 3")
.appendLine(" [Documentation] doc 1")
.appendLine(" ... doc 2 doc 3")
.appendLine("*** Keywords ***")
.appendLine("kw 1")
.appendLine("kw 2")
.appendLine(" [Documentation] doc 1")
.appendLine("kw 3")
.appendLine(" [Documentation] doc 1")
.appendLine(" ... doc 2 doc 3")
.appendLine("*** Settings ***")
.appendLine("Documentation doc1")
.appendLine("... doc2 doc3")
.appendLine("Metadata data1 data2")
.appendLine("*** Variables ***")
.appendLine("${var} 1")
.appendLine("@{list} a b c");
}
private static <T1, T2> Map<T1, T2> mapOfSize(final int expectedSize) {
return argThat(new MapOfSizeMatcher<Map<T1, T2>>(expectedSize));
}
private static Annotation[] arrayOfSize(final int expectedSize) {
return argThat(new ArrayOfSizeMatcher<Annotation[]>(expectedSize));
}
private static class ArrayOfSizeMatcher<T> implements ArgumentMatcher<T> {
private final int expectedSize;
public ArrayOfSizeMatcher(final int expectedSize) {
this.expectedSize = expectedSize;
}
@Override
public boolean matches(final T item) {
return item != null && item.getClass().isArray() && ((Object[]) item).length == expectedSize;
}
}
private static class MapOfSizeMatcher<T> implements ArgumentMatcher<T> {
private final int expectedSize;
public MapOfSizeMatcher(final int expectedSize) {
this.expectedSize = expectedSize;
}
@Override
public boolean matches(final T item) {
return item instanceof Map<?, ?> && ((Map<?, ?>) item).size() == expectedSize;
}
}
}