package io.takari.maven.plugins.compile.jdt;
import static io.takari.maven.testing.TestResources.cp;
import static io.takari.maven.testing.TestResources.rm;
import static io.takari.maven.testing.TestResources.touch;
import java.io.File;
import org.apache.maven.plugin.MojoExecutionException;
import org.junit.Assert;
import org.junit.Test;
public class CompileJdtTest extends AbstractCompileJdtTest {
/**
* Asserts specified output exists and is not older than specified input
*/
protected static void assertBuildOutput(File basedir, String input, String output) {
File inputFile = new File(basedir, input);
File outputFile = new File(basedir, output);
Assert.assertTrue("output is older than input", outputFile.lastModified() >= inputFile.lastModified());
}
@Test
public void testBasic() throws Exception {
File basedir = resources.getBasedir("compile-jdt/basic");
// initial build
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class");
assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class");
assertBuildOutput(basedir, "src/main/java/basic/Basic2.java", "target/classes/basic/Basic2.class");
// no-change rebuild
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, new String[0]);
mojos.assertCarriedOverOutputs(basedir, "target/classes/basic/Basic1.class", "target/classes/basic/Basic2.class");
// one file changed
cp(basedir, "src/main/java/basic/Basic1.java-changed", "src/main/java/basic/Basic1.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/basic/Basic1.class");
assertBuildOutput(basedir, "src/main/java/basic/Basic1.java", "target/classes/basic/Basic1.class");
}
@Test
public void testBasic_timestampChangeRebuild() throws Exception {
File basedir = resources.getBasedir("compile-jdt/basic");
File classes = new File(basedir, "target/classes");
// initial build
mojos.compile(basedir);
mojos.assertBuildOutputs(classes, "basic/Basic1.class", "basic/Basic2.class");
// move back timestamp, round to 10s to accommodate filesystem timestamp rounding
long timestamp = System.currentTimeMillis() - 20000L;
timestamp = timestamp - (timestamp % 10000L);
new File(classes, "basic/Basic1.class").setLastModified(timestamp);
touch(basedir, "src/main/java/basic/Basic1.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(classes, "basic/Basic1.class");
// timestamp is the same if the file is the same
Assert.assertEquals(timestamp, new File(classes, "basic/Basic1.class").lastModified());
}
@Test
public void testSupertype() throws Exception {
File basedir = resources.getBasedir("compile-jdt/supertype");
// initial build
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class");
// non-structural change
cp(basedir, "src/main/java/supertype/SuperClass.java-comment", "src/main/java/supertype/SuperClass.java");
cp(basedir, "src/main/java/supertype/SuperInterface.java-comment", "src/main/java/supertype/SuperInterface.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class");
// superclass change
cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class");
}
@Test
public void testSupertype_superClassChangeDoesNotTriggerRebuildOfImplementedInterfaces() throws Exception {
File basedir = resources.getBasedir("compile-jdt/supertype");
// initial build
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class", "target/classes/supertype/SuperInterface.class");
// superclass insignificant change
cp(basedir, "src/main/java/supertype/SuperClass.java-methodBody", "src/main/java/supertype/SuperClass.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SuperClass.class");
// superclass significant change
cp(basedir, "src/main/java/supertype/SuperClass.java-member", "src/main/java/supertype/SuperClass.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/supertype/SubClass.class", "target/classes/supertype/SuperClass.class");
}
@Test
public void testCircular() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/circular"));
mojos.assertBuildOutputs(basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class");
cp(basedir, "src/main/java/circular/ClassA.java-changed", "src/main/java/circular/ClassA.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/circular/ClassA.class", "target/classes/circular/ClassB.class");
}
@Test
public void testReference() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/reference"));
mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class");
// no change rebuild
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, new String[0]);
Assert.assertTrue(new File(basedir, "target/classes/reference/Parameter.class").canRead());
Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead());
// insignificant change
cp(basedir, "src/main/java/reference/Parameter.java-comment", "src/main/java/reference/Parameter.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class");
Assert.assertTrue(new File(basedir, "target/classes/reference/Type.class").canRead());
// significant change
cp(basedir, "src/main/java/reference/Parameter.java-method", "src/main/java/reference/Parameter.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/reference/Parameter.class", "target/classes/reference/Type.class");
}
@Test
public void testMissing() throws Exception {
final String[] messages = {"ERROR Error.java [6:12] Missing cannot be resolved to a type", "ERROR Error.java [8:20] Missing cannot be resolved to a type"};
File basedir = resources.getBasedir("compile-jdt/missing");
try {
mojos.compile(basedir);
Assert.fail();
} catch (MojoExecutionException expected) {
// expected
}
mojos.assertBuildOutputs(basedir, "target/classes/missing/Other.class");
Assert.assertFalse(new File(basedir, "target/classes/missing/Error.class").exists());
mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages);
// no change rebuild
try {
mojos.compile(basedir);
Assert.fail();
} catch (MojoExecutionException expected) {
// expected
}
mojos.assertBuildOutputs(basedir, new String[0]);
mojos.assertMessages(basedir, "src/main/java/missing/Error.java", messages);
// fix the problem
cp(basedir, "src/main/java/missing/Missing.java-missing", "src/main/java/missing/Missing.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class");
// reintroduce the problem
rm(basedir, "src/main/java/missing/Missing.java");
try {
mojos.compile(basedir);
Assert.fail();
} catch (MojoExecutionException expected) {
// expected
}
mojos.assertDeletedOutputs(basedir, "target/classes/missing/Error.class", "target/classes/missing/Missing.class");
}
@Test
public void testMultifile() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/multifile"));
mojos.assertBuildOutputs(basedir, "target/classes/multifile/ClassA.class", "target/classes/multifile/ClassB.class", "target/classes/multifile/ClassB$Nested.class");
touch(basedir, "src/main/java/multifile/ClassA.java");
cp(basedir, "src/main/java/multifile/ClassB.java-changed", "src/main/java/multifile/ClassB.java");
try {
mojos.compile(basedir);
Assert.fail();
} catch (MojoExecutionException expected) {
// expected
}
// TODO assert expected error messages
mojos.assertBuildOutputs(basedir, "target/classes/multifile/ClassB.class");
mojos.assertDeletedOutputs(basedir, "target/classes/multifile/ClassA.class", "target/classes/multifile/ClassB$Nested.class");
}
@Test
public void testSecondaryType() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/secondary-type"));
File classes = new File(basedir, "target/classes");
mojos.assertBuildOutputs(classes //
, "secondary/Primary.class" //
, "secondary/Secondary.class" //
, "secondary/SecondarySubclass.class" //
, "secondary/SecondarySubclassClient.class");
touch(basedir, "src/main/java/secondary/SecondarySubclassClient.java");
mojos.compile(basedir);
mojos.assertBuildOutputs(classes //
, "secondary/SecondarySubclassClient.class");
}
@Test
public void testRemovedTypes() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/removed-types"));
File classes = new File(basedir, "target/classes");
mojos.assertBuildOutputs(classes //
, "removed/A.class" //
, "removed/B.class" //
, "removed/Dummy.class");
rm(basedir, "src/main/java/removed/A.java");
rm(basedir, "src/main/java/removed/B.java");
mojos.compile(basedir);
mojos.assertDeletedOutputs(classes //
, "removed/A.class" //
, "removed/B.class");
}
@Test
public void testRemoveSecondaryType() throws Exception {
File basedir = mojos.compile(resources.getBasedir("compile-jdt/remove-secondary-type"));
File classes = new File(basedir, "target/classes");
mojos.assertBuildOutputs(classes //
, "secondary/A.class" //
, "secondary/B.class" //
, "secondary/ASecondary.class");
cp(basedir, "src/main/java/secondary/A.java-changed", "src/main/java/secondary/A.java");
try {
mojos.compile(basedir);
Assert.fail();
} catch (MojoExecutionException expected) {
// TODO assert error message
}
mojos.assertBuildOutputs(classes //
, "secondary/A.class");
mojos.assertDeletedOutputs(classes //
, "secondary/B.class" //
, "secondary/ASecondary.class");
}
}