fixed run tests action
[idea/community.git] / python / educational / course-creator / src / com / jetbrains / edu / coursecreator / actions / CCRunTestsAction.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.jetbrains.edu.coursecreator.actions;
17
18 import com.intellij.execution.Location;
19 import com.intellij.execution.actions.ConfigurationContext;
20 import com.intellij.icons.AllIcons;
21 import com.intellij.ide.fileTemplates.FileTemplate;
22 import com.intellij.openapi.actionSystem.AnAction;
23 import com.intellij.openapi.actionSystem.AnActionEvent;
24 import com.intellij.openapi.actionSystem.Presentation;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.fileEditor.FileDocumentManager;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.util.io.FileUtil;
30 import com.intellij.openapi.util.io.FileUtilRt;
31 import com.intellij.openapi.vfs.VirtualFile;
32 import com.intellij.psi.PsiDirectory;
33 import com.intellij.psi.PsiElement;
34 import com.intellij.psi.PsiFile;
35 import com.jetbrains.edu.EduNames;
36 import com.jetbrains.edu.EduUtils;
37 import com.jetbrains.edu.courseFormat.Course;
38 import com.jetbrains.edu.courseFormat.Lesson;
39 import com.jetbrains.edu.courseFormat.Task;
40 import com.jetbrains.edu.courseFormat.TaskFile;
41 import com.jetbrains.edu.coursecreator.CCLanguageManager;
42 import com.jetbrains.edu.coursecreator.CCProjectService;
43 import com.jetbrains.edu.coursecreator.CCUtils;
44 import org.jetbrains.annotations.NotNull;
45
46 import java.io.IOException;
47 import java.util.Map;
48
49 public abstract class CCRunTestsAction extends AnAction {
50   private static final Logger LOG = Logger.getInstance(CCRunTestsAction.class.getName());
51
52   public CCRunTestsAction() {
53     getTemplatePresentation().setIcon(AllIcons.Actions.Lightning);
54   }
55
56   @Override
57   public void update(@NotNull AnActionEvent e) {
58     if (!CCProjectService.setCCActionAvailable(e)) {
59       EduUtils.enableAction(e, false);
60       return;
61     }
62
63     Presentation presentation = e.getPresentation();
64     presentation.setText("");
65     presentation.setVisible(false);
66     presentation.setEnabled(false);
67
68     final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
69     Location location = context.getLocation();
70     if (location == null) {
71       return;
72     }
73     PsiElement psiElement = location.getPsiElement();
74     PsiFile psiFile = psiElement.getContainingFile();
75     Project project = e.getProject();
76     if (project == null || psiFile == null) {
77       presentation.setVisible(false);
78       presentation.setEnabled(false);
79       return;
80     }
81     final CCProjectService service = CCProjectService.getInstance(project);
82     final Course course = service.getCourse();
83     final PsiDirectory taskDir = psiFile.getContainingDirectory();
84     if (taskDir == null) return;
85     final PsiDirectory lessonDir = taskDir.getParent();
86     if (lessonDir == null) return;
87     if (course == null) return;
88     final Lesson lesson = course.getLesson(lessonDir.getName());
89     if (lesson == null) return;
90     final Task task = lesson.getTask(taskDir.getName());
91     if (task == null) {
92       presentation.setVisible(false);
93       presentation.setEnabled(false);
94       return;
95     }
96     TaskFile taskFile = service.getTaskFile(psiFile.getVirtualFile());
97     if (taskFile == null) {
98       LOG.info("could not find task file");
99       presentation.setVisible(false);
100       presentation.setEnabled(false);
101       return;
102     }
103     if (psiFile.getName().contains(".answer")) {
104       presentation.setEnabled(true);
105       presentation.setVisible(true);
106       presentation.setText("Run tests from '" + psiFile.getName() + "'");
107     }
108     else {
109       presentation.setEnabled(false);
110       presentation.setVisible(false);
111     }
112   }
113
114   public void actionPerformed(@NotNull AnActionEvent e) {
115     final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
116     run(context);
117   }
118
119   private void run(final @NotNull ConfigurationContext context) {
120     ApplicationManager.getApplication().runWriteAction(new Runnable() {
121       @Override
122       public void run() {
123         final Project project = context.getProject();
124         PsiElement location = context.getPsiLocation();
125         final Course course = CCProjectService.getInstance(project).getCourse();
126         if (course == null || location == null) {
127           return;
128         }
129         PsiFile psiFile = location.getContainingFile();
130         final VirtualFile virtualFile = psiFile.getVirtualFile();
131         final VirtualFile taskDir = virtualFile.getParent();
132         if (taskDir == null) {
133           return;
134         }
135         VirtualFile lessonDir = taskDir.getParent();
136         Lesson lesson = course.getLesson(lessonDir.getName());
137         if (lesson == null) {
138           return;
139         }
140         final Task task = lesson.getTask(taskDir.getName());
141         if (task == null) {
142           return;
143         }
144         clearTestEnvironment(taskDir, project);
145         CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
146         if (manager == null) {
147           return;
148         }
149         for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
150           final String name = entry.getKey();
151           createTaskFileForTest(taskDir, name, entry.getValue(), project);
152         }
153         FileTemplate testsTemplate = manager.getTestsTemplate(project);
154         if (testsTemplate == null) {
155           return;
156         }
157         VirtualFile testFile = taskDir.findChild(testsTemplate.getName() + "." + testsTemplate.getExtension());
158         if (testFile == null) {
159           return;
160         }
161         executeTests(project, virtualFile, taskDir, testFile);
162       }
163     });
164   }
165
166   private static void createTaskFileForTest(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile,
167                                             @NotNull final Project project) {
168     try {
169       String answerFileName = FileUtil.getNameWithoutExtension(fileName) + ".answer";
170       final String extension = FileUtilRt.getExtension(fileName);
171       final VirtualFile answerFile = taskDir.findChild(answerFileName + "." + extension);
172       if (answerFile == null) {
173         LOG.debug("could not find answer file " + answerFileName);
174         return;
175       }
176       ApplicationManager.getApplication().runWriteAction(new Runnable() {
177         @Override
178         public void run() {
179           final FileDocumentManager documentManager = FileDocumentManager.getInstance();
180           documentManager.saveAllDocuments();
181         }
182       });
183       final VirtualFile oldTaskFile = taskDir.findChild(fileName);
184       if (oldTaskFile != null) {
185         oldTaskFile.delete(project);
186       }
187       VirtualFile copy = answerFile.copy(project, taskDir, fileName);
188       EduUtils.flushWindows(taskFile, copy, false);
189       createResourceFiles(answerFile, project);
190     }
191     catch (IOException e) {
192       LOG.error(e);
193     }
194   }
195
196   public static void clearTestEnvironment(@NotNull final VirtualFile taskDir, @NotNull final Project project) {
197     try {
198       VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
199       if (ideaDir == null) {
200         LOG.debug("idea directory doesn't exist");
201         return;
202       }
203       VirtualFile courseResourceDir = ideaDir.findChild(EduNames.COURSE);
204       if (courseResourceDir != null) {
205         courseResourceDir.delete(project);
206       }
207       VirtualFile[] taskDirChildren = taskDir.getChildren();
208       for (VirtualFile file : taskDirChildren) {
209         if (file.getName().contains(EduNames.WINDOWS_POSTFIX)) {
210           file.delete(project);
211         }
212         if (CCProjectService.getInstance(project).isTaskFile(file)) {
213           file.delete(project);
214         }
215       }
216     }
217     catch (IOException e) {
218       LOG.error(e);
219     }
220   }
221
222   protected abstract void executeTests(@NotNull final Project project,
223                                    @NotNull final VirtualFile virtualFile,
224                                    @NotNull final VirtualFile taskDir,
225                                    @NotNull final VirtualFile testFile);
226
227   //some tests could compare task files after user modifications with initial task files
228   private static void createResourceFiles(@NotNull final VirtualFile file, @NotNull final Project project) {
229     VirtualFile taskDir = file.getParent();
230     int index = EduUtils.getIndex(taskDir.getName(), EduNames.TASK);
231     VirtualFile lessonDir = taskDir.getParent();
232     int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
233     Course course = CCProjectService.getInstance(project).getCourse();
234     if (course == null) {
235       return;
236     }
237     VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
238     assert ideaDir != null;
239     try {
240       VirtualFile courseResourceDir = findOrCreateDir(project, ideaDir, EduNames.COURSE);
241       VirtualFile lessonResourceDir = findOrCreateDir(project, courseResourceDir, lessonDir.getName());
242       VirtualFile taskResourceDir = findOrCreateDir(project, lessonResourceDir, taskDir.getName());
243       if (EduUtils.indexIsValid(lessonIndex, course.getLessons())) {
244         Lesson lesson = course.getLessons().get(lessonIndex);
245         if (EduUtils.indexIsValid(index, lesson.getTaskList())) {
246           Task task = lesson.getTaskList().get(index);
247           for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
248             TaskFile taskFile = new TaskFile();
249             TaskFile.copy(entry.getValue(), taskFile);
250             EduUtils.createStudentFileFromAnswer(project, taskResourceDir, taskDir, entry.getKey(), taskFile);
251           }
252         }
253       }
254     }
255     catch (IOException e) {
256       LOG.error(e);
257     }
258   }
259
260   private static VirtualFile findOrCreateDir(@NotNull final Project project, @NotNull final VirtualFile dir, String name) throws IOException {
261     VirtualFile targetDir = dir.findChild(name);
262     if (targetDir == null) {
263       targetDir = dir.createChildDirectory(project, name);
264     }
265     return targetDir;
266   }
267
268 }