--- /dev/null
+we're going to delete this placeholder
\ No newline at end of file
--- /dev/null
+we're going to delete <placeholder>thi<caret>s</placeholder> placeholder
\ No newline at end of file
--- /dev/null
+<placeholder taskText="type here" hint="Test hint">here</placeholder> will be added one placeholder
\ No newline at end of file
--- /dev/null
+<selection>here</selection> will be added one placeholder
\ No newline at end of file
--- /dev/null
+type <placeholder>h<selection>ere</selection></placeholder>
\ No newline at end of file
--- /dev/null
+def f():
+ pass
+ <placeholder taskText="type here" hint="Test hint">type here</placeholder>
\ No newline at end of file
--- /dev/null
+def f():
+ pass
+ <caret>
\ No newline at end of file
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.markup.MarkupModel;
+import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.EditorTestUtil;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.courseFormat.*;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.ComparisonFailure;
import java.io.File;
import java.io.IOException;
public abstract class CCTestCase extends LightPlatformCodeInsightFixtureTestCase {
private static final Logger LOG = Logger.getInstance(CCTestCase.class);
+ @Nullable
+ public static RangeHighlighter getHighlighter(MarkupModel model, AnswerPlaceholder placeholder) {
+ for (RangeHighlighter highlighter : model.getAllHighlighters()) {
+ int endOffset = placeholder.getOffset() + placeholder.getRealLength();
+ if (highlighter.getStartOffset() == placeholder.getOffset() && highlighter.getEndOffset() == endOffset) {
+ return highlighter;
+ }
+ }
+ return null;
+ }
+
+ protected static void checkHighlighters(TaskFile taskFile, MarkupModel markupModel) {
+ for (AnswerPlaceholder answerPlaceholder : taskFile.getAnswerPlaceholders()) {
+ if (getHighlighter(markupModel, answerPlaceholder) == null) {
+ throw new AssertionError("No highlighter for placeholder: " + CCTestsUtil.getPlaceholderPresentation(answerPlaceholder));
+ }
+ }
+ }
+
+ public void checkByFile(TaskFile taskFile, String fileName, boolean useLength) {
+ Pair<Document, List<AnswerPlaceholder>> placeholders = getPlaceholders(fileName, useLength, true);
+ String message = "Placeholders don't match";
+ if (taskFile.getAnswerPlaceholders().size() != placeholders.second.size()) {
+ throw new ComparisonFailure(message,
+ CCTestsUtil.getPlaceholdersPresentation(taskFile.getAnswerPlaceholders()),
+ CCTestsUtil.getPlaceholdersPresentation(placeholders.second));
+ }
+ for (AnswerPlaceholder answerPlaceholder : placeholders.getSecond()) {
+ AnswerPlaceholder placeholder = taskFile.getAnswerPlaceholder(answerPlaceholder.getOffset());
+ if (!CCTestsUtil.comparePlaceholders(placeholder, answerPlaceholder)) {
+ throw new ComparisonFailure(message,
+ CCTestsUtil.getPlaceholdersPresentation(taskFile.getAnswerPlaceholders()),
+ CCTestsUtil.getPlaceholdersPresentation(placeholders.second));
+ }
+ }
+ }
+
@Override
protected String getTestDataPath() {
//TODO: rewrite to work for plugin
}
}
});
-
}
protected VirtualFile configureByTaskFile(String name) {
new WriteCommandAction(null) {
@Override
protected void run(@NotNull Result result) {
- final String openingTagRx = "<placeholder( taskText=\"(.+?)\")?( possibleAnswer=\"(.+?)\")?>";
+ final String openingTagRx = "<placeholder( taskText=\"(.+?)\")?( possibleAnswer=\"(.+?)\")?( hint=\"(.+?)\")?>";
final String closingTagRx = "</placeholder>";
CharSequence text = document.getCharsSequence();
final Matcher openingMatcher = Pattern.compile(openingTagRx).matcher(text);
if (possibleAnswer != null) {
answerPlaceholder.setPossibleAnswer(possibleAnswer);
}
+ String hint = openingMatcher.group(6);
+ if (hint != null) {
+ answerPlaceholder.setHint(hint);
+ }
answerPlaceholder.setOffset(openingMatcher.start());
if (!closingMatcher.find(openingMatcher.end())) {
LOG.error("No matching closing tag found");
}
public Pair<Document, List<AnswerPlaceholder>> getPlaceholders(String name) {
+ return getPlaceholders(name, true, false);
+ }
+
+ public Pair<Document, List<AnswerPlaceholder>> getPlaceholders(String name, boolean useLength, boolean removeMarkers) {
VirtualFile resultFile = LocalFileSystem.getInstance().findFileByPath(getTestDataPath() + "/" + name);
Document document = FileDocumentManager.getInstance().getDocument(resultFile);
Document tempDocument = EditorFactory.getInstance().createDocument(document.getCharsSequence());
- List<AnswerPlaceholder> placeholders = getPlaceholders(tempDocument, true);
+ if (removeMarkers) {
+ EditorTestUtil.extractCaretAndSelectionMarkers(tempDocument);
+ }
+ List<AnswerPlaceholder> placeholders = getPlaceholders(tempDocument, useLength);
return Pair.create(tempDocument, placeholders);
}
+
+ @Override
+ protected boolean shouldContainTempFiles() {
+ return false;
+ }
}
package com.jetbrains.edu.coursecreator;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+
+import java.util.Collection;
+import java.util.List;
+
public class CCTestsUtil {
+ public static final String BEFORE_POSTFIX = "_before.txt";
+ public static final String AFTER_POSTFIX = "_after.txt";
+
private CCTestsUtil() {
}
+ public static boolean comparePlaceholders(AnswerPlaceholder p1, AnswerPlaceholder p2) {
+ if (p1.getOffset() != p2.getOffset()) return false;
+ if (p1.getRealLength() != p2.getRealLength()) return false;
+ if (p1.getPossibleAnswer() != null ? !p1.getPossibleAnswer().equals(p2.getPossibleAnswer()) : p2.getPossibleAnswer() != null) return false;
+ if (p1.getTaskText() != null ? !p1.getTaskText().equals(p2.getTaskText()) : p2.getTaskText() != null) return false;
+ if (!p1.getHints().equals(p1.getHints())) return false;
+ return true;
+ }
+ public static String getPlaceholderPresentation(AnswerPlaceholder placeholder) {
+ return "offset=" + placeholder.getOffset() +
+ " length=" + placeholder.getLength() +
+ " possibleAnswer=" + placeholder.getPossibleAnswer() +
+ " taskText=" + placeholder.getTaskText();
+ }
+
+ public static String getPlaceholdersPresentation(List<AnswerPlaceholder> placeholders) {
+ Collection<String> transformed = Collections2.transform(placeholders, new Function<AnswerPlaceholder, String>() {
+ @Override
+ public String apply(AnswerPlaceholder placeholder) {
+ return getPlaceholderPresentation(placeholder);
+ }
+ });
+ return "[" + StringUtil.join(transformed, ",") + "]";
+ }
}
--- /dev/null
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.command.undo.UndoManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.coursecreator.CCTestCase;
+import com.jetbrains.edu.coursecreator.CCTestsUtil;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import com.jetbrains.edu.learning.ui.CCCreateAnswerPlaceholderDialog;
+
+import java.util.Collections;
+import java.util.List;
+
+public class CCAnswerPlaceholderActionTest extends CCTestCase {
+ static class CCTestAction extends CCAddAnswerPlaceholder {
+ @Override
+ protected CCCreateAnswerPlaceholderDialog createDialog(Project project, AnswerPlaceholder answerPlaceholder) {
+ return new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder.getTaskText(), answerPlaceholder.getHints()) {
+ @Override
+ public boolean showAndGet() {
+ return true;
+ }
+
+ @Override
+ public String getTaskText() {
+ return "type here";
+ }
+
+ @Override
+ public List<String> getHints() {
+ return Collections.singletonList("Test hint");
+ }
+ };
+ }
+ }
+
+ public void testPlaceholderWithSelection() {
+ doTest("onePlaceholder");
+ }
+
+ public void testPlaceholderWithoutSelection() {
+ doTest("withoutSelection");
+ }
+
+ public void testPlaceholderIntersection() {
+ configureByTaskFile("placeholderIntersection.txt");
+ Presentation presentation = myFixture.testAction(new CCTestAction());
+ assertTrue(presentation.isVisible() && !presentation.isEnabled());
+ }
+
+ public void testPlaceholderDeleted() {
+ doTest("deletePlaceholder");
+ }
+
+ private void doTest(String name) {
+ VirtualFile virtualFile = configureByTaskFile(name + CCTestsUtil.BEFORE_POSTFIX);
+ myFixture.testAction(new CCTestAction());
+ TaskFile taskFile = StudyUtils.getTaskFile(getProject(), virtualFile);
+ checkByFile(taskFile, name + CCTestsUtil.AFTER_POSTFIX, false);
+ checkHighlighters(taskFile, myFixture.getEditor().getMarkupModel());
+ UndoManager.getInstance(getProject()).undo(FileEditorManager.getInstance(getProject()).getSelectedEditor(virtualFile));
+ checkByFile(taskFile, name + CCTestsUtil.BEFORE_POSTFIX, false);
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return super.getTestDataPath() + "/actions/addPlaceholder";
+ }
+}
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
-import com.intellij.openapi.editor.markup.MarkupModel;
-import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.MapDataContext;
import com.intellij.testFramework.TestActionEvent;
import com.jetbrains.edu.coursecreator.CCTestCase;
+import com.jetbrains.edu.coursecreator.CCTestsUtil;
import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder;
-import org.jetbrains.annotations.Nullable;
import java.util.List;
}
public void testOnePlaceholder() {
- doTest("test_before.txt", "test_after.txt");
+ doTest("test");
}
public void testSeveralPlaceholders() {
- doTest("several_before.txt", "several_after.txt");
+ doTest("several");
}
- private void doTest(String beforeName, String afterName) {
- VirtualFile file = configureByTaskFile(beforeName);
+ private void doTest(String name) {
+ VirtualFile file = configureByTaskFile(name + CCTestsUtil.BEFORE_POSTFIX);
CCShowPreview action = new CCShowPreview();
TestActionEvent e = getActionEvent(action, getPsiManager().findFile(file));
action.beforeActionPerformedUpdate(e);
assertTrue(e.getPresentation().isEnabled() && e.getPresentation().isVisible());
action.actionPerformed(e);
Editor editor = EditorFactory.getInstance().getAllEditors()[1];
- Pair<Document, List<AnswerPlaceholder>> pair = getPlaceholders(afterName);
+ Pair<Document, List<AnswerPlaceholder>> pair = getPlaceholders(name + CCTestsUtil.AFTER_POSTFIX);
assertEquals("Files don't match", editor.getDocument().getText(), pair.getFirst().getText());
for (AnswerPlaceholder placeholder : pair.getSecond()) {
- assertNotNull("No highlighter for placeholder", getHighlighter(editor.getMarkupModel(), placeholder));
+ assertNotNull("No highlighter for placeholder:" + CCTestsUtil.getPlaceholderPresentation(placeholder), getHighlighter(editor.getMarkupModel(), placeholder));
}
EditorFactory.getInstance().releaseEditor(editor);
}
- @Nullable
- private static RangeHighlighter getHighlighter(MarkupModel model, AnswerPlaceholder placeholder) {
- for (RangeHighlighter highlighter : model.getAllHighlighters()) {
- int endOffset = placeholder.getOffset() + placeholder.getRealLength();
- if (highlighter.getStartOffset() == placeholder.getOffset() && highlighter.getEndOffset() == endOffset) {
- return highlighter;
- }
- }
- return null;
- }
-
@Override
protected String getTestDataPath() {
return super.getTestDataPath() + "/actions/preview";
}
- @Override
- protected boolean shouldContainTempFiles() {
- return false;
- }
-
TestActionEvent getActionEvent(AnAction action, PsiFile psiFile) {
MapDataContext context = new MapDataContext();
context.put(CommonDataKeys.PSI_FILE, psiFile);