--- /dev/null
+/*
+ * Copyright 2000-2016 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.roots;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.roots.TestModuleProperties;
+import com.intellij.testFramework.ModuleTestCase;
+
+/**
+ * @author nik
+ */
+public class ModuleTestPropertiesTest extends ModuleTestCase {
+ public void testSetAndGet() throws Exception {
+ Module tests = createModule("tests");
+ TestModuleProperties moduleProperties = TestModuleProperties.getInstance(tests);
+ moduleProperties.setProductionModuleName(myModule.getName());
+ assertSame(myModule, moduleProperties.getProductionModule());
+ }
+}
@Nullable private String[] myIdeModuleGroup;
@Nullable private String mySourceCompatibility;
@Nullable private String myTargetCompatibility;
+ @Nullable private String myProductionModuleId;
private boolean myInheritProjectCompileOutputPath = true;
myModuleFileDirectoryPath = path;
}
+ /**
+ * @return an internal id of production module corresponding to a test-only module, this information is used to populate
+ * {@link com.intellij.openapi.roots.TestModuleProperties}
+ */
+ @Nullable
+ public String getProductionModuleId() {
+ return myProductionModuleId;
+ }
+
+ public void setProductionModuleId(@Nullable String productionModuleId) {
+ myProductionModuleId = productionModuleId;
+ }
+
public boolean isInheritProjectCompileOutputPath() {
return myInheritProjectCompileOutputPath;
}
void commit();
void dispose();
+
+ void setTestModuleProperties(Module testModule, String productionModuleName);
}
private ModifiableModuleModel myModifiableModuleModel;
private Map<Module, ModifiableRootModel> myModifiableRootModels = new THashMap<Module, ModifiableRootModel>();
private Map<Module, ModifiableFacetModel> myModifiableFacetModels = new THashMap<Module, ModifiableFacetModel>();
+ private Map<Module, String> myProductionModulesForTestModules = new THashMap<Module, String>();
private Map<Library, Library.ModifiableModel> myModifiableLibraryModels = new IdentityHashMap<Library, Library.ModifiableModel>();
private ModifiableArtifactModel myModifiableArtifactModel;
private AbstractIdeModifiableModelsProvider.MyPackagingElementResolvingContext myPackagingElementResolvingContext;
model.commit();
}
}
+ for (Map.Entry<Module, String> entry : myProductionModulesForTestModules.entrySet()) {
+ TestModuleProperties.getInstance(entry.getKey()).setProductionModuleName(entry.getValue());
+ }
for (Map.Entry<Module, ModifiableFacetModel> each : myModifiableFacetModels.entrySet()) {
if(!each.getKey().isDisposed()) {
myModifiableFacetModels.clear();
myModifiableLibraryModels.clear();
}
+
+ @Override
+ public void setTestModuleProperties(Module testModule, String productionModuleName) {
+ myProductionModulesForTestModules.put(testModule, productionModuleName);
+ }
}
ModuleData data = module.getData();
final Module created = modelsProvider.newModule(data.getModuleFilePath(), data.getModuleTypeId());
module.putUserData(MODULE_KEY, created);
+ String productionModuleId = data.getProductionModuleId();
+ if (productionModuleId != null) {
+ modelsProvider.setTestModuleProperties(created, productionModuleId);
+ }
Set<String> orphanFiles = project.getUserData(ORPHAN_MODULE_FILES);
if (orphanFiles != null) {
orphanFiles.remove(created.getModuleFilePath());
<moduleService serviceInterface="com.intellij.openapi.components.impl.stores.IComponentStore"
serviceImplementation="com.intellij.configurationStore.ModuleStoreImpl"
testServiceImplementation="com.intellij.configurationStore.ModuleStoreImpl$TestModuleStore"/>
+ <moduleService serviceInterface="com.intellij.openapi.roots.TestModuleProperties"
+ serviceImplementation="com.intellij.openapi.roots.impl.TestModulePropertiesImpl"/>
<moduleService serviceImplementation="com.intellij.openapi.module.impl.ModuleImpl$DeprecatedModuleOptionManager"/>
<moduleService serviceInterface="com.intellij.openapi.components.PathMacroManager" serviceImplementation="com.intellij.openapi.components.impl.ModulePathMacroManager"/>
--- /dev/null
+/*
+ * Copyright 2000-2016 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.openapi.roots;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleServiceManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * In some cases tests need to be extracted to a separate module (because they have a different classpath, output folder or JDK). E.g. when
+ * the project is imported from Gradle IDEA creates separate modules for each source set of a Gradle project.
+ * <p/>
+ * This service allows to specify to which production module the tests module belongs. This information may be used for example by
+ * 'Create Test' feature.
+ * <p/>
+ * <strong>This API isn't stable for now and may be changed in future. Also it isn't possible to change this in UI.</strong>
+ * @author nik
+ */
+public abstract class TestModuleProperties {
+ public static TestModuleProperties getInstance(@NotNull Module module) {
+ return ModuleServiceManager.getService(module, TestModuleProperties.class);
+ }
+
+ @Nullable
+ public abstract String getProductionModuleName();
+
+ @Nullable
+ public abstract Module getProductionModule();
+
+ public abstract void setProductionModuleName(@Nullable String moduleName);
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 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.openapi.roots.impl;
+
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModulePointer;
+import com.intellij.openapi.module.ModulePointerManager;
+import com.intellij.openapi.roots.TestModuleProperties;
+import com.intellij.util.xmlb.annotations.Attribute;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+@State(
+ name = "TestModuleProperties",
+ storages = @Storage(file = StoragePathMacros.MODULE_FILE)
+)
+public class TestModulePropertiesImpl extends TestModuleProperties implements PersistentStateComponent<TestModulePropertiesImpl.TestModulePropertiesState> {
+ private final ModulePointerManager myModulePointerManager;
+ private ModulePointer myProductionModulePointer;
+
+ public TestModulePropertiesImpl(@NotNull ModulePointerManager modulePointerManager) {
+ myModulePointerManager = modulePointerManager;
+ }
+
+ @Nullable
+ @Override
+ public String getProductionModuleName() {
+ return myProductionModulePointer != null ? myProductionModulePointer.getModuleName() : null;
+ }
+
+ @Nullable
+ @Override
+ public Module getProductionModule() {
+ return myProductionModulePointer != null ? myProductionModulePointer.getModule() : null;
+ }
+
+ @Override
+ public void setProductionModuleName(@Nullable String moduleName) {
+ myProductionModulePointer = moduleName != null ? myModulePointerManager.create(moduleName) : null;
+ }
+
+ @Nullable
+ @Override
+ public TestModulePropertiesState getState() {
+ TestModulePropertiesState state = new TestModulePropertiesState();
+ state.moduleName = getProductionModuleName();
+ return state;
+ }
+
+ @Override
+ public void loadState(TestModulePropertiesState state) {
+
+ }
+
+ public static class TestModulePropertiesState {
+ @Attribute("production-module")
+ public String moduleName;
+ }
+}
for (ExternalSourceSet sourceSet : externalProject.getSourceSets().values()) {
final String moduleId = getModuleId(externalProject, sourceSet);
final String moduleExternalName = gradleModule.getName() + ":" + sourceSet.getName();
- final String moduleInternalName = gradleModule.getName() + "_" + sourceSet.getName();
+ final String moduleInternalName = getInternalModuleName(gradleModule, sourceSet.getName());
GradleSourceSetData sourceSetData = new GradleSourceSetData(
moduleId, moduleExternalName, moduleInternalName, mainModuleFileDirectoryPath, mainModuleConfigPath);
}
artifacts.addAll(archivesArtifacts);
}
- } else if("test".equals(sourceSet.getName())) {
- final Set<File> testsArtifacts = externalProject.getArtifactsByConfiguration().get("tests");
- if (testsArtifacts != null) {
- artifacts.addAll(testsArtifacts);
+ }
+ else {
+ sourceSetData.setProductionModuleId(getInternalModuleName(gradleModule, "main"));
+ if ("test".equals(sourceSet.getName())) {
+ final Set<File> testsArtifacts = externalProject.getArtifactsByConfiguration().get("tests");
+ if (testsArtifacts != null) {
+ artifacts.addAll(testsArtifacts);
+ }
}
}
sourceSetData.setArtifacts(ContainerUtil.newArrayList(artifacts));
return mainModuleNode;
}
+ @NotNull
+ public String getInternalModuleName(@NotNull IdeaModule gradleModule, @NotNull String sourceSetName) {
+ return gradleModule.getName() + "_" + sourceSetName;
+ }
+
@Override
public void populateModuleExtraModels(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule) {
final BuildScriptClasspathModel buildScriptClasspathModel = resolverCtx.getExtraProject(gradleModule, BuildScriptClasspathModel.class);