Groovy-Eclipse compiler support back-end (IDEA-52379)
[idea/community.git] / java / testFramework / src / com / intellij / testFramework / CompilerTester.java
1 /*
2  * Copyright 2000-2013 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.intellij.testFramework;
17
18 import com.intellij.compiler.CompilerTestUtil;
19 import com.intellij.openapi.application.AccessToken;
20 import com.intellij.openapi.application.Result;
21 import com.intellij.openapi.application.WriteAction;
22 import com.intellij.openapi.command.WriteCommandAction;
23 import com.intellij.openapi.compiler.*;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
27 import com.intellij.openapi.roots.CompilerModuleExtension;
28 import com.intellij.openapi.roots.CompilerProjectExtension;
29 import com.intellij.openapi.roots.ModuleRootManager;
30 import com.intellij.openapi.roots.ModuleRootModificationUtil;
31 import com.intellij.openapi.vfs.VfsUtil;
32 import com.intellij.openapi.vfs.VirtualFile;
33 import com.intellij.psi.JavaPsiFacade;
34 import com.intellij.psi.PsiFile;
35 import com.intellij.psi.search.GlobalSearchScope;
36 import com.intellij.testFramework.fixtures.TempDirTestFixture;
37 import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl;
38 import com.intellij.util.Consumer;
39 import com.intellij.util.ObjectUtils;
40 import com.intellij.util.concurrency.Semaphore;
41 import com.intellij.util.ui.UIUtil;
42 import org.jetbrains.annotations.Nullable;
43 import org.junit.Assert;
44
45 import javax.swing.*;
46 import java.io.File;
47 import java.io.IOException;
48 import java.util.ArrayList;
49 import java.util.Collections;
50 import java.util.List;
51
52 /**
53  * @author peter
54  */
55 public class CompilerTester {
56   private Project myProject;
57   private List<Module> myModules;
58   private TempDirTestFixture myMainOutput;
59
60   public CompilerTester(Module module) throws Exception {
61     this(module.getProject(), Collections.singletonList(module));
62   }
63
64   public CompilerTester(Project project, List<Module> modules) throws Exception {
65     myProject = project;
66     myModules = modules;
67     myMainOutput = new TempDirTestFixtureImpl();
68     myMainOutput.setUp();
69
70     new WriteCommandAction(getProject()) {
71       @Override
72       protected void run(Result result) throws Throwable {
73         //noinspection ConstantConditions
74         CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl());
75         CompilerTestUtil.enableExternalCompiler();
76         for (Module module : myModules) {
77           ModuleRootModificationUtil.setModuleSdk(module, JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk());
78         }
79       }
80     }.execute();
81   }
82
83   public void tearDown() {
84     CompilerTestUtil.disableExternalCompiler(getProject());
85
86     try {
87       myMainOutput.tearDown();
88     }
89     catch (Exception e) {
90       throw new RuntimeException(e);
91     } 
92     finally {
93       myMainOutput = null;
94       myModules = null;
95     }
96   }
97
98   private Project getProject() {
99     return myProject;
100   }
101
102   public void deleteClassFile(final String className) throws IOException {
103     AccessToken token = WriteAction.start();
104     try {
105         //noinspection ConstantConditions
106         touch(JavaPsiFacade.getInstance(getProject()).findClass(className, GlobalSearchScope.allScope(getProject())).getContainingFile().getVirtualFile());
107     }
108     finally {
109       token.finish();
110     }
111   }
112
113   @Nullable
114   public VirtualFile findClassFile(String className, Module module) {
115     //noinspection ConstantConditions
116     VirtualFile path = ModuleRootManager.getInstance(module).getModuleExtension(CompilerModuleExtension.class).getCompilerOutputPath();
117     path.getChildren();
118     assert path != null;
119     path.refresh(false, true);
120     return path.findChild(className.replace('.', '/') + ".class");
121   }
122
123   public void touch(VirtualFile file) throws IOException {
124     file.setBinaryContent(file.contentsToByteArray(), -1, file.getTimeStamp() + 1);
125     File ioFile = VfsUtil.virtualToIoFile(file);
126     assert ioFile.setLastModified(ioFile.lastModified() - 100000);
127     file.refresh(false, false);
128   }
129
130   public void setFileText(final PsiFile file, final String text) throws IOException {
131     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
132       @Override
133       public void run() {
134         try {
135           final VirtualFile virtualFile = file.getVirtualFile();
136           VfsUtil.saveText(ObjectUtils.assertNotNull(virtualFile), text);
137         }
138         catch (IOException e) {
139           throw new RuntimeException(e);
140         }
141       }
142     });
143     touch(file.getVirtualFile());
144   }
145
146   public void setFileName(final PsiFile file, final String name) {
147     new WriteCommandAction(getProject()) {
148       @Override
149       protected void run(Result result) throws Throwable {
150         file.setName(name);
151       }
152     }.execute();
153   }
154
155
156   public List<CompilerMessage> make() {
157     return runCompiler(new Consumer<ErrorReportingCallback>() {
158       @Override
159       public void consume(ErrorReportingCallback callback) {
160         CompilerManager.getInstance(getProject()).make(callback);
161       }
162     });
163   }
164
165   public List<CompilerMessage> rebuild() {
166     return runCompiler(new Consumer<ErrorReportingCallback>() {
167       @Override
168       public void consume(ErrorReportingCallback callback) {
169         CompilerManager.getInstance(getProject()).rebuild(callback);
170       }
171     });
172   }
173
174   public List<CompilerMessage> compileModule(final Module module) {
175     return runCompiler(new Consumer<ErrorReportingCallback>() {
176       @Override
177       public void consume(ErrorReportingCallback callback) {
178         CompilerManager.getInstance(getProject()).compile(module, callback);
179       }
180     });
181   }
182
183   public List<CompilerMessage> make(final CompileScope scope) {
184     return runCompiler(new Consumer<ErrorReportingCallback>() {
185       @Override
186       public void consume(ErrorReportingCallback callback) {
187         CompilerManager.getInstance(getProject()).make(scope, callback);
188       }
189     });
190   }
191
192   public List<CompilerMessage> compileFiles(final VirtualFile... files) {
193     return runCompiler(new Consumer<ErrorReportingCallback>() {
194       @Override
195       public void consume(ErrorReportingCallback callback) {
196         CompilerManager.getInstance(getProject()).compile(files, callback);
197       }
198     });
199   }
200
201   private List<CompilerMessage> runCompiler(final Consumer<ErrorReportingCallback> runnable) {
202     final Semaphore semaphore = new Semaphore();
203     semaphore.down();
204     final ErrorReportingCallback callback = new ErrorReportingCallback(semaphore);
205     UIUtil.invokeAndWaitIfNeeded(new Runnable() {
206       @Override
207       public void run() {
208         try {
209           getProject().save();
210           CompilerTestUtil.saveApplicationSettings();
211           for (Module module : myModules) {
212             final VirtualFile moduleFile = module.getModuleFile();
213             File ioFile = VfsUtil.virtualToIoFile(moduleFile);
214             if (!ioFile.exists()) {
215               getProject().save();
216               assert ioFile.exists() : "File does not exist: " + ioFile.getPath();
217             }
218           }
219           runnable.consume(callback);
220         }
221         catch (Exception e) {
222           throw new RuntimeException(e);
223         }
224       }
225     });
226
227     //tests run in awt
228     while (!semaphore.waitFor(100)) {
229       if (SwingUtilities.isEventDispatchThread()) {
230         UIUtil.dispatchAllInvocationEvents();
231       }
232     }
233     callback.throwException();
234     return callback.getMessages();
235   }
236
237   private static class ErrorReportingCallback implements CompileStatusNotification {
238     private final Semaphore mySemaphore;
239     private Throwable myError;
240     private final List<CompilerMessage> myMessages = new ArrayList<CompilerMessage>();
241
242     public ErrorReportingCallback(Semaphore semaphore) {
243       mySemaphore = semaphore;
244     }
245
246     @Override
247     public void finished(boolean aborted, int errors, int warnings, final CompileContext compileContext) {
248       try {
249         for (CompilerMessageCategory category : CompilerMessageCategory.values()) {
250           CompilerMessage[] messages = compileContext.getMessages(category);
251           for (CompilerMessage message : messages) {
252             final String text = message.getMessage();
253             if (category != CompilerMessageCategory.INFORMATION ||
254                 !(text.contains("Compilation completed successfully") ||
255                   text.startsWith("Using javac") ||
256                   text.startsWith("Using Groovy-Eclipse"))) {
257               myMessages.add(message);
258             }
259           }
260         }
261         Assert.assertFalse("Code did not compile!", aborted);
262       }
263       catch (Throwable t) {
264         myError = t;
265       }
266       finally {
267         mySemaphore.up();
268       }
269     }
270
271     void throwException() {
272       if (myError != null) {
273         throw new RuntimeException(myError);
274       }
275     }
276
277     public List<CompilerMessage> getMessages() {
278       return myMessages;
279     }
280   }
281
282
283 }