/* * Copyright 2003-2017 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 jetbrains.mps.idea.core.tests; import com.intellij.facet.FacetManager; import com.intellij.facet.ModifiableFacetModel; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleWithNameAlreadyExists; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleOrderEntry; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.OrderEntry; import com.intellij.util.ThrowableRunnable; import com.intellij.util.ui.UIUtil; import jetbrains.mps.ide.project.ProjectHelper; import jetbrains.mps.idea.core.facet.MPSConfigurationBean; import jetbrains.mps.idea.core.facet.MPSFacet; import jetbrains.mps.idea.core.facet.MPSFacetType; import jetbrains.mps.persistence.DefaultModelRoot; import jetbrains.mps.project.Solution; import jetbrains.mps.project.facets.JavaModuleFacet; import jetbrains.mps.smodel.Language; import jetbrains.mps.smodel.ModuleRepositoryFacade; import jetbrains.mps.util.Computable; import jetbrains.mps.util.IterableUtil; import jetbrains.mps.util.annotation.ToRemove; import org.jetbrains.annotations.NonNls; import org.jetbrains.mps.openapi.module.SDependency; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.persistence.ModelRoot; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; public class FacetTests extends AbstractMPSFixtureTestCase { private ModuleRepositoryFacade myModuleRepositoryFacade; @Override protected void setUp() throws Exception { super.setUp(); myModuleRepositoryFacade = new ModuleRepositoryFacade(ProjectHelper.fromIdeaProject(myModule.getProject())); } @Override protected void runTest() throws Throwable { UIUtil.invokeAndWaitIfNeeded(new ThrowableRunnable() { @Override public void run() throws Throwable { flushEDT(); } }); super.runTest(); } public void testFacetInitialized() { FacetManager facetManager = FacetManager.getInstance(myModule); Collection<MPSFacet> mpsFacets = facetManager.getFacetsByType(MPSFacetType.ID); assertEquals(1, mpsFacets.size()); assertEquals(myFacet, mpsFacets.iterator().next()); assertEquals(myFacet, facetManager.getFacetByType(MPSFacetType.ID)); assertTrue(myFacet.wasInitialized()); runModelRead(() -> { // Default Solution settings Solution solution = myFacet.getSolution(); // relies on the fact that only the core plugin is on (my god why) assertFalse(solution.getModelRoots().iterator().hasNext()); // JDK solution should be always returned as module dependencies for now // Commented out: jdk is connected like a real module sdk, which is probably absent in this test environment // assertEquals(1, solution.getDependencies().size()); assertEmpty(myFacet.getConfiguration().getBean().getUsedLanguages()); assertEquals(getModuleHome() + "/src_gen", solution.getFacet(JavaModuleFacet.class).getOutputRoot().toPath().toString()); Solution repositorySolution = myModuleRepositoryFacade.getModule(solution.getModuleReference(), Solution.class); assertEquals(solution, repositorySolution); assertEquals(myModule.getName(), solution.getModuleDescriptor().getNamespace()); }); } public void testSolutionRemovedOnFacetDeletion() { SModuleReference solutionReference = myFacet.getSolution().getModuleReference(); ApplicationManager.getApplication().runWriteAction(() -> { ModifiableFacetModel modifiableModel = FacetManager.getInstance(myModule).createModifiableModel(); MPSFacet mpsFacet = modifiableModel.getFacetByType(MPSFacetType.ID); modifiableModel.removeFacet(mpsFacet); modifiableModel.commit(); }); Solution repositorySolution = myModuleRepositoryFacade.getModule(solutionReference, Solution.class); assertNull(repositorySolution); } public void testSolutionRemovedOnModuleDeletion() { SModuleReference solutionReference = myFacet.getSolution().getModuleReference(); ApplicationManager.getApplication().runWriteAction(() -> { ModuleManager moduleManager = ModuleManager.getInstance(myModule.getProject()); ModifiableModuleModel modifiableModel = moduleManager.getModifiableModel(); modifiableModel.disposeModule(myModule); modifiableModel.commit(); }); Solution repositorySolution = myModuleRepositoryFacade.getModule(solutionReference, Solution.class); assertNull(repositorySolution); } public void testAddRemoveModelRoot() throws InterruptedException { @NonNls final File modelRootDir = new File(getModuleHome(), "modelRoot"); assertTrue(modelRootDir.mkdir()); final SModuleReference solutionReference = myFacet.getSolution().getModuleReference(); String modelRootPath = modelRootDir.getPath(); MPSConfigurationBean configurationBean = myFacet.getConfiguration().getBean(); DefaultModelRoot root = new DefaultModelRoot(); root.setContentRoot(modelRootPath); root.addFile(DefaultModelRoot.SOURCE_ROOTS, modelRootPath); configurationBean.setModelRoots(Collections.singletonList(root)); myFacet.setConfiguration(configurationBean); flushEDT(); runModelRead(() -> { Solution repositorySolution = myModuleRepositoryFacade.getModule(solutionReference, Solution.class); assertEquals(myFacet.getSolution(), repositorySolution); Iterable<ModelRoot> modelRoots = repositorySolution.getModelRoots(); Iterator<ModelRoot> iterator = modelRoots.iterator(); assertTrue(iterator.hasNext()); ModelRoot theModelRoot = iterator.next(); assertFalse(iterator.hasNext()); assertEquals(modelRootDir.getPath(), ((DefaultModelRoot) theModelRoot).getFiles(DefaultModelRoot.SOURCE_ROOTS).iterator().next()); }); configurationBean = myFacet.getConfiguration().getBean(); configurationBean.setModelRoots(new ArrayList<>()); myFacet.setConfiguration(configurationBean); flushEDT(); runModelRead(() -> { Solution repositorySolution = myModuleRepositoryFacade.getModule(solutionReference, Solution.class); assertFalse(repositorySolution.getModelRoots().iterator().hasNext()); }); } /** * This check does not have any meaning, because adding/removing language to facet itself is not affects anything. * Language imports now moved to models. * * TODO: write test for add/remove used language to model * */ @Deprecated @ToRemove(version = 3.4) public void testAddRemoveUsedLanguage() throws InterruptedException { final Language[] usedLanguages = new Language[2]; final MPSConfigurationBean configurationBean = runModelRead(() -> { Language baseLanguage = (Language) myModuleRepositoryFacade.getModuleByName("jetbrains.mps.baseLanguage"); assertNotNull(baseLanguage); Language editorLanguage = (Language) myModuleRepositoryFacade.getModuleByName("jetbrains.mps.lang.editor"); assertNotNull(editorLanguage); String[] usedLanguageStrings = new String[]{baseLanguage.getModuleReference().toString(), editorLanguage.getModuleReference().toString()}; usedLanguages[0] = baseLanguage; usedLanguages[1] = editorLanguage; MPSConfigurationBean cb = myFacet.getConfiguration().getBean(); cb.setUsedLanguages(usedLanguageStrings); return cb; }); myFacet.setConfiguration(configurationBean); flushEDT(); runModelRead(() -> { Collection<SModuleReference> solutionUsedLanguageRefs = myFacet.getSolution().getUsedLanguagesReferences(); Set<Language> solutionUsedLanguages = new HashSet<>(); for (SModuleReference solutionUsedLanguageRef : solutionUsedLanguageRefs) { solutionUsedLanguages.add(myModuleRepositoryFacade.getModule(solutionUsedLanguageRef, Language.class)); } assertEquals(usedLanguages.length, solutionUsedLanguages.size()); for (Language usedLanguage : usedLanguages) { assertTrue(solutionUsedLanguages.contains(usedLanguage)); } }); configurationBean.setUsedLanguages(new String[0]); myFacet.setConfiguration(configurationBean); flushEDT(); runModelRead(() -> assertEmpty(myFacet.getSolution().getUsedLanguagesReferences())); } public void testSetGeneratorOutputPath() throws InterruptedException { @NonNls String generatorOutputPath = getModuleHome() + "/generatorOut"; MPSConfigurationBean configurationBean = myFacet.getConfiguration().getBean(); configurationBean.setGeneratorOutputPath(generatorOutputPath); myFacet.setConfiguration(configurationBean); flushEDT(); assertEquals(generatorOutputPath, myFacet.getSolution().getFacet(JavaModuleFacet.class).getOutputRoot().toPath().toString()); } public void testDefaultOutput() { MPSConfigurationBean configurationBean = myFacet.getConfiguration().getBean(); assertFalse(configurationBean.isUseTransientOutputFolder()); assertFalse(configurationBean.isUseModuleSourceFolder()); } public void testAddRemoveDependencies() throws Exception { final Module module2 = addModuleAndSetupFixture(myProjectBuilder); final MPSFacet mpsFacet2 = addMPSFacet(module2); // todo: should be one big ModelAccess.runWriteAction() ? Computable<List<SDependency>> getDependencies = () -> IterableUtil.asList(mpsFacet2.getSolution().getDeclaredDependencies()); int originalDependCount = runModelRead(getDependencies).size(); ApplicationManager.getApplication().runWriteAction(() -> { ModifiableRootModel rootModel = ModuleRootManager.getInstance(module2).getModifiableModel(); rootModel.addModuleOrderEntry(myModule); rootModel.commit(); }); flushEDT(); List<SDependency> solution2Dependencies = runModelRead(getDependencies); assertEquals(originalDependCount + 1, solution2Dependencies.size()); boolean found = false; for (SDependency dependency : solution2Dependencies) { if (myFacet.getSolution().getModuleReference().equals(dependency.getTargetModule())) { found = true; break; } } assertTrue("Cross-Module dependency was not exposed in faced dependencies", found); ApplicationManager.getApplication().runWriteAction(() -> { ModifiableRootModel rootModel = ModuleRootManager.getInstance(module2).getModifiableModel(); for (OrderEntry orderEntry : rootModel.getOrderEntries()) { if (orderEntry instanceof ModuleOrderEntry && myModule.equals(((ModuleOrderEntry) orderEntry).getModule())) { rootModel.removeOrderEntry(orderEntry); break; } } rootModel.commit(); }); flushEDT(); int finalDependenciesCount = runModelRead(getDependencies).size(); assertEquals(originalDependCount, finalDependenciesCount); // commented out: we don't always depend on jdk any longer // assertFalse(myFacet.getSolution().getModuleReference().equals(mpsFacet2.getSolution().getDependencies().get(0).getModuleRef())); } public void testUpdateNamespaceOnModuleRename() throws InterruptedException { final String newModuleName = "newModuleName__"; ApplicationManager.getApplication().runWriteAction(() -> { ModifiableModuleModel modifiableModel = ModuleManager.getInstance(myModule.getProject()).getModifiableModel(); try { modifiableModel.renameModule(myModule, newModuleName); } catch (ModuleWithNameAlreadyExists moduleWithNameAlreadyExists) { fail(moduleWithNameAlreadyExists.getMessage()); } modifiableModel.commit(); }); flushEDT(); //In ModuleRenameHandler method resetFacet(MPSFacet) dispose parameter facet and return new instance myFacet = (MPSFacet) FacetManager.getInstance(myModule).getFacetByType(myFacet.getTypeId()); assertEquals(newModuleName, myModule.getName()); assertEquals(newModuleName, myFacet.getSolution().getModuleDescriptor().getNamespace()); } }