package com.intellij.flex.uiDesigner; import com.intellij.flex.uiDesigner.io.StringRegistry; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.impl.DebugUtil; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.net.SocketException; import java.util.concurrent.atomic.AtomicBoolean; import static com.intellij.flex.uiDesigner.DocumentFactoryManager.DocumentInfo; @Flex(version="4.5") public class AppTest extends AppTestBase { private static final int APP_TEST_CLASS_ID = 3; private final Semaphore semaphore = new Semaphore(); private final AtomicBoolean fail = new AtomicBoolean(); @Override protected void changeServicesImplementation() { Tests.changeDesignerServiceImplementation(SocketInputHandler.class, MySocketInputHandler.class); Tests.changeDesignerServiceImplementation(Client.class, TestClient.class); } @Override protected void applicationLaunchedAndInitialized() { ((MySocketInputHandler)SocketInputHandler.getInstance()).fail = fail; ((MySocketInputHandler)SocketInputHandler.getInstance()).semaphore = semaphore; MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(myModule); connection.subscribe(DesignerApplicationManager.MESSAGE_TOPIC, new DocumentRenderedListener() { @Override public void documentRendered(DocumentInfo info) { semaphore.up(); } @Override public void errorOccurred() { fail.set(true); semaphore.up(); } }); } private void await() throws InterruptedException { semaphore.waitForUnsafe(); if (fail.get()) { fail(); } } private void callClientAssert(String methodName) throws IOException, InterruptedException { semaphore.down(); client.test(methodName.equals("close") ? null : myModule, methodName, APP_TEST_CLASS_ID); await(); fail.set(false); } private void callClientAssert(VirtualFile file) throws IOException, InterruptedException { semaphore.down(); ActionCallback callback = client.test(null, DocumentFactoryManager.getInstance().getId(file), getTestName(false), APP_TEST_CLASS_ID); callback.doWhenProcessed(() -> semaphore.up()); await(); } public void _testCloseAndOpenProject() throws Exception { File temp = createTempDirectory(); final Project alienProject = createProject(temp + "/t.ipr", DebugUtil.currentStackTrace()); assertTrue(ProjectManagerEx.getInstanceEx().openProject(alienProject)); UIUtil.dispatchAllInvocationEvents(); // startup activities openAndWait(configureByFiles("injectedAS/Transitions.mxml")[0], "injectedAS/Transitions.mxml"); } private void renderAndWait(VirtualFile file) throws InterruptedException { semaphore.down(); AsyncResult<DocumentInfo> result = DesignerApplicationManager.getInstance().renderDocument(myModule, Tests.virtualToPsi(myProject, file)); result.doWhenProcessed(() -> semaphore.up()); await(); } public void testUpdateDocumentOnIdeaAutoSave() throws Exception { final VirtualFile[] files = configureByFiles("ProjectMxmlComponentAsChild.mxml", "AuxProjectMxmlComponent.mxml"); renderAndWait(files[0]); insertString(files[0], 166, "A"); callClientAssert(files[0]); renderAndWait(files[1]); insertString(files[1], 191, "A"); callClientAssert(files[0]); } private void insertString(VirtualFile file, final int offset, @NotNull final CharSequence s) throws InterruptedException { final Document document = FileDocumentManager.getInstance().getDocument(file); assertNotNull(document); ApplicationManager.getApplication().runWriteAction(() -> document.insertString(offset, s)); semaphore.down(); PsiDocumentManager.getInstance(myProject).commitAllDocuments(); FileDocumentManager.getInstance().saveAllDocuments(); await(); } private void openAndWait(VirtualFile file, @Nullable String relativePath) throws InterruptedException, IOException { semaphore.down(); DesignerApplicationManager.getInstance().renderDocument(myModule, Tests.virtualToPsi(myProject, file)); await(); } @Override protected void tearDown() throws Exception { try { super.tearDown(); if (getName().equals("testCloseAndOpenProject")) { callClientAssert("close"); } } finally { DesignerApplicationManager.getInstance().disposeApplication(); StringRegistry.getInstance().reset(); } } private static class MySocketInputHandler extends TestSocketInputHandler { private AtomicBoolean fail; private Semaphore semaphore; @Override protected boolean processOnRead() { return true; } @Override protected void processCommand(int command) throws IOException { boolean result = true; try { super.processCommand(command); } catch (Throwable e) { //noinspection InstanceofCatchParameter if (!(e instanceof SocketException)) { result = false; fail.set(true); try { LOG.error(e); } catch (AssertionError ignored) { } } } finally { if (!result) { semaphore.up(); } } } } }