Merge branch 'liana/simplified_debugger'
[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.AbstractMap;
48 import java.util.Map;
49
50 public abstract class CCRunTestsAction extends AnAction {
51   private static final Logger LOG = Logger.getInstance(CCRunTestsAction.class.getName());
52
53   public CCRunTestsAction() {
54     getTemplatePresentation().setIcon(AllIcons.Actions.Lightning);
55   }
56
57   @Override
58   public void update(@NotNull AnActionEvent e) {
59     if (!CCProjectService.setCCActionAvailable(e)) {
60       EduUtils.enableAction(e, false);
61       return;
62     }
63
64     Presentation presentation = e.getPresentation();
65     presentation.setText("");
66     presentation.setVisible(false);
67     presentation.setEnabled(false);
68
69     final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
70     Location location = context.getLocation();
71     if (location == null) {
72       return;
73     }
74     PsiElement psiElement = location.getPsiElement();
75     PsiFile psiFile = psiElement.getContainingFile();
76     Project project = e.getProject();
77     if (project == null || psiFile == null) {
78       presentation.setVisible(false);
79       presentation.setEnabled(false);
80       return;
81     }
82     final CCProjectService service = CCProjectService.getInstance(project);
83     final Course course = service.getCourse();
84     final PsiDirectory taskDir = psiFile.getContainingDirectory();
85     if (taskDir == null) return;
86     final PsiDirectory lessonDir = taskDir.getParent();
87     if (lessonDir == null) return;
88     if (course == null) return;
89     final Lesson lesson = course.getLesson(lessonDir.getName());
90     if (lesson == null) return;
91     final Task task = lesson.getTask(taskDir.getName());
92     if (task == null) {
93       presentation.setVisible(false);
94       presentation.setEnabled(false);
95       return;
96     }
97     TaskFile taskFile = service.getTaskFile(psiFile.getVirtualFile());
98     if (taskFile == null) {
99       LOG.info("could not find task file");
100       presentation.setVisible(false);
101       presentation.setEnabled(false);
102       return;
103     }
104     if (psiFile.getName().contains(".answer")) {
105       presentation.setEnabled(true);
106       presentation.setVisible(true);
107       presentation.setText("Run tests from '" + psiFile.getName() + "'");
108     }
109     else {
110       presentation.setEnabled(false);
111       presentation.setVisible(false);
112     }
113   }
114
115   public void actionPerformed(@NotNull AnActionEvent e) {
116     final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
117     run(context);
118   }
119
120   private void run(final @NotNull ConfigurationContext context) {
121     ApplicationManager.getApplication().runWriteAction(new Runnable() {
122       @Override
123       public void run() {
124         final Project project = context.getProject();
125         PsiElement location = context.getPsiLocation();
126         final Course course = CCProjectService.getInstance(project).getCourse();
127         if (course == null || location == null) {
128           return;
129         }
130         PsiFile psiFile = location.getContainingFile();
131         final VirtualFile virtualFile = psiFile.getVirtualFile();
132         final VirtualFile taskDir = virtualFile.getParent();
133         if (taskDir == null) {
134           return;
135         }
136         VirtualFile lessonDir = taskDir.getParent();
137         Lesson lesson = course.getLesson(lessonDir.getName());
138         if (lesson == null) {
139           return;
140         }
141         final Task task = lesson.getTask(taskDir.getName());
142         if (task == null) {
143           return;
144         }
145         clearTestEnvironment(taskDir, project);
146         for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
147           final String name = entry.getKey();
148           CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
149           if (manager == null) {
150             return;
151           }
152           createTestEnvironment(taskDir, name, entry.getValue(), project);
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
167   private static void createTestEnvironment(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile,
168                                             @NotNull final Project project) {
169     try {
170       String answerFileName = FileUtil.getNameWithoutExtension(fileName) + ".answer";
171       final String extension = FileUtilRt.getExtension(fileName);
172       final VirtualFile answerFile = taskDir.findChild(answerFileName + "." + extension);
173       if (answerFile == null) {
174         LOG.debug("could not find answer file " + answerFileName);
175         return;
176       }
177       ApplicationManager.getApplication().runWriteAction(new Runnable() {
178         @Override
179         public void run() {
180           final FileDocumentManager documentManager = FileDocumentManager.getInstance();
181           documentManager.saveAllDocuments();
182         }
183       });
184       final VirtualFile oldTaskFile = taskDir.findChild(fileName);
185       if (oldTaskFile != null) {
186         oldTaskFile.delete(project);
187       }
188       answerFile.copy(project, taskDir, fileName);
189       EduUtils.flushWindows(taskFile, answerFile, false);
190       createResourceFiles(answerFile, project);
191     }
192     catch (IOException e) {
193       LOG.error(e);
194     }
195   }
196
197   public static void clearTestEnvironment(@NotNull final VirtualFile taskDir, @NotNull final Project project) {
198     try {
199       VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
200       if (ideaDir == null) {
201         LOG.debug("idea directory doesn't exist");
202         return;
203       }
204       VirtualFile courseResourceDir = ideaDir.findChild(EduNames.COURSE);
205       if (courseResourceDir != null) {
206         courseResourceDir.delete(project);
207       }
208       VirtualFile[] taskDirChildren = taskDir.getChildren();
209       for (VirtualFile file : taskDirChildren) {
210         if (file.getName().contains(EduNames.WINDOWS_POSTFIX)) {
211           file.delete(project);
212         }
213         if (CCProjectService.getInstance(project).isTaskFile(file)) {
214           file.delete(project);
215         }
216       }
217     }
218     catch (IOException e) {
219       LOG.error(e);
220     }
221   }
222
223   protected abstract void executeTests(@NotNull final Project project,
224                                    @NotNull final VirtualFile virtualFile,
225                                    @NotNull final VirtualFile taskDir,
226                                    @NotNull final VirtualFile testFile);
227
228   //some tests could compare task files after user modifications with initial task files
229   private static void createResourceFiles(@NotNull final VirtualFile file, @NotNull final Project project) {
230     VirtualFile taskDir = file.getParent();
231     int index = EduUtils.getIndex(taskDir.getName(), EduNames.TASK);
232     VirtualFile lessonDir = taskDir.getParent();
233     int lessonIndex = EduUtils.getIndex(lessonDir.getName(), EduNames.LESSON);
234     Course course = CCProjectService.getInstance(project).getCourse();
235     if (course == null) {
236       return;
237     }
238     VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
239     assert ideaDir != null;
240     try {
241       VirtualFile courseResourceDir = findOrCreateDir(project, ideaDir, EduNames.COURSE);
242       VirtualFile lessonResourceDir = findOrCreateDir(project, courseResourceDir, lessonDir.getName());
243       VirtualFile taskResourceDir = findOrCreateDir(project, lessonResourceDir, taskDir.getName());
244       if (EduUtils.indexIsValid(lessonIndex, course.getLessons())) {
245         Lesson lesson = course.getLessons().get(lessonIndex);
246         if (EduUtils.indexIsValid(index, lesson.getTaskList())) {
247           Task task = lesson.getTaskList().get(index);
248           for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
249             TaskFile taskFileCopy = new TaskFile();
250             TaskFile.copy(entry.getValue(), taskFileCopy);
251             EduUtils.createStudentFileFromAnswer(project, taskResourceDir, taskDir,
252                                                  new AbstractMap.SimpleEntry<String, TaskFile>(entry.getKey(), taskFileCopy));
253           }
254         }
255       }
256     }
257     catch (IOException e) {
258       LOG.error(e);
259     }
260   }
261
262   private static VirtualFile findOrCreateDir(@NotNull final Project project, @NotNull final VirtualFile dir, String name) throws IOException {
263     VirtualFile targetDir = dir.findChild(name);
264     if (targetDir == null) {
265       targetDir = dir.createChildDirectory(project, name);
266     }
267     return targetDir;
268   }
269
270 }