<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/../../educational/course-creator/src/com/jetbrains/edu/coursecreator/format" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="student" />
<orderEntry type="library" name="Guava" level="project" />
+ <orderEntry type="module" module-name="testFramework" scope="TEST" />
</component>
</module>
\ No newline at end of file
@Override
public void fileCreated(@NotNull VirtualFileEvent event) {
VirtualFile createdFile = event.getFile();
+ if (createdFile.isDirectory()) {
+ return;
+ }
+ if (createdFile.getPath().contains(CCUtils.GENERATED_FILES_FOLDER)) {
+ return;
+ }
Project project = ProjectUtil.guessProjectForFile(createdFile);
if (project == null) {
return;
}
+ if (project.getBasePath() !=null && !FileUtil.isAncestor(project.getBasePath(), createdFile.getPath(), true)) {
+ return;
+ }
Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null || !CCUtils.isCourseCreator(project)) {
return;
if (project == null) {
return;
}
+ if (project.getBasePath() !=null && !FileUtil.isAncestor(project.getBasePath(), removedFile.getPath(), true)) {
+ return;
+ }
Course course = StudyTaskManager.getInstance(project).getCourse();
if (course == null || path.contains(FileUtil.toSystemIndependentName(course.getCourseDirectory()))) {
return;
if (task == null) {
return;
}
- //TODO: remove from steps as well
task.getTaskFiles().remove(removedTaskFile.getName());
}
}
public class CCShowPreview extends DumbAwareAction {
public static final String SHOW_PREVIEW = "Show Preview";
+ public static final String NO_PREVIEW_MESSAGE = "Preview is available for task files with answer placeholders only";
public CCShowPreview() {
super(SHOW_PREVIEW, SHOW_PREVIEW, null);
createdEditor.setCaretEnabled(false);
showPreviewFrame.setComponent(labeledEditor);
showPreviewFrame.setSize(new Dimension(500, 500));
- showPreviewFrame.show();
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ showPreviewFrame.show();
+ }
}
}
\ No newline at end of file
--- /dev/null
+no placeholders
\ No newline at end of file
--- /dev/null
+print("<placeholder>veryverylongtextveryverylongtextveryverylongtextveryverylongtext</placeholder> + <placeholder>test</placeholder> = 2")
\ No newline at end of file
--- /dev/null
+print("<placeholder taskText="veryverylongtextveryverylongtextveryverylongtextveryverylongtext">1</placeholder> + <placeholder taskText="test">1</placeholder> = 2")
\ No newline at end of file
--- /dev/null
+<placeholder>type here</placeholder>
\ No newline at end of file
--- /dev/null
+<placeholder taskText="type here">two</placeholder>
\ No newline at end of file
--- /dev/null
+package com.jetbrains.edu.coursecreator;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+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.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.courseFormat.*;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class CCTestCase extends LightPlatformCodeInsightFixtureTestCase {
+ private static final Logger LOG = Logger.getInstance(CCTestCase.class);
+
+ @Override
+ protected String getTestDataPath() {
+ //TODO: rewrite to work for plugin
+ return new File(PathManager.getHomePath(), "community/python/educational-core/course-creator/testData").getPath();
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ Course course = new Course();
+ course.setName("test course");
+ StudyTaskManager.getInstance(getProject()).setCourse(course);
+
+ Lesson lesson = new Lesson();
+ lesson.setName("lesson1");
+ Task task = new Task();
+ task.setName("task1");
+ task.setIndex(1);
+ lesson.addTask(task);
+ lesson.setIndex(1);
+ course.getLessons().add(lesson);
+ course.setCourseMode(CCUtils.COURSE_MODE);
+ course.initCourse(false);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ VirtualFile lesson1 = myFixture.getProject().getBaseDir().createChildDirectory(this, "lesson1");
+ lesson1.createChildDirectory(this, "task1");
+ }
+ catch (IOException e) {
+ //ignore
+ }
+ }
+ });
+
+ }
+
+ protected VirtualFile configureByTaskFile(String name) {
+ VirtualFile file =
+ myFixture.copyFileToProject(name, FileUtil.join(getProject().getBasePath(), "lesson1", "task1", name));
+ myFixture.configureFromExistingVirtualFile(file);
+
+ Document document = FileDocumentManager.getInstance().getDocument(file);
+ Task task = StudyTaskManager.getInstance(getProject()).getCourse().getLessons().get(0).getTaskList().get(0);
+ TaskFile taskFile = new TaskFile();
+ taskFile.setTask(task);
+ task.getTaskFiles().put(name, taskFile);
+ for (AnswerPlaceholder placeholder : getPlaceholders(document, false)) {
+ taskFile.addAnswerPlaceholder(placeholder);
+ }
+ taskFile.sortAnswerPlaceholders();
+ return file;
+ }
+
+ private static List<AnswerPlaceholder> getPlaceholders(Document document, boolean useLength) {
+ final List<AnswerPlaceholder> placeholders = new ArrayList<>();
+ new WriteCommandAction(null) {
+ @Override
+ protected void run(@NotNull Result result) {
+ final String openingTagRx = "<placeholder( taskText=\"(.+?)\")?( possibleAnswer=\"(.+?)\")?>";
+ final String closingTagRx = "</placeholder>";
+ CharSequence text = document.getCharsSequence();
+ final Matcher openingMatcher = Pattern.compile(openingTagRx).matcher(text);
+ final Matcher closingMatcher = Pattern.compile(closingTagRx).matcher(text);
+ int pos = 0;
+ while (openingMatcher.find(pos)) {
+ AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
+ answerPlaceholder.setUseLength(useLength);
+ String taskText = openingMatcher.group(2);
+ if (taskText != null) {
+ answerPlaceholder.setTaskText(taskText);
+ answerPlaceholder.setLength(taskText.length());
+ }
+ String possibleAnswer = openingMatcher.group(4);
+ if (possibleAnswer != null) {
+ answerPlaceholder.setPossibleAnswer(possibleAnswer);
+ }
+ answerPlaceholder.setOffset(openingMatcher.start());
+ if (!closingMatcher.find(openingMatcher.end())) {
+ LOG.error("No matching closing tag found");
+ }
+ if (useLength) {
+ answerPlaceholder.setLength(closingMatcher.start() - openingMatcher.end());
+ } else {
+ if (possibleAnswer == null) {
+ answerPlaceholder.setPossibleAnswer(document.getText(TextRange.create(openingMatcher.end(), closingMatcher.start())));
+ }
+ }
+ document.deleteString(closingMatcher.start(), closingMatcher.end());
+ document.deleteString(openingMatcher.start(), openingMatcher.end());
+ placeholders.add(answerPlaceholder);
+ pos = answerPlaceholder.getOffset() + answerPlaceholder.getRealLength();
+ }
+ }
+ }.execute();
+ return placeholders;
+ }
+
+ public Pair<Document, List<AnswerPlaceholder>> getPlaceholders(String name) {
+ 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);
+ return Pair.create(tempDocument, placeholders);
+ }
+}
+
+
--- /dev/null
+package com.jetbrains.edu.coursecreator;
+
+public class CCTestsUtil {
+ private CCTestsUtil() {
+ }
+
+
+}
--- /dev/null
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+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.learning.courseFormat.AnswerPlaceholder;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class CCShowPreviewTest extends CCTestCase {
+
+ public void testPreviewUnavailable() {
+ VirtualFile file = configureByTaskFile("noplaceholders.txt");
+ CCShowPreview action = new CCShowPreview();
+ TestActionEvent e = getActionEvent(action, getPsiManager().findFile(file));
+ action.beforeActionPerformedUpdate(e);
+ assertTrue(e.getPresentation().isEnabled() && e.getPresentation().isVisible());
+ try {
+ action.actionPerformed(e);
+ assertTrue("No message shown", false);
+ } catch (RuntimeException ex) {
+ assertEquals(CCShowPreview.NO_PREVIEW_MESSAGE, ex.getMessage());
+ }
+ }
+
+ public void testOnePlaceholder() {
+ doTest("test_before.txt", "test_after.txt");
+ }
+
+ public void testSeveralPlaceholders() {
+ doTest("several_before.txt", "several_after.txt");
+ }
+
+ private void doTest(String beforeName, String afterName) {
+ VirtualFile file = configureByTaskFile(beforeName);
+ 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);
+ 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));
+ }
+ 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);
+ context.put(CommonDataKeys.PROJECT, getProject());
+ context.put(LangDataKeys.MODULE, myFixture.getModule());
+ return new TestActionEvent(context, action);
+ }
+}