3fc82be53f46edd4deb7026988873d7a2c864d1b
[idea/community.git] / platform / external-system-impl / testSrc / com / intellij / openapi / externalSystem / test / ExternalSystemTestCase.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.intellij.openapi.externalSystem.test;
17
18 import com.intellij.compiler.CompilerTestUtil;
19 import com.intellij.compiler.artifacts.ArtifactsTestUtil;
20 import com.intellij.compiler.impl.ModuleCompileScope;
21 import com.intellij.openapi.application.AccessToken;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.application.Result;
24 import com.intellij.openapi.application.WriteAction;
25 import com.intellij.openapi.command.WriteCommandAction;
26 import com.intellij.openapi.compiler.CompileScope;
27 import com.intellij.openapi.compiler.CompilerMessage;
28 import com.intellij.openapi.module.Module;
29 import com.intellij.openapi.module.ModuleManager;
30 import com.intellij.openapi.module.ModuleType;
31 import com.intellij.openapi.module.StdModuleTypes;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.projectRoots.Sdk;
34 import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
35 import com.intellij.openapi.roots.ModuleRootModificationUtil;
36 import com.intellij.openapi.util.Pair;
37 import com.intellij.openapi.util.SystemInfo;
38 import com.intellij.openapi.util.io.ByteSequence;
39 import com.intellij.openapi.util.io.FileUtil;
40 import com.intellij.openapi.util.io.FileUtilRt;
41 import com.intellij.openapi.vfs.*;
42 import com.intellij.packaging.artifacts.Artifact;
43 import com.intellij.packaging.impl.compiler.ArtifactCompileScope;
44 import com.intellij.testFramework.*;
45 import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
46 import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
47 import com.intellij.util.io.TestFileSystemItem;
48 import gnu.trove.THashSet;
49 import org.jetbrains.annotations.NonNls;
50 import org.jetbrains.annotations.NotNull;
51 import org.junit.After;
52 import org.junit.Before;
53
54 import java.awt.*;
55 import java.io.File;
56 import java.io.FileOutputStream;
57 import java.io.IOException;
58 import java.lang.reflect.Field;
59 import java.lang.reflect.Modifier;
60 import java.util.*;
61 import java.util.List;
62 import java.util.jar.Attributes;
63 import java.util.jar.JarEntry;
64 import java.util.jar.JarOutputStream;
65 import java.util.jar.Manifest;
66
67 /**
68  * @author Vladislav.Soroka
69  * @since 6/30/2014
70  */
71 public abstract class ExternalSystemTestCase extends UsefulTestCase {
72   private static File ourTempDir;
73
74   protected IdeaProjectTestFixture myTestFixture;
75
76   protected Project myProject;
77
78   protected File myTestDir;
79   protected VirtualFile myProjectRoot;
80   protected VirtualFile myProjectConfig;
81   protected List<VirtualFile> myAllConfigs = new ArrayList<VirtualFile>();
82
83   static {
84     IdeaTestCase.initPlatformPrefix();
85   }
86
87   @Before
88   @Override
89   public void setUp() throws Exception {
90     super.setUp();
91     ensureTempDirCreated();
92
93     myTestDir = new File(ourTempDir, getTestName(false));
94     FileUtil.ensureExists(myTestDir);
95
96     setUpFixtures();
97     myProject = myTestFixture.getProject();
98
99     edt(new Runnable() {
100       @Override
101       public void run() {
102         ApplicationManager.getApplication().runWriteAction(new Runnable() {
103           @Override
104           public void run() {
105             try {
106               setUpInWriteAction();
107             }
108             catch (Throwable e) {
109               try {
110                 tearDown();
111               }
112               catch (Exception e1) {
113                 e1.printStackTrace();
114               }
115               throw new RuntimeException(e);
116             }
117           }
118         });
119       }
120     });
121   }
122
123   private void ensureTempDirCreated() throws IOException {
124     if (ourTempDir != null) return;
125
126     ourTempDir = new File(FileUtil.getTempDirectory(), getTestsTempDir());
127     FileUtil.delete(ourTempDir);
128     FileUtil.ensureExists(ourTempDir);
129   }
130
131   protected abstract String getTestsTempDir();
132
133   protected void setUpFixtures() throws Exception {
134     myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).getFixture();
135     myTestFixture.setUp();
136   }
137
138   protected void setUpInWriteAction() throws Exception {
139     File projectDir = new File(myTestDir, "project");
140     FileUtil.ensureExists(projectDir);
141     myProjectRoot = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(projectDir);
142   }
143
144   @After
145   @Override
146   public void tearDown() throws Exception {
147     try {
148       edt(new Runnable() {
149         @Override
150         public void run() {
151           try {
152             CompilerTestUtil.disableExternalCompiler(myProject);
153             tearDownFixtures();
154           }
155           catch (Exception e) {
156             throw new RuntimeException(e);
157           }
158         }
159       });
160       myProject = null;
161       if (!FileUtil.delete(myTestDir) && myTestDir.exists()) {
162         System.err.println("Cannot delete " + myTestDir);
163         //printDirectoryContent(myDir);
164         myTestDir.deleteOnExit();
165       }
166     }
167     finally {
168       super.tearDown();
169       resetClassFields(getClass());
170     }
171   }
172
173   private static void printDirectoryContent(File dir) {
174     File[] files = dir.listFiles();
175     if (files == null) return;
176
177     for (File file : files) {
178       System.out.println(file.getAbsolutePath());
179
180       if (file.isDirectory()) {
181         printDirectoryContent(file);
182       }
183     }
184   }
185
186   protected void tearDownFixtures() throws Exception {
187     myTestFixture.tearDown();
188     myTestFixture = null;
189   }
190
191   private void resetClassFields(final Class<?> aClass) {
192     if (aClass == null) return;
193
194     final Field[] fields = aClass.getDeclaredFields();
195     for (Field field : fields) {
196       final int modifiers = field.getModifiers();
197       if ((modifiers & Modifier.FINAL) == 0
198           && (modifiers & Modifier.STATIC) == 0
199           && !field.getType().isPrimitive()) {
200         field.setAccessible(true);
201         try {
202           field.set(this, null);
203         }
204         catch (IllegalAccessException e) {
205           e.printStackTrace();
206         }
207       }
208     }
209
210     if (aClass == ExternalSystemTestCase.class) return;
211     resetClassFields(aClass.getSuperclass());
212   }
213
214   @Override
215   protected void runTest() throws Throwable {
216     try {
217       if (runInWriteAction()) {
218         new WriteAction() {
219           @Override
220           protected void run(@NotNull Result result) throws Throwable {
221             ExternalSystemTestCase.super.runTest();
222           }
223         }.executeSilently().throwException();
224       }
225       else {
226         ExternalSystemTestCase.super.runTest();
227       }
228     }
229     catch (Exception throwable) {
230       Throwable each = throwable;
231       do {
232         if (each instanceof HeadlessException) {
233           printIgnoredMessage("Doesn't work in Headless environment");
234           return;
235         }
236       }
237       while ((each = each.getCause()) != null);
238       throw throwable;
239     }
240   }
241
242   @Override
243   protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
244     runnable.run();
245   }
246
247   protected boolean runInWriteAction() {
248     return false;
249   }
250
251   protected static String getRoot() {
252     if (SystemInfo.isWindows) return "c:";
253     return "";
254   }
255
256   protected static String getEnvVar() {
257     if (SystemInfo.isWindows) return "TEMP";
258     else if (SystemInfo.isLinux) return "HOME";
259     return "TMPDIR";
260   }
261
262   protected String getProjectPath() {
263     return myProjectRoot.getPath();
264   }
265
266   protected String getParentPath() {
267     return myProjectRoot.getParent().getPath();
268   }
269
270   protected String pathFromBasedir(String relPath) {
271     return pathFromBasedir(myProjectRoot, relPath);
272   }
273
274   protected static String pathFromBasedir(VirtualFile root, String relPath) {
275     return FileUtil.toSystemIndependentName(root.getPath() + "/" + relPath);
276   }
277
278   protected Module createModule(String name) throws IOException {
279     return createModule(name, StdModuleTypes.JAVA);
280   }
281
282   protected Module createModule(final String name, final ModuleType type) throws IOException {
283     return new WriteCommandAction<Module>(myProject) {
284       @Override
285       protected void run(Result<Module> moduleResult) throws Throwable {
286         VirtualFile f = createProjectSubFile(name + "/" + name + ".iml");
287         Module module = ModuleManager.getInstance(myProject).newModule(f.getPath(), type.getId());
288         PsiTestUtil.addContentRoot(module, f.getParent());
289         moduleResult.setResult(module);
290       }
291     }.execute().getResultObject();
292   }
293
294   protected VirtualFile createProjectConfig(@NonNls String config) throws IOException {
295     return myProjectConfig = createConfigFile(myProjectRoot, config);
296   }
297
298   protected VirtualFile createConfigFile(final VirtualFile dir, String config) throws IOException {
299     final String configFileName = getExternalSystemConfigFileName();
300     VirtualFile f = dir.findChild(configFileName);
301     if (f == null) {
302       f = new WriteAction<VirtualFile>() {
303         @Override
304         protected void run(Result<VirtualFile> result) throws Throwable {
305           VirtualFile res = dir.createChildData(null, configFileName);
306           result.setResult(res);
307         }
308       }.execute().getResultObject();
309       myAllConfigs.add(f);
310     }
311     setFileContent(f, config, true);
312     return f;
313   }
314
315   protected abstract String getExternalSystemConfigFileName();
316
317   protected void createStdProjectFolders() throws IOException {
318     createProjectSubDirs("src/main/java",
319                          "src/main/resources",
320                          "src/test/java",
321                          "src/test/resources");
322   }
323
324   protected void createProjectSubDirs(String... relativePaths) throws IOException {
325     for (String path : relativePaths) {
326       createProjectSubDir(path);
327     }
328   }
329
330   protected VirtualFile createProjectSubDir(String relativePath) throws IOException {
331     File f = new File(getProjectPath(), relativePath);
332     FileUtil.ensureExists(f);
333     return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
334   }
335
336   protected VirtualFile createProjectSubFile(String relativePath) throws IOException {
337     File f = new File(getProjectPath(), relativePath);
338     FileUtil.ensureExists(f.getParentFile());
339     FileUtil.ensureCanCreateFile(f);
340     final boolean created = f.createNewFile();
341     if(!created) {
342       throw new AssertionError("Unable to create the project sub file: " + f.getAbsolutePath());
343     }
344     return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
345   }
346
347   @NotNull
348   protected VirtualFile createProjectJarSubFile(String relativePath, Pair<ByteSequence, String>... contentEntries) throws IOException {
349     assertTrue("Use 'jar' extension for JAR files: '" + relativePath + "'", FileUtilRt.extensionEquals(relativePath, "jar"));
350     File f = new File(getProjectPath(), relativePath);
351     FileUtil.ensureExists(f.getParentFile());
352     FileUtil.ensureCanCreateFile(f);
353     final boolean created = f.createNewFile();
354     if (!created) {
355       throw new AssertionError("Unable to create the project sub file: " + f.getAbsolutePath());
356     }
357
358     Manifest manifest = new Manifest();
359     manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
360     JarOutputStream target = new JarOutputStream(new FileOutputStream(f), manifest);
361     for (Pair<ByteSequence, String> contentEntry : contentEntries) {
362       addJarEntry(contentEntry.first.getBytes(), contentEntry.second, target);
363     }
364     target.close();
365
366     final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
367     assertNotNull(virtualFile);
368     final VirtualFile jarFile = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile);
369     assertNotNull(jarFile);
370     return jarFile;
371   }
372
373   private static void addJarEntry(byte[] bytes, String path, JarOutputStream target) throws IOException {
374     JarEntry entry = new JarEntry(path.replace("\\", "/"));
375     target.putNextEntry(entry);
376     target.write(bytes);
377     target.close();
378   }
379
380   protected VirtualFile createProjectSubFile(String relativePath, String content) throws IOException {
381     VirtualFile file = createProjectSubFile(relativePath);
382     setFileContent(file, content, false);
383     return file;
384   }
385
386
387   protected void compileModules(final String... moduleNames) {
388     compile(createModulesCompileScope(moduleNames));
389   }
390
391   protected void buildArtifacts(String... artifactNames) {
392     compile(createArtifactsScope(artifactNames));
393   }
394
395   private void compile(final CompileScope scope) {
396     try {
397       CompilerTester tester = new CompilerTester(myProject, Arrays.asList(scope.getAffectedModules()));
398       try {
399         List<CompilerMessage> messages = tester.make(scope);
400         for (CompilerMessage message : messages) {
401           switch (message.getCategory()) {
402             case ERROR:
403               fail("Compilation failed with error: " + message.getMessage());
404               break;
405             case WARNING:
406               System.out.println("Compilation warning: " + message.getMessage());
407               break;
408             case INFORMATION:
409               break;
410             case STATISTICS:
411               break;
412           }
413         }
414       }
415       finally {
416         tester.tearDown();
417       }
418     }
419     catch (Exception e) {
420       throw new RuntimeException(e);
421     }
422   }
423
424
425   private CompileScope createModulesCompileScope(final String[] moduleNames) {
426     final List<Module> modules = new ArrayList<Module>();
427     for (String name : moduleNames) {
428       modules.add(getModule(name));
429     }
430     return new ModuleCompileScope(myProject, modules.toArray(new Module[modules.size()]), false);
431   }
432
433   private CompileScope createArtifactsScope(String[] artifactNames) {
434     List<Artifact> artifacts = new ArrayList<Artifact>();
435     for (String name : artifactNames) {
436       artifacts.add(ArtifactsTestUtil.findArtifact(myProject, name));
437     }
438     return ArtifactCompileScope.createArtifactsScope(myProject, artifacts);
439   }
440
441   protected Sdk setupJdkForModule(final String moduleName) {
442     final Sdk sdk = true ? JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk() : createJdk("Java 1.5");
443     ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk);
444     return sdk;
445   }
446
447   protected static Sdk createJdk(String versionName) {
448     return IdeaTestUtil.getMockJdk17(versionName);
449   }
450
451   protected Module getModule(final String name) {
452     AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock();
453     try {
454       Module m = ModuleManager.getInstance(myProject).findModuleByName(name);
455       assertNotNull("Module " + name + " not found", m);
456       return m;
457     }
458     finally {
459       accessToken.finish();
460     }
461   }
462
463   protected void assertExplodedLayout(String artifactName, String expected) {
464     assertJarLayout(artifactName + " exploded", expected);
465   }
466
467   protected void assertJarLayout(String artifactName, String expected) {
468     ArtifactsTestUtil.assertLayout(myProject, artifactName, expected);
469   }
470
471   protected void assertArtifactOutputPath(final String artifactName, final String expected) {
472     ArtifactsTestUtil.assertOutputPath(myProject, artifactName, expected);
473   }
474
475   protected void assertArtifactOutputFileName(final String artifactName, final String expected) {
476     ArtifactsTestUtil.assertOutputFileName(myProject, artifactName, expected);
477   }
478
479   protected void assertArtifactOutput(String artifactName, TestFileSystemItem fs) {
480     final Artifact artifact = ArtifactsTestUtil.findArtifact(myProject, artifactName);
481     final VirtualFile outputFile = artifact.getOutputFile();
482     assert outputFile != null;
483     final File file = VfsUtilCore.virtualToIoFile(outputFile);
484     fs.assertFileEqual(file);
485   }
486
487   private static void setFileContent(final VirtualFile file, final String content, final boolean advanceStamps) throws IOException {
488     new WriteAction<VirtualFile>() {
489       @Override
490       protected void run(@NotNull Result<VirtualFile> result) throws Throwable {
491         if (advanceStamps) {
492           file.setBinaryContent(content.getBytes(CharsetToolkit.UTF8_CHARSET), -1, file.getTimeStamp() + 4000);
493         }
494         else {
495           file.setBinaryContent(content.getBytes(CharsetToolkit.UTF8_CHARSET), file.getModificationStamp(), file.getTimeStamp());
496         }
497       }
498     }.execute().getResultObject();
499   }
500
501   protected static <T, U> void assertOrderedElementsAreEqual(Collection<U> actual, Collection<T> expected) {
502     assertOrderedElementsAreEqual(actual, expected.toArray());
503   }
504
505   protected static <T> void assertUnorderedElementsAreEqual(Collection<T> actual, Collection<T> expected) {
506     assertEquals(new HashSet<T>(expected), new HashSet<T>(actual));
507   }
508   protected static void assertUnorderedPathsAreEqual(Collection<String> actual, Collection<String> expected) {
509     assertEquals(new SetWithToString<String>(new THashSet<String>(expected, FileUtil.PATH_HASHING_STRATEGY)),
510                  new SetWithToString<String>(new THashSet<String>(actual, FileUtil.PATH_HASHING_STRATEGY)));
511   }
512
513   protected static <T> void assertUnorderedElementsAreEqual(T[] actual, T... expected) {
514     assertUnorderedElementsAreEqual(Arrays.asList(actual), expected);
515   }
516
517   protected static <T> void assertUnorderedElementsAreEqual(Collection<T> actual, T... expected) {
518     assertUnorderedElementsAreEqual(actual, Arrays.asList(expected));
519   }
520
521   protected static <T, U> void assertOrderedElementsAreEqual(Collection<U> actual, T... expected) {
522     String s = "\nexpected: " + Arrays.asList(expected) + "\nactual: " + new ArrayList<U>(actual);
523     assertEquals(s, expected.length, actual.size());
524
525     java.util.List<U> actualList = new ArrayList<U>(actual);
526     for (int i = 0; i < expected.length; i++) {
527       T expectedElement = expected[i];
528       U actualElement = actualList.get(i);
529       assertEquals(s, expectedElement, actualElement);
530     }
531   }
532
533   protected static <T> void assertContain(java.util.List<? extends T> actual, T... expected) {
534     java.util.List<T> expectedList = Arrays.asList(expected);
535     assertTrue("expected: " + expectedList + "\n" + "actual: " + actual.toString(), actual.containsAll(expectedList));
536   }
537
538   protected static <T> void assertDoNotContain(java.util.List<T> actual, T... expected) {
539     java.util.List<T> actualCopy = new ArrayList<T>(actual);
540     actualCopy.removeAll(Arrays.asList(expected));
541     assertEquals(actual.toString(), actualCopy.size(), actual.size());
542   }
543
544   protected boolean ignore() {
545     printIgnoredMessage(null);
546     return true;
547   }
548
549   private void printIgnoredMessage(String message) {
550     String toPrint = "Ignored";
551     if (message != null) {
552       toPrint += ", because " + message;
553     }
554     toPrint += ": " + getClass().getSimpleName() + "." + getName();
555     System.out.println(toPrint);
556   }
557
558   private static class SetWithToString<T> extends AbstractSet<T> {
559
560     private final Set<T> myDelegate;
561
562     public SetWithToString(@NotNull Set<T> delegate) {
563       myDelegate = delegate;
564     }
565
566     @Override
567     public int size() {
568       return myDelegate.size();
569     }
570
571     @Override
572     public boolean contains(Object o) {
573       return myDelegate.contains(o);
574     }
575
576     @NotNull
577     @Override
578     public Iterator<T> iterator() {
579       return myDelegate.iterator();
580     }
581
582     @Override
583     public boolean containsAll(Collection<?> c) {
584       return myDelegate.containsAll(c);
585     }
586
587     @Override
588     public boolean equals(Object o) {
589       return myDelegate.equals(o);
590     }
591
592     @Override
593     public int hashCode() {
594       return myDelegate.hashCode();
595     }
596   }
597
598 }