| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.testFramework; |
| |
| import com.intellij.compiler.CompilerTestUtil; |
| import com.intellij.openapi.application.AccessToken; |
| import com.intellij.openapi.application.Result; |
| import com.intellij.openapi.application.WriteAction; |
| import com.intellij.openapi.command.WriteCommandAction; |
| import com.intellij.openapi.compiler.*; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; |
| import com.intellij.openapi.roots.CompilerModuleExtension; |
| import com.intellij.openapi.roots.CompilerProjectExtension; |
| import com.intellij.openapi.roots.ModuleRootManager; |
| import com.intellij.openapi.roots.ModuleRootModificationUtil; |
| import com.intellij.openapi.vfs.VfsUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.psi.JavaPsiFacade; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.intellij.testFramework.fixtures.TempDirTestFixture; |
| import com.intellij.testFramework.fixtures.impl.TempDirTestFixtureImpl; |
| import com.intellij.util.Consumer; |
| import com.intellij.util.ObjectUtils; |
| import com.intellij.util.concurrency.Semaphore; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.Nullable; |
| import org.junit.Assert; |
| |
| import javax.swing.*; |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** |
| * @author peter |
| */ |
| public class CompilerTester { |
| private Project myProject; |
| private List<Module> myModules; |
| private TempDirTestFixture myMainOutput; |
| |
| public CompilerTester(Module module) throws Exception { |
| this(module.getProject(), Collections.singletonList(module)); |
| } |
| |
| public CompilerTester(Project project, List<Module> modules) throws Exception { |
| myProject = project; |
| myModules = modules; |
| myMainOutput = new TempDirTestFixtureImpl(); |
| myMainOutput.setUp(); |
| |
| new WriteCommandAction(getProject()) { |
| @Override |
| protected void run(Result result) throws Throwable { |
| //noinspection ConstantConditions |
| CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl()); |
| CompilerTestUtil.enableExternalCompiler(); |
| for (Module module : myModules) { |
| ModuleRootModificationUtil.setModuleSdk(module, JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk()); |
| } |
| } |
| }.execute(); |
| } |
| |
| public void tearDown() { |
| CompilerTestUtil.disableExternalCompiler(getProject()); |
| |
| try { |
| myMainOutput.tearDown(); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| finally { |
| myMainOutput = null; |
| myModules = null; |
| } |
| } |
| |
| private Project getProject() { |
| return myProject; |
| } |
| |
| public void deleteClassFile(final String className) throws IOException { |
| AccessToken token = WriteAction.start(); |
| try { |
| //noinspection ConstantConditions |
| touch(JavaPsiFacade.getInstance(getProject()).findClass(className, GlobalSearchScope.allScope(getProject())).getContainingFile().getVirtualFile()); |
| } |
| finally { |
| token.finish(); |
| } |
| } |
| |
| @Nullable |
| public VirtualFile findClassFile(String className, Module module) { |
| //noinspection ConstantConditions |
| VirtualFile path = ModuleRootManager.getInstance(module).getModuleExtension(CompilerModuleExtension.class).getCompilerOutputPath(); |
| path.getChildren(); |
| assert path != null; |
| path.refresh(false, true); |
| return path.findChild(className.replace('.', '/') + ".class"); |
| } |
| |
| public void touch(VirtualFile file) throws IOException { |
| file.setBinaryContent(file.contentsToByteArray(), -1, file.getTimeStamp() + 1); |
| File ioFile = VfsUtil.virtualToIoFile(file); |
| assert ioFile.setLastModified(ioFile.lastModified() - 100000); |
| file.refresh(false, false); |
| } |
| |
| public void setFileText(final PsiFile file, final String text) throws IOException { |
| UIUtil.invokeAndWaitIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| final VirtualFile virtualFile = file.getVirtualFile(); |
| VfsUtil.saveText(ObjectUtils.assertNotNull(virtualFile), text); |
| } |
| catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }); |
| touch(file.getVirtualFile()); |
| } |
| |
| public void setFileName(final PsiFile file, final String name) { |
| new WriteCommandAction(getProject()) { |
| @Override |
| protected void run(Result result) throws Throwable { |
| file.setName(name); |
| } |
| }.execute(); |
| } |
| |
| |
| public List<CompilerMessage> make() { |
| return runCompiler(new Consumer<ErrorReportingCallback>() { |
| @Override |
| public void consume(ErrorReportingCallback callback) { |
| CompilerManager.getInstance(getProject()).make(callback); |
| } |
| }); |
| } |
| |
| public List<CompilerMessage> rebuild() { |
| return runCompiler(new Consumer<ErrorReportingCallback>() { |
| @Override |
| public void consume(ErrorReportingCallback callback) { |
| CompilerManager.getInstance(getProject()).rebuild(callback); |
| } |
| }); |
| } |
| |
| public List<CompilerMessage> compileModule(final Module module) { |
| return runCompiler(new Consumer<ErrorReportingCallback>() { |
| @Override |
| public void consume(ErrorReportingCallback callback) { |
| CompilerManager.getInstance(getProject()).compile(module, callback); |
| } |
| }); |
| } |
| |
| public List<CompilerMessage> make(final CompileScope scope) { |
| return runCompiler(new Consumer<ErrorReportingCallback>() { |
| @Override |
| public void consume(ErrorReportingCallback callback) { |
| CompilerManager.getInstance(getProject()).make(scope, callback); |
| } |
| }); |
| } |
| |
| public List<CompilerMessage> compileFiles(final VirtualFile... files) { |
| return runCompiler(new Consumer<ErrorReportingCallback>() { |
| @Override |
| public void consume(ErrorReportingCallback callback) { |
| CompilerManager.getInstance(getProject()).compile(files, callback); |
| } |
| }); |
| } |
| |
| private List<CompilerMessage> runCompiler(final Consumer<ErrorReportingCallback> runnable) { |
| final Semaphore semaphore = new Semaphore(); |
| semaphore.down(); |
| final ErrorReportingCallback callback = new ErrorReportingCallback(semaphore); |
| UIUtil.invokeAndWaitIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| try { |
| getProject().save(); |
| CompilerTestUtil.saveApplicationSettings(); |
| for (Module module : myModules) { |
| final VirtualFile moduleFile = module.getModuleFile(); |
| File ioFile = VfsUtil.virtualToIoFile(moduleFile); |
| if (!ioFile.exists()) { |
| getProject().save(); |
| assert ioFile.exists() : "File does not exist: " + ioFile.getPath(); |
| } |
| } |
| runnable.consume(callback); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| }); |
| |
| //tests run in awt |
| while (!semaphore.waitFor(100)) { |
| if (SwingUtilities.isEventDispatchThread()) { |
| UIUtil.dispatchAllInvocationEvents(); |
| } |
| } |
| callback.throwException(); |
| return callback.getMessages(); |
| } |
| |
| private static class ErrorReportingCallback implements CompileStatusNotification { |
| private final Semaphore mySemaphore; |
| private Throwable myError; |
| private final List<CompilerMessage> myMessages = new ArrayList<CompilerMessage>(); |
| |
| public ErrorReportingCallback(Semaphore semaphore) { |
| mySemaphore = semaphore; |
| } |
| |
| @Override |
| public void finished(boolean aborted, int errors, int warnings, final CompileContext compileContext) { |
| try { |
| for (CompilerMessageCategory category : CompilerMessageCategory.values()) { |
| CompilerMessage[] messages = compileContext.getMessages(category); |
| for (CompilerMessage message : messages) { |
| final String text = message.getMessage(); |
| if (category != CompilerMessageCategory.INFORMATION || !(text.contains("Compilation completed successfully") || text.startsWith("Using javac"))) { |
| myMessages.add(message); |
| } |
| } |
| } |
| Assert.assertFalse("Code did not compile!", aborted); |
| } |
| catch (Throwable t) { |
| myError = t; |
| } |
| finally { |
| mySemaphore.up(); |
| } |
| } |
| |
| void throwException() { |
| if (myError != null) { |
| throw new RuntimeException(myError); |
| } |
| } |
| |
| public List<CompilerMessage> getMessages() { |
| return myMessages; |
| } |
| } |
| |
| |
| } |