diff --git a/jps/antLayout/src/jetbrains/antlayout/antlib.xml b/jps/antLayout/src/jetbrains/antlayout/antlib.xml
index 3ef82b992989..bc7053c450e8 100755
--- a/jps/antLayout/src/jetbrains/antlayout/antlib.xml
+++ b/jps/antLayout/src/jetbrains/antlayout/antlib.xml
@@ -7,4 +7,5 @@
+
\ No newline at end of file
diff --git a/jps/antLayout/src/jetbrains/antlayout/datatypes/Container.java b/jps/antLayout/src/jetbrains/antlayout/datatypes/Container.java
index 517d3a37a5d1..d2b487512025 100755
--- a/jps/antLayout/src/jetbrains/antlayout/datatypes/Container.java
+++ b/jps/antLayout/src/jetbrains/antlayout/datatypes/Container.java
@@ -60,6 +60,10 @@ public abstract class Container extends Content {
children.add(new FileSetContainer(module));
}
+ public void addModuleTests(IdeaModuleTests module) {
+ children.add(new FileSetContainer(module));
+ }
+
public List getChildren() {
return children;
}
@@ -100,6 +104,9 @@ public abstract class Container extends Content {
if (set instanceof IdeaModule) {
return new IdeaModule((IdeaModule) set);
}
+ if (set instanceof IdeaModuleTests) {
+ return new IdeaModuleTests((IdeaModuleTests) set);
+ }
if (set instanceof ZipFileSet) {
return new LayoutFileSet((ZipFileSet) set.clone());
} else {
diff --git a/jps/antLayout/src/jetbrains/antlayout/datatypes/FileSetContainer.java b/jps/antLayout/src/jetbrains/antlayout/datatypes/FileSetContainer.java
index 07468b91c13b..8c872813cab2 100644
--- a/jps/antLayout/src/jetbrains/antlayout/datatypes/FileSetContainer.java
+++ b/jps/antLayout/src/jetbrains/antlayout/datatypes/FileSetContainer.java
@@ -27,8 +27,8 @@ public class FileSetContainer extends Content {
@Override
public void validateArguments() throws BuildException {
- if (fileSet instanceof IdeaModule) {
- ((IdeaModule) fileSet).validateArguments();
+ if (fileSet instanceof IdeaModuleBase) {
+ ((IdeaModuleBase) fileSet).validateArguments();
}
}
}
diff --git a/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModule.java b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModule.java
index 7435db1053d7..5f2fc37938f1 100755
--- a/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModule.java
+++ b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModule.java
@@ -1,65 +1,23 @@
-package jetbrains.antlayout.datatypes;
-
-import jetbrains.antlayout.util.LayoutFileSet;
-import org.apache.tools.ant.BuildException;
-
-import java.io.File;
-
-/**
- * @author max
- */
-public class IdeaModule extends LayoutFileSet {
- private String name;
-
- public IdeaModule() {
- }
-
- public IdeaModule(IdeaModule fileset) {
- super(fileset);
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- setDir(getMainOutput());
- }
-
- private File getMainOutput() {
- String common = getProject().getProperty("modules.output");
- if (common != null) {
- return new File(new File(common), "production/" + name);
- }
-
- String adhoc = getProject().getProperty("module." + name +".output.main");
- return adhoc != null ? new File(adhoc) : null;
- }
-
- public void validateArguments() throws BuildException {
- if (name == null) {
- throw new BuildException("name attribute must be specified for moduleentry");
- }
-
- File main = getMainOutput();
-
- if (main == null || !main.exists()) {
- throw new BuildException("No production output found for module " + name +
- ". Either modules.output property references project output that doesn't contain this module or " +
- "module." + name +".output.main is not defined or references non-existing directory.");
- }
- }
-
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- IdeaModule that = (IdeaModule) o;
- return getDir(getProject()).equals(that.getDir(getProject()));
- }
-
- public int hashCode() {
- return getDir(getProject()).hashCode();
- }
-}
+package jetbrains.antlayout.datatypes;
+
+import java.io.File;
+
+/**
+ * @author max
+ */
+public class IdeaModule extends IdeaModuleBase {
+ public IdeaModule() {
+ }
+
+ public IdeaModule(IdeaModule fileset) {
+ super(fileset);
+ }
+
+ protected String getKind() {
+ return "production";
+ }
+
+ protected String getOutputDirProperty() {
+ return "module." + getName() + ".output.main";
+ }
+}
diff --git a/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleBase.java b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleBase.java
new file mode 100644
index 000000000000..ca5becf998cd
--- /dev/null
+++ b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleBase.java
@@ -0,0 +1,70 @@
+package jetbrains.antlayout.datatypes;
+
+import jetbrains.antlayout.util.LayoutFileSet;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.ZipFileSet;
+
+import java.io.File;
+
+/**
+ * @author nik
+ */
+public abstract class IdeaModuleBase extends LayoutFileSet {
+ private String name;
+
+ protected IdeaModuleBase() {
+ }
+
+ public IdeaModuleBase(ZipFileSet fileset) {
+ super(fileset);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ setDir(getOutputDir());
+ }
+
+ protected File getOutputDir() {
+ String common = getProject().getProperty("modules.output");
+ if (common != null) {
+ return new File(new File(common), getKind() + "/" + getName());
+ }
+
+ String adhoc = getProject().getProperty(getOutputDirProperty());
+ return adhoc != null ? new File(adhoc) : null;
+ }
+
+ public void validateArguments() throws BuildException {
+ if (name == null) {
+ throw new BuildException("name attribute must be specified for module entry");
+ }
+
+ File outputDir = getOutputDir();
+
+ if (outputDir == null || !outputDir.exists()) {
+ throw new BuildException("No " + getKind() + " output found for module " + name +
+ ". Either modules.output property references project output that doesn't contain this module or " +
+ getOutputDirProperty() + " is not defined or references non-existing directory.");
+ }
+ }
+
+ protected abstract String getOutputDirProperty();
+
+ protected abstract String getKind();
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IdeaModule that = (IdeaModule) o;
+ return getDir(getProject()).equals(that.getDir(getProject()));
+ }
+
+ public int hashCode() {
+ return getDir(getProject()).hashCode();
+ }
+}
diff --git a/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleTests.java b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleTests.java
new file mode 100644
index 000000000000..10abc63abd64
--- /dev/null
+++ b/jps/antLayout/src/jetbrains/antlayout/datatypes/IdeaModuleTests.java
@@ -0,0 +1,27 @@
+package jetbrains.antlayout.datatypes;
+
+import org.apache.tools.ant.types.ZipFileSet;
+
+import java.io.File;
+
+/**
+ * @author nik
+ */
+public class IdeaModuleTests extends IdeaModuleBase {
+ public IdeaModuleTests() {
+ }
+
+ public IdeaModuleTests(ZipFileSet fileset) {
+ super(fileset);
+ }
+
+ @Override
+ protected String getOutputDirProperty() {
+ return "module." + getName() + ".output.test";
+ }
+
+ @Override
+ protected String getKind() {
+ return "test";
+ }
+}
diff --git a/jps/antLayout/src/jetbrains/antlayout/tasks/LayoutTask.java b/jps/antLayout/src/jetbrains/antlayout/tasks/LayoutTask.java
index 62c7557156c8..2ccb269349a8 100755
--- a/jps/antLayout/src/jetbrains/antlayout/tasks/LayoutTask.java
+++ b/jps/antLayout/src/jetbrains/antlayout/tasks/LayoutTask.java
@@ -41,6 +41,10 @@ public class LayoutTask extends Task {
containers.add(new FileSetContainer(module));
}
+ public void addModuleTests(IdeaModuleTests module) {
+ containers.add(new FileSetContainer(module));
+ }
+
public void addFileset(FileSet fileSet) {
containers.add(new FileSetContainer(fileSet));
}
diff --git a/jps/src/org/jetbrains/jps/Jps.groovy b/jps/src/org/jetbrains/jps/Jps.groovy
index 5d551ffe4774..81154b243375 100644
--- a/jps/src/org/jetbrains/jps/Jps.groovy
+++ b/jps/src/org/jetbrains/jps/Jps.groovy
@@ -40,7 +40,7 @@ final class Jps {
def old = binding.getVariable("module")
def layoutInfo = new LayoutInfo()
- ["module", "zip", "dir"].each {tag ->
+ ["module", "moduleTests", "zip", "dir"].each {tag ->
binding.setVariable(tag, {Object[] args ->
if (args.length == 1) {
binding.ant."$tag"(name: args[0])
diff --git a/jps/src/org/jetbrains/jps/artifacts/LayoutElement.groovy b/jps/src/org/jetbrains/jps/artifacts/LayoutElement.groovy
index aaa534c25d26..d85c2d6015c8 100644
--- a/jps/src/org/jetbrains/jps/artifacts/LayoutElement.groovy
+++ b/jps/src/org/jetbrains/jps/artifacts/LayoutElement.groovy
@@ -1,9 +1,8 @@
package org.jetbrains.jps.artifacts
import org.jetbrains.jps.Project
-import org.jetbrains.jps.Library
-/**
+ /**
* @author nik
*/
abstract class LayoutElement {
@@ -58,3 +57,11 @@ class ModuleOutputElement extends LayoutElement {
project.binding.module.call(moduleName)
}
}
+
+class ModuleTestOutputElement extends LayoutElement {
+ String moduleName
+
+ def build(Project project) {
+ project.binding.moduleTests.call(moduleName)
+ }
+}
diff --git a/jps/src/org/jetbrains/jps/idea/ArtifactLoader.groovy b/jps/src/org/jetbrains/jps/idea/ArtifactLoader.groovy
index 30a63bd99927..2084764e08a7 100644
--- a/jps/src/org/jetbrains/jps/idea/ArtifactLoader.groovy
+++ b/jps/src/org/jetbrains/jps/idea/ArtifactLoader.groovy
@@ -58,6 +58,12 @@ class ArtifactLoader {
project.error("Unknown module '$name' in '$artifactName' artifact")
}
return new ModuleOutputElement(moduleName: name);
+ case "module-test-output":
+ def name = tag."@name"
+ if (project.modules[name] == null) {
+ project.error("Unknown module '$name' in '$artifactName' artifact")
+ }
+ return new ModuleTestOutputElement(moduleName: name);
case "library":
return new LibraryFilesElement(libraryLevel: tag."@level", libraryName: tag."@name", moduleName: tag."@module-name");
}
diff --git a/jps/testData/moduleTestOutput/moduleTestOutput.iml b/jps/testData/moduleTestOutput/moduleTestOutput.iml
new file mode 100644
index 000000000000..26c800ce3109
--- /dev/null
+++ b/jps/testData/moduleTestOutput/moduleTestOutput.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps/testData/moduleTestOutput/moduleTestOutput.ipr b/jps/testData/moduleTestOutput/moduleTestOutput.ipr
new file mode 100644
index 000000000000..3bbd2eb52f70
--- /dev/null
+++ b/jps/testData/moduleTestOutput/moduleTestOutput.ipr
@@ -0,0 +1,20 @@
+
+
+
+
+ $PROJECT_DIR$/out/artifacts/tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jps/testData/moduleTestOutput/src/MyClass.java b/jps/testData/moduleTestOutput/src/MyClass.java
new file mode 100644
index 000000000000..bef6c0e59445
--- /dev/null
+++ b/jps/testData/moduleTestOutput/src/MyClass.java
@@ -0,0 +1,9 @@
+/**
+ * Created by IntelliJ IDEA.
+ * User: nik
+ * Date: 4/5/11
+ * Time: 4:39 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MyClass {
+}
diff --git a/jps/testData/moduleTestOutput/testSrc/MyTest.java b/jps/testData/moduleTestOutput/testSrc/MyTest.java
new file mode 100644
index 000000000000..a301f651cc77
--- /dev/null
+++ b/jps/testData/moduleTestOutput/testSrc/MyTest.java
@@ -0,0 +1,9 @@
+/**
+ * Created by IntelliJ IDEA.
+ * User: nik
+ * Date: 4/5/11
+ * Time: 4:39 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MyTest {
+}
diff --git a/jps/testSrc/org/jetbrains/jps/ModuleTestOutputElementTest.groovy b/jps/testSrc/org/jetbrains/jps/ModuleTestOutputElementTest.groovy
new file mode 100644
index 000000000000..df0aeb1e8767
--- /dev/null
+++ b/jps/testSrc/org/jetbrains/jps/ModuleTestOutputElementTest.groovy
@@ -0,0 +1,26 @@
+package org.jetbrains.jps
+
+/**
+ * @author nik
+ */
+class ModuleTestOutputElementTest extends JpsBuildTestCase {
+ public void test() {
+ doTest("testData/moduleTestOutput/moduleTestOutput.ipr", {}, {
+ dir("artifacts") {
+ dir("tests") {
+ file("MyTest.class")
+ }
+ }
+ dir("production") {
+ dir("moduleTestOutput") {
+ file("MyClass.class")
+ }
+ }
+ dir("test") {
+ dir("moduleTestOutput") {
+ file("MyTest.class")
+ }
+ }
+ })
+ }
+}