tests for CCShowPreview
authorLiana Bakradze <liana.bakradze@jetbrains.com>
Tue, 16 Aug 2016 10:27:50 +0000 (13:27 +0300)
committerLiana Bakradze <liana.bakradze@jetbrains.com>
Tue, 16 Aug 2016 10:27:50 +0000 (13:27 +0300)
python/educational-core/course-creator/course-creator.iml
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java
python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCShowPreview.java
python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/several_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/several_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/test_after.txt [new file with mode: 0644]
python/educational-core/course-creator/testData/actions/preview/test_before.txt [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java [new file with mode: 0644]
python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java [new file with mode: 0644]

index 6c6bf51f6d20555ab40cbd8278de5a0594e660f5..7f8af6dd20f2873d7a7c0da40877fd3a2ad0fb66 100644 (file)
@@ -5,6 +5,7 @@
     <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" />
@@ -13,5 +14,6 @@
     <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
index 791bfaabce5fcc52dec63deb0b08e06c187c2f50..572db02ec8d1fd60f1ae3dccacf2c1aa5bac0ec9 100644 (file)
@@ -22,10 +22,19 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
   @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;
@@ -76,6 +85,9 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
     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;
@@ -125,7 +137,6 @@ public class CCVirtualFileListener extends VirtualFileAdapter {
     if (task == null) {
       return;
     }
-    //TODO: remove from steps as well
     task.getTaskFiles().remove(removedTaskFile.getName());
   }
 }
index 52b497f61fd7ea50e54f76369c3658fc6be88bf6..f312436106c2750175986be1260453c256a4f71c 100644 (file)
@@ -55,6 +55,7 @@ import java.util.Calendar;
 
 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);
@@ -161,6 +162,8 @@ public class CCShowPreview extends DumbAwareAction {
     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
diff --git a/python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt b/python/educational-core/course-creator/testData/actions/preview/noplaceholders.txt
new file mode 100644 (file)
index 0000000..ad22405
--- /dev/null
@@ -0,0 +1 @@
+no placeholders
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/several_after.txt b/python/educational-core/course-creator/testData/actions/preview/several_after.txt
new file mode 100644 (file)
index 0000000..9422757
--- /dev/null
@@ -0,0 +1 @@
+print("<placeholder>veryverylongtextveryverylongtextveryverylongtextveryverylongtext</placeholder> + <placeholder>test</placeholder> = 2")
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/several_before.txt b/python/educational-core/course-creator/testData/actions/preview/several_before.txt
new file mode 100644 (file)
index 0000000..652621a
--- /dev/null
@@ -0,0 +1 @@
+print("<placeholder taskText="veryverylongtextveryverylongtextveryverylongtextveryverylongtext">1</placeholder> + <placeholder taskText="test">1</placeholder> = 2")
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/test_after.txt b/python/educational-core/course-creator/testData/actions/preview/test_after.txt
new file mode 100644 (file)
index 0000000..9a1e373
--- /dev/null
@@ -0,0 +1 @@
+<placeholder>type here</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testData/actions/preview/test_before.txt b/python/educational-core/course-creator/testData/actions/preview/test_before.txt
new file mode 100644 (file)
index 0000000..3012cb8
--- /dev/null
@@ -0,0 +1 @@
+<placeholder taskText="type here">two</placeholder>
\ No newline at end of file
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java
new file mode 100644 (file)
index 0000000..d1756f2
--- /dev/null
@@ -0,0 +1,139 @@
+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);
+  }
+}
+
+
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/CCTestsUtil.java
new file mode 100644 (file)
index 0000000..5b14b8e
--- /dev/null
@@ -0,0 +1,8 @@
+package com.jetbrains.edu.coursecreator;
+
+public class CCTestsUtil {
+  private CCTestsUtil() {
+  }
+
+
+}
diff --git a/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java b/python/educational-core/course-creator/testSrc/com/jetbrains/edu/coursecreator/actions/CCShowPreviewTest.java
new file mode 100644 (file)
index 0000000..c105652
--- /dev/null
@@ -0,0 +1,90 @@
+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);
+  }
+}