Browse Source

MultiIncrementalSupport: the test harness for managing Ajde interactions and several multi incremental tests.

tags/PRE_ANDY
aclement 19 years ago
parent
commit
175d006555

+ 2
- 0
tests/src/org/aspectj/systemtest/AllTests.java View File

@@ -19,6 +19,7 @@ import org.aspectj.systemtest.base.BaseTests;
import org.aspectj.systemtest.design.DesignTests;
import org.aspectj.systemtest.incremental.IncrementalTests;
import org.aspectj.systemtest.incremental.model.IncrementalModelTests;
import org.aspectj.systemtest.incremental.tools.MultiProjectIncrementalTests;
import org.aspectj.systemtest.inpath.InPathTests;
import org.aspectj.systemtest.options.OptionsTests;
import org.aspectj.systemtest.pre10x.AjcPre10xTests;
@@ -45,6 +46,7 @@ public class AllTests {
suite.addTest(BaseTests.suite());
suite.addTest(DesignTests.suite());
suite.addTest(IncrementalTests.suite());
suite.addTestSuite(MultiProjectIncrementalTests.class);
suite.addTest(IncrementalModelTests.suite());
//suite.addTest(KnownLimitationsTests.class);
suite.addTest(OptionsTests.suite());

+ 709
- 0
tests/src/org/aspectj/systemtest/incremental/tools/AjdeInteractionTestbed.java View File

@@ -0,0 +1,709 @@
/* *******************************************************************
* Copyright (c) 2005 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andy Clement initial implementation
* ******************************************************************/
package org.aspectj.systemtest.incremental.tools;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import junit.framework.AssertionFailedError;
import junit.framework.TestCase;

import org.aspectj.ajde.Ajde;
import org.aspectj.ajde.BuildOptionsAdapter;
import org.aspectj.ajde.BuildProgressMonitor;
import org.aspectj.ajde.ErrorHandler;
import org.aspectj.ajde.ProjectPropertiesAdapter;
import org.aspectj.ajde.TaskListManager;
import org.aspectj.ajdt.internal.core.builder.AjState;
import org.aspectj.ajdt.internal.core.builder.IStateListener;
import org.aspectj.ajdt.internal.core.builder.IncrementalStateManager;
import org.aspectj.asm.AsmManager;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.IMessage.Kind;

/**
* This class uses Ajde in the same way that an IDE (e.g. AJDT) does.
*
* The build is driven through 'build(projectName,configFile)' but the
* build can be configured by the methods beginning 'configure***'.
* Information about what happened during a build is accessible
* through the get*, was*, print* public methods...
*
* There are many methods across the multiple listeners that communicate
* info with Ajde - not all are implemented. Those that are are
* task tagged DOESSOMETHING :)
*/
public class AjdeInteractionTestbed extends TestCase {

public static boolean VERBOSE = false; // do you want the gory details?
public final static String testdataSrcDir = "../tests/multiIncremental";
protected static File sandboxDir;
private static final String SANDBOX_NAME = "ajcSandbox";
private static boolean buildModel;
// Methods for configuring the build
public static void configureBuildStructureModel(boolean b) { buildModel = b;}
public static void configureNewProjectDependency(String fromProject, String projectItDependsOn) {
MyProjectPropertiesAdapter.addDependancy(fromProject,projectItDependsOn);
}
// End of methods for configuring the build
protected File getWorkingDir() { return sandboxDir; }
protected void setUp() throws Exception {
super.setUp();
// Create a sandbox in which to work
createEmptySandbox();
}
/** Drives a build */
public boolean build(String projectName,String configFile) {
return AjdeManager.build(projectName,configFile);
}

/** Looks after communicating with the singleton Ajde instance */
public static class AjdeManager {
static {
Ajde.init(null,
MyTaskListManager.getInstance(),
MyBuildProgressMonitor.getInstance(),
MyProjectPropertiesAdapter.getInstance(),
MyBuildOptionsAdapter.getInstance(),
null,null,
MyErrorHandler.getInstance());

MyStateListener sl = MyStateListener.getInstance();
AjState.stateListener = sl;
}

/**
* Builds a specified project using a specified config file. Subsequent
* calls to build the same project should result in incremental builds.
*/
private static boolean build(String projectName,String configFile) {
pause(1000); // delay to allow previous runs build stamps to be OK
lognoln("Building project '"+projectName+"'");
// Ajde.getDefault().enableLogging(System.out);
//Ajde.getDefault().getBuildManager().setReportInfoMessages(true);
// Configure the necessary providers and listeners for this compile
MyBuildProgressMonitor.reset();
MyTaskListManager.reset();
MyStateListener.reset();
MyProjectPropertiesAdapter.setActiveProject(projectName);
AsmManager.attemptIncrementalModelRepairs=true;
IncrementalStateManager.recordIncrementalStates=true;
Ajde.getDefault().getBuildManager().setBuildModelMode(buildModel);
// Do the compile
Ajde.getDefault().getBuildManager().build(getFile(projectName,configFile));
// Wait for it to complete
while (!MyBuildProgressMonitor.hasFinished()) {
lognoln(".");
pause(100);
}
log("");
// What happened?
if (MyTaskListManager.hasErrorMessages()) {
System.err.println("Build errors:");
for (Iterator iter = MyTaskListManager.getErrorMessages().iterator(); iter.hasNext();) {
IMessage element = (IMessage) iter.next();
System.err.println(element);
}
System.err.println("---------");
}
log("Build finished, time taken = "+MyBuildProgressMonitor.getTimeTaken()+"ms");
return true;
}
private static void pause(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ie) {}
}
// public static boolean lastCompileDefaultedToBatch() {
// return MyTaskListManager.defaultedToBatch();
// }
}

// Methods for querying what happened during a build and accessing information
// about the build:
/**
* Helper method for dumping info about which files were compiled and
* woven during the last build.
*/
public String printCompiledAndWovenFiles() {
StringBuffer sb = new StringBuffer();
if (getCompiledFiles().size()==0 && getWovenClasses().size()==0)
sb.append("No files were compiled or woven\n");
for (Iterator iter = getCompiledFiles().iterator(); iter.hasNext();) {
Object element = (Object) iter.next();
sb.append("compiled: "+element+"\n");
}
for (Iterator iter = getWovenClasses().iterator(); iter.hasNext();) {
Object element = (Object) iter.next();
sb.append("woven: "+element+"\n");
}
return sb.toString();
}
/**
* Summary report on what happened in the most recent build
*/
public void printBuildReport() {
System.out.println("\n============== BUILD REPORT =================");
System.out.println("Build took: "+getTimeTakenForBuild()+"ms");
List compiled=getCompiledFiles();
System.out.println("Compiled: "+compiled.size()+" files");
for (Iterator iter = compiled.iterator(); iter.hasNext();) {
System.out.println(" :"+iter.next());
}
List woven=getWovenClasses();
System.out.println("Wove: "+woven.size()+" files");
for (Iterator iter = woven.iterator(); iter.hasNext();) {
System.out.println(" :"+iter.next());
}
if (wasFullBuild()) System.out.println("It was a batch (full) build");
System.out.println("=============================================");
}
public boolean wasFullBuild() {
return MyStateListener.wasFullBuild();
}

public long getTimeTakenForBuild() {
return MyBuildProgressMonitor.getTimeTaken();
}
public List getCompiledFiles() {
return MyBuildProgressMonitor.getCompiledFiles();
}

public List getWovenClasses() {
return MyBuildProgressMonitor.getWovenClasses();
}
// Infrastructure below here
private void createEmptySandbox() {
String os = System.getProperty("os.name");
File tempDir = null;
// AMC - I did this rather than use the JDK default as I hate having to go look
// in c:\documents and settings\......... for the results of a failed test.
if (os.startsWith("Windows")) {
tempDir = new File("C:\\temp");
if (!tempDir.exists()) {tempDir.mkdir();}
} else {
tempDir = new File("/tmp");
}
File sandboxRoot = new File(tempDir,SANDBOX_NAME);
if (!sandboxRoot.exists()) {
sandboxRoot.mkdir();
}

org.aspectj.util.FileUtil.deleteContents(sandboxRoot);

try {
sandboxDir = File.createTempFile("ajcTest",".tmp",sandboxRoot);
sandboxDir.delete();
sandboxDir.mkdir();
} catch (IOException ioEx) {
throw new AssertionFailedError("Unable to create sandbox directory for test");
}
}
private static void log(String msg) {
if (VERBOSE) System.out.println(msg);
}
private static void lognoln(String msg) {
if (VERBOSE) System.out.print(msg);
}
/** Return the *full* path to this file which is taken relative to the project dir*/
protected static String getFile(String projectName, String path) {
return new File(sandboxDir,projectName+File.separatorChar + path).getAbsolutePath();
}

// Helper classes that communicate with Ajde
static class MyErrorHandler implements ErrorHandler {
static MyErrorHandler _instance = new MyErrorHandler();
private MyErrorHandler() {}
public static ErrorHandler getInstance() {
return _instance;
}

public void handleWarning(String message) {
log("ErrorHandler.handleWarning("+message+")");
}

public void handleError(String message) {
log("ErrorHandler.handleWarning("+message+")");
}

public void handleError(String message, Throwable t) {
log("ErrorHandler.handleError("+message+","+t+")");
if (VERBOSE) t.printStackTrace();
}
}
// -----------------
static class MyProjectPropertiesAdapter implements ProjectPropertiesAdapter {
private final static boolean VERBOSE = false;

static MyProjectPropertiesAdapter _instance = new MyProjectPropertiesAdapter();
private MyProjectPropertiesAdapter() {}
public static ProjectPropertiesAdapter getInstance() {
return _instance;
}
private String projectName = null;
public static void setActiveProject(String n) {
_instance.projectName = n;
}

private static Hashtable dependants = new Hashtable();
public static void addDependancy(String project, String projectItDependsOn) {
List l = (List)dependants.get(project);
if (l == null) {
List ps = new ArrayList();
ps.add(projectItDependsOn);
dependants.put(project,ps);
} else {
l.add(projectItDependsOn);
}
}

// interface impl below
// DOESSOMETHING
public String getProjectName() {
log("MyProjectProperties.getProjectName() [returning "+projectName+"]");
return projectName;
}

// DOESSOMETHING
public String getRootProjectDir() {
String dir = testdataSrcDir+File.separatorChar+projectName;
log("MyProjectProperties.getRootProjectDir() [returning "+dir+"]");
return dir;
}

public List getBuildConfigFiles() {
log("MyProjectProperties.getBuildConfigFiles()");
return null;
}

public String getDefaultBuildConfigFile() {
log("MyProjectProperties.getDefaultBuildConfigFile()");
return null;
}

public String getLastActiveBuildConfigFile() {
log("MyProjectProperties.getLastActiveBuildConfigFile()");
return null;
}

public List getProjectSourceFiles() {
log("MyProjectProperties.getProjectSourceFiles()");
return null;
}

public String getProjectSourcePath() {
log("MyProjectProperties.getProjectSourcePath()");
return null;
}

// DOESSOMETHING
public String getClasspath() {
log("MyProjectProperties.getClasspath()");
String cp =
new File(testdataSrcDir) + File.pathSeparator +
System.getProperty("sun.boot.class.path") + File.pathSeparator +
"../runtime/bin" + File.pathSeparator +
System.getProperty("aspectjrt.path");
// look at dependant projects
List projects = (List)dependants.get(projectName);
if (projects!=null) {
for (Iterator iter = projects.iterator(); iter.hasNext();) {
cp = getFile((String)iter.next(),"bin")+File.pathSeparator+cp;
}
}
//System.err.println("For project "+projectName+" getClasspath() returning "+cp);
return cp;
}
public String getOutputPath() {
String dir = getFile(projectName,"bin");
log("MyProjectProperties.getOutputPath() [returning "+dir+"]");
return dir;
}

public String getBootClasspath() {
log("MyProjectProperties.getBootClasspath()");
return null;
}

public String getClassToExecute() {
log("MyProjectProperties.getClassToExecute()");
return null;
}

public String getExecutionArgs() {
log("MyProjectProperties.getExecutionArgs()");
return null;
}

public String getVmArgs() {
log("MyProjectProperties.getVmArgs()");
return null;
}

public Set getInJars() {
log("MyProjectProperties.getInJars()");
return null;
}

public Set getInpath() {
log("MyProjectProperties.getInPath()");
return null;
}

public Map getSourcePathResources() {
log("MyProjectProperties.getSourcePathResources()");
return null;
}

public String getOutJar() {
log("MyProjectProperties.getOutJar()");
return null;
}

public Set getSourceRoots() {
log("MyProjectProperties.getSourceRoots()");
return null;
}

public Set getAspectPath() {
log("MyProjectProperties.getAspectPath()");
return null;
}
public static void log(String s) {
if (VERBOSE) System.out.println(s);
}
}
// -----------------------
static class MyBuildProgressMonitor implements BuildProgressMonitor {

public static boolean VERBOSE = false;
private static MyBuildProgressMonitor _instance = new MyBuildProgressMonitor();
private MyBuildProgressMonitor() {}
private List compiledFiles=new ArrayList();
private List wovenClasses=new ArrayList();

public static BuildProgressMonitor getInstance() {
return _instance;
}
public static void reset() {
_instance.finished = false;
_instance.compiledFiles.clear();
_instance.wovenClasses.clear();
}
public static boolean hasFinished() {
return _instance.finished;
}
public static List getCompiledFiles() { return _instance.compiledFiles;}
public static List getWovenClasses() { return _instance.wovenClasses; }
//---
private long starttime = 0;
private long totaltimetaken = 0;
private boolean finished = false;

public void start(String configFile) {
starttime = System.currentTimeMillis();
log("BuildProgressMonitor.start("+configFile+")");
}

public void setProgressText(String text) {
log("BuildProgressMonitor.setProgressText("+text+")");
if (text.startsWith("compiled: ")) {
compiledFiles.add(text.substring(10));
} else if (text.startsWith("woven class ")) {
wovenClasses.add(text.substring(12));
} else if (text.startsWith("woven aspect ")) {
wovenClasses.add(text.substring(13));
}
}

public void setProgressBarVal(int newVal) {
log("BuildProgressMonitor.setProgressBarVal("+newVal+")");
}

public void incrementProgressBarVal() {
log("BuildProgressMonitor.incrementProgressBarVal()");
}

public void setProgressBarMax(int maxVal) {
log("BuildProgressMonitor.setProgressBarMax("+maxVal+")");
}

public int getProgressBarMax() {
log("BuildProgressMonitor.getProgressBarMax() [returns 100]");
return 100;
}

public void finish() {
log("BuildProgressMonitor.finish()");
_instance.finished=true;
_instance.totaltimetaken=(System.currentTimeMillis()-starttime);
}
public static long getTimeTaken() {
return _instance.totaltimetaken;
}
public static void log(String s) {
if (VERBOSE) System.out.println(s);
}

}
// ----
static class MyTaskListManager implements TaskListManager {

private static final String CANT_BUILD_INCREMENTAL_INDICATION = "Unable to perform incremental build";
private static final String DOING_BATCH_BUILD_INDICATION = "Performing batch build for config";
private final static boolean VERBOSE = false;
static MyTaskListManager _instance = new MyTaskListManager();
private MyTaskListManager() {}
private boolean receivedNonIncrementalBuildMessage = false;
private boolean receivedBatchBuildMessage = false;
private List errorMessages = new ArrayList();
public static void reset() {
_instance.receivedNonIncrementalBuildMessage=false;
_instance.receivedBatchBuildMessage=false;
_instance.errorMessages.clear();
}
// public static boolean defaultedToBatch() {
// return _instance.receivedNonIncrementalBuildMessage;
// }
//
// public static boolean didBatchBuild() {
// return _instance.receivedBatchBuildMessage;
// }
public static boolean hasErrorMessages() {
return !_instance.errorMessages.isEmpty();
}
public static List/*IMessage*/ getErrorMessages() {
return _instance.errorMessages;
}
public static TaskListManager getInstance() {
return _instance;
}

public void addSourcelineTask(String message, ISourceLocation sourceLocation, Kind kind) {
log("TaskListManager.addSourcelineTask("+message+","+sourceLocation+","+kind+")");
}

// DOESSOMETHING
public void addSourcelineTask(IMessage message) {
// if (message.getKind()==IMessage.INFO) {
// if (message.getMessage().startsWith(CANT_BUILD_INCREMENTAL_INDICATION)) _instance.receivedNonIncrementalBuildMessage=true;
// if (message.getMessage().startsWith(DOING_BATCH_BUILD_INDICATION)) _instance.receivedBatchBuildMessage=true;
// }
if (message.getKind()==IMessage.ERROR) {
errorMessages.add(message);
}
log("TaskListManager.addSourcelineTask("+message+")");
}

public boolean hasWarning() {
log("TaskListManager.hasWarning() [returning false]");
return false;
}

public void addProjectTask(String message, Kind kind) {
log("TaskListManager.addProjectTask("+message+","+kind+")");
}

public void clearTasks() {
log("TaskListManager.clearTasks()");
}
public static void log(String s) {
if (VERBOSE) System.out.println(s);
}
}

// ----
static class MyBuildOptionsAdapter implements BuildOptionsAdapter {
static MyBuildOptionsAdapter _instance = new MyBuildOptionsAdapter();
private MyBuildOptionsAdapter() {}
public static BuildOptionsAdapter getInstance() {
return _instance;
}

public Map getJavaOptionsMap() {
return null;
}

public boolean getUseJavacMode() {
return false;
}

public String getWorkingOutputPath() {
return null;
}

public boolean getPreprocessMode() {
return false;
}

public String getCharacterEncoding() {
return null;
}

public boolean getSourceOnePointFourMode() {
return false;
}

// DOESSOMETHING
public boolean getIncrementalMode() {
return true;
}

public boolean getLenientSpecMode() {
return false;
}

public boolean getStrictSpecMode() {
return false;
}

public boolean getPortingMode() {
return false;
}

public String getNonStandardOptions() {
return null;
}

public String getComplianceLevel() {
return null;
}

public String getSourceCompatibilityLevel() {
return null;
}

public Set getWarnings() {
return null;
}

public Set getDebugLevel() {
return null;
}

public boolean getNoImportError() {
return false;
}

public boolean getPreserveAllLocals() {
return false;
}
}
static class MyStateListener implements IStateListener {
private static MyStateListener _instance = new MyStateListener();
private MyStateListener() {reset();}
public static MyStateListener getInstance() { return _instance;}
public static boolean informedAboutKindOfBuild;
public static boolean fullBuildOccurred;
public static void reset() {
informedAboutKindOfBuild=false;
fullBuildOccurred=false;
}
public boolean pathChange = false;
public void pathChangeDetected() {pathChange = true;}
public void aboutToCompareClasspaths(List oldClasspath, List newClasspath) {}
public void detectedClassChangeInThisDir(File f) {}
public void buildSuccessful(boolean wasFullBuild) {
informedAboutKindOfBuild= true;
fullBuildOccurred=wasFullBuild;
}
public static boolean wasFullBuild() {
if (!informedAboutKindOfBuild) throw new RuntimeException("I never heard about what kind of build it was!!");
return fullBuildOccurred;
}
};
}

+ 424
- 0
tests/src/org/aspectj/systemtest/incremental/tools/MultiProjectIncrementalTests.java View File

@@ -0,0 +1,424 @@
/* *******************************************************************
* Copyright (c) 2005 Contributors.
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://eclipse.org/legal/epl-v10.html
*
* Contributors:
* Andy Clement initial implementation
* ******************************************************************/
package org.aspectj.systemtest.incremental.tools;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.aspectj.ajdt.internal.core.builder.AjState;
import org.aspectj.ajdt.internal.core.builder.IncrementalStateManager;
import org.aspectj.asm.AsmManager;
import org.aspectj.asm.IProgramElement;
import org.aspectj.testing.util.FileUtil;

/**
* The superclass knows all about talking through Ajde to the compiler.
* The superclass isn't in charge of knowing how to simulate overlays
* for incremental builds, that is in here. As is the ability to
* generate valid build configs based on a directory structure. To
* support this we just need access to a sandbox directory - this
* sandbox is managed by the superclass (it only assumes all builds occur
* in <sandboxDir>/<projectName>/ )
*
* The idea is you can initialize multiple projects in the sandbox and
* they can all be built independently, hopefully exploiting
* incremental compilation. Between builds you can alter the contents
* of a project using the alter() method that overlays some set of
* new files onto the current set (adding new files/changing existing
* ones) - you can then drive a new build and check it behaves as
* expected.
*/
public class MultiProjectIncrementalTests extends AjdeInteractionTestbed {

private static boolean VERBOSE = false;
protected void setUp() throws Exception {
super.setUp();
}
// Compile a single simple project
public void testTheBasics() {
initialiseProject("P1");
build("P1"); // This first build will be batch
build("P1");
checkWasntFullBuild();
checkCompileWeaveCount(0,0);
}
// Make simple changes to a project, adding a class
public void testSimpleChanges() {
initialiseProject("P1");
build("P1"); // This first build will be batch
alter("P1","inc1"); // adds a single class
build("P1");
checkCompileWeaveCount(1,-1);
build("P1");
checkCompileWeaveCount(0,-1);
}
// Make simple changes to a project, adding a class and an aspect
public void testAddingAnAspect() {
initialiseProject("P1");
build("P1");
alter("P1","inc1"); // adds a class
alter("P1","inc2"); // adds an aspect
build("P1");
long timeTakenForFullBuildAndWeave = getTimeTakenForBuild();
checkWasntFullBuild();
checkCompileWeaveCount(2,3);
build("P1");
long timeTakenForSimpleIncBuild = getTimeTakenForBuild();
// I don't think this test will have timing issues as the times should be *RADICALLY* different
// On my config, first build time is 2093ms and the second is 30ms
assertTrue("Should not take longer for the trivial incremental build! first="+timeTakenForFullBuildAndWeave+
"ms second="+timeTakenForSimpleIncBuild+"ms",
timeTakenForSimpleIncBuild<timeTakenForFullBuildAndWeave);
}
public void testBuildingTwoProjectsInTurns() {
configureBuildStructureModel(true);
initialiseProject("P1");
initialiseProject("P2");
build("P1");
build("P2");
build("P1");
checkWasntFullBuild();
build("P2");
checkWasntFullBuild();
}
/**
* In order for this next test to run, I had to move the weaver/world pair we keep in the
* AjBuildManager instance down into the state object - this makes perfect sense - otherwise
* when reusing the state for another project we'd not be switching to the right weaver/world
* for that project.
*/
public void testBuildingTwoProjectsMakingSmallChanges() {
configureBuildStructureModel(true);
initialiseProject("P1");
initialiseProject("P2");

build("P1");
build("P2");
build("P1");
checkWasntFullBuild();
build("P2");
checkWasntFullBuild();
alter("P1","inc1"); // adds a class
alter("P1","inc2"); // adds an aspect
build("P1");
checkWasntFullBuild();
}
/**
* Setup up two simple projects and build them in turn - check the
* structure model is right after each build
*/
public void testBuildingTwoProjectsAndVerifyingModel() {
configureBuildStructureModel(true);
initialiseProject("P1");
initialiseProject("P2");

build("P1");
checkForNode("pkg","C",true);

build("P2");
checkForNode("pkg","C",false);

build("P1");
checkForNode("pkg","C",true);
build("P2");
checkForNode("pkg","C",false);
}


// Setup up two simple projects and build them in turn - check the
// structure model is right after each build
public void testBuildingTwoProjectsAndVerifyingStuff() {
configureBuildStructureModel(true);
initialiseProject("P1");
initialiseProject("P2");

build("P1");
checkForNode("pkg","C",true);

build("P2");
checkForNode("pkg","C",false);

build("P1");
checkForNode("pkg","C",true);
build("P2");
checkForNode("pkg","C",false);
}

/**
* Complex. Here we are testing that a state object records structural changes since
* the last full build correctly. We build a simple project from scratch - this will
* be a full build and so the structural changes since last build count should be 0.
* We then alter a class, adding a new method and check structural changes is 1.
*/
public void testStateManagement1() {
File binDirectoryForP1 = new File(getFile("P1","bin"));
initialiseProject("P1");
build("P1"); // full build
AjState ajs = IncrementalStateManager.findStateManagingOutputLocation(binDirectoryForP1);
assertTrue("There should be a state object for project P1",ajs!=null);
assertTrue("Should be no structural changes as it was a full build but found: "+
ajs.getNumberOfStructuralChangesSinceLastFullBuild(),
ajs.getNumberOfStructuralChangesSinceLastFullBuild()==0);
alter("P1","inc3"); // adds a method to the class C.java
build("P1");
checkWasntFullBuild();
ajs = IncrementalStateManager.findStateManagingOutputLocation(new File(getFile("P1","bin")));
assertTrue("There should be state for project P1",ajs!=null);
checkWasntFullBuild();
assertTrue("Should be one structural changes as it was a full build but found: "+
ajs.getNumberOfStructuralChangesSinceLastFullBuild(),
ajs.getNumberOfStructuralChangesSinceLastFullBuild()==1);

}
/**
* Complex. Here we are testing that a state object records structural changes since
* the last full build correctly. We build a simple project from scratch - this will
* be a full build and so the structural changes since last build count should be 0.
* We then alter a class, changing body of a method, not the structure and
* check struc changes is still 0.
*/
public void testStateManagement2() {
File binDirectoryForP1 = new File(getFile("P1","bin"));
initialiseProject("P1");
alter("P1","inc3"); // need this change in here so 'inc4' can be applied without making
// it a structural change
build("P1"); // full build
AjState ajs = IncrementalStateManager.findStateManagingOutputLocation(binDirectoryForP1);
assertTrue("There should be state for project P1",ajs!=null);
assertTrue("Should be no struc changes as its a full build: "+
ajs.getNumberOfStructuralChangesSinceLastFullBuild(),
ajs.getNumberOfStructuralChangesSinceLastFullBuild()==0);
alter("P1","inc4"); // changes body of main() method but does *not* change the structure of C.java
build("P1");
checkWasntFullBuild();
ajs = IncrementalStateManager.findStateManagingOutputLocation(new File(getFile("P1","bin")));
assertTrue("There should be state for project P1",ajs!=null);
checkWasntFullBuild();
assertTrue("Shouldn't be any structural changes but there were "+
ajs.getNumberOfStructuralChangesSinceLastFullBuild(),
ajs.getNumberOfStructuralChangesSinceLastFullBuild()==0);
}
/**
* Now the most complex test. Create a dependancy between two projects. Building
* one may affect whether the other does an incremental or full build. The
* structural information recorded in the state object should be getting used
* to control whether a full build is necessary...
*/
public void testBuildingDependantProjects() {
initialiseProject("P1");
initialiseProject("P2");
configureNewProjectDependency("P2","P1");
build("P1");
build("P2"); // now everything is consistent and compiled
alter("P1","inc1"); // adds a second class
build("P1");
build("P2"); // although a second class was added - P2 can't be using it, so we don't full build here :)
checkWasntFullBuild();
alter("P1","inc3"); // structurally changes one of the classes
build("P1");
build("P2"); // build notices the structural change
checkWasFullBuild();
alter("P1","inc4");
build("P1");
build("P2"); // build sees a change but works out its not structural
checkWasntFullBuild();
}
// other possible tests:
// - memory usage (freemem calls?)
// - relationship map

// ---------------------------------------------------------------------------------------------------

/**
* Check we compiled/wove the right number of files, passing '-1' indicates you don't care about
* that number.
*/
private void checkCompileWeaveCount(int expCompile,int expWoven) {
if (expCompile!=-1 && getCompiledFiles().size()!=expCompile)
fail("Expected compilation of "+expCompile+" files but compiled "+getCompiledFiles().size()+
"\n"+printCompiledAndWovenFiles());
if (expWoven!=-1 && getWovenClasses().size()!=expWoven)
fail("Expected weaving of "+expWoven+" files but wove "+getWovenClasses().size()+
"\n"+printCompiledAndWovenFiles());
}
private void checkWasntFullBuild() {
assertTrue("Shouldn't have been a full (batch) build",!wasFullBuild());
}
private void checkWasFullBuild() {
assertTrue("Should have been a full (batch) build",wasFullBuild());
}
private void checkForNode(String packageName,String typeName,boolean shouldBeFound) {
IProgramElement ipe = AsmManager.getDefault().getHierarchy().findElementForType(packageName,typeName);
if (shouldBeFound) {
if (ipe==null) printModel();
assertTrue("Should have been able to find '"+packageName+"."+typeName+"' in the asm",ipe!=null);
} else {
if (ipe!=null) printModel();
assertTrue("Should have NOT been able to find '"+packageName+"."+typeName+"' in the asm",ipe==null);
}
}


private void printModel() {
try {
AsmManager.dumptree(AsmManager.getDefault().getHierarchy().getRoot(),0);
} catch (IOException e) {
e.printStackTrace();
}
}

public void build(String projectName) {
constructUpToDateLstFile(projectName,"build.lst");
build(projectName,"build.lst");
if (AjdeInteractionTestbed.VERBOSE) printBuildReport();
}

private void constructUpToDateLstFile(String pname,String configname) {
File projectBase = new File(sandboxDir,pname);
File toConstruct = new File(projectBase,configname);
List filesForCompilation = new ArrayList();
collectUpFiles(projectBase,projectBase,filesForCompilation);

try {
FileOutputStream fos = new FileOutputStream(toConstruct);
DataOutputStream dos = new DataOutputStream(fos);
for (Iterator iter = filesForCompilation.iterator(); iter.hasNext();) {
String file = (String) iter.next();
dos.writeBytes(file+"\n");
}
dos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
private void collectUpFiles(File location,File base,List collectionPoint) {
String contents[] = location.list();
if (contents==null) return;
for (int i = 0; i < contents.length; i++) {
String string = contents[i];
File f = new File(location,string);
if (f.isDirectory()) {
collectUpFiles(f,base,collectionPoint);
} else if (f.isFile() && (f.getName().endsWith(".aj") || f.getName().endsWith(".java"))) {
String fileFound;
try {
fileFound = f.getCanonicalPath();
String toRemove = base.getCanonicalPath();
if (!fileFound.startsWith(toRemove)) throw new RuntimeException("eh? "+fileFound+" "+toRemove);
collectionPoint.add(fileFound.substring(toRemove.length()+1));//+1 captures extra separator
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* Fill in the working directory with the project base files,
* from the 'base' folder.
*/
private void initialiseProject(String p) {
File projectSrc=new File(testdataSrcDir+File.separatorChar+p+File.separatorChar+"base");
File destination=new File(getWorkingDir(),p);
if (!destination.exists()) {destination.mkdir();}
copy(projectSrc,destination);//,false);
}

/*
* Applies an overlay onto the project being tested - copying
* the contents of the specified overlay directory.
*/
private void alter(String projectName,String overlayDirectory) {
File projectSrc =new File(testdataSrcDir+File.separatorChar+projectName+
File.separatorChar+overlayDirectory);
File destination=new File(getWorkingDir(),projectName);
copy(projectSrc,destination);
}
/**
* Copy the contents of some directory to another location - the
* copy is recursive.
*/
private void copy(File from, File to) {
String contents[] = from.list();
if (contents==null) return;
for (int i = 0; i < contents.length; i++) {
String string = contents[i];
File f = new File(from,string);
File t = new File(to,string);
if (f.isDirectory() && !f.getName().startsWith("inc")) {
t.mkdir();
copy(f,t);
} else if (f.isFile()) {
StringBuffer sb = new StringBuffer();
//if (VERBOSE) System.err.println("Copying "+f+" to "+t);
FileUtil.copyFile(f,t,sb);
if (sb.length()!=0) { System.err.println(sb.toString());}
}
}
}

private static void log(String msg) {
if (VERBOSE) System.out.println(msg);
}
}

Loading…
Cancel
Save