/******************************************************************** * Copyright (c) 2006 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: IBM Corporation - initial API and implementation * Helen Hawkins - initial version *******************************************************************/ package org.aspectj.systemtest.incremental.tools; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.aspectj.ajde.OutputLocationManager; import org.aspectj.ajdt.internal.core.builder.AjBuildConfig; import org.aspectj.ajdt.internal.core.builder.AjBuildManager; import org.aspectj.ajdt.internal.core.builder.AjState; import org.aspectj.ajdt.internal.core.builder.IncrementalStateManager; import org.aspectj.util.FileUtil; import org.aspectj.weaver.bcel.UnwovenClassFile; /** * Similar to OutputLocationManagerTests, however, tests the different * scenarios when no outputDir is set but instead there is an * OutputLocationManager which returns the same output location for all * files and resources. * * There are eight places where AjBuildConfig.getOutputDir() is called * that are tested here: * * AjBuildManager.getOutputClassFileName(..) - testCorrectInfoWhenNoOutputPath * AjBuildManager.initBcelWorld(..) - testPathResolutionWithInpathDirAndNoOutputPath * testPathResolutionWithInpathJarAndNoOutputPath * AjBuildManager.writeManifest(..) - testCopyManifest * AjBuildManager.writeOutxml(..) - testOutxml * - testOutXmlForAspectsWithDifferentOutputDirs * AjState.createUnwovenClassFile(..) - testPathResolutionAfterChangeInClassOnInpath * AjState.deleteResources(..) - testAjStateDeleteResources * AjState.maybeDeleteResources(..) - testAjStateDeleteResourcesInInputDir * AjState.removeAllResultsOfLastBuild(..) - testAllResourcesAreDeletedCorrectlyOnPathChange * IncrementalStateManager.findStateManagingOutputLocation(..) - testFindStateManagingOutputLocation * * The other three places are not tested here because they were implemented * when OutputLocationManager was introduced. * */ public class MoreOutputLocationManagerTests extends AbstractMultiProjectIncrementalAjdeInteractionTestbed { private String inpathTestingDir; private String expectedOutputDir; protected void setUp() throws Exception { super.setUp(); initialiseProject("inpathTesting"); inpathTestingDir = getWorkingDir() + File.separator + "inpathTesting"; expectedOutputDir = inpathTestingDir + File.separator + "bin"; configureOutputLocationManager(new SingleDirOutputLocMgr(inpathTestingDir), false); } /** * Tests that the UnwovenClassFiles have the correct path when there * is no outputDir but there is an OutputLocationManager. Is a simple * project that has no inpath setting */ public void testCorrectInfoWhenNoOutputPath() { build("inpathTesting"); AjState state = getState(); Map classNameToFileMap = state.getClassNameToFileMap(); assertFalse("expected there to be classes ",classNameToFileMap.isEmpty()); Set entrySet = classNameToFileMap.entrySet(); for (Iterator iterator = entrySet.iterator(); iterator.hasNext();) { Map.Entry entry = (Map.Entry) iterator.next(); String className = (String) entry.getKey(); String fullClassName = expectedOutputDir + File.separator + className.replace('.',File.separatorChar) + ".class"; File file = (File) entry.getValue(); assertEquals("expected file to have path \n" + fullClassName + ", but" + " found path \n" + file.getAbsolutePath(),fullClassName, file.getAbsolutePath()); } } /** * Tests that can retieve the state that manages a given output location * when there is no outputDir set */ public void testFindStateManagingOutputLocation() { build("inpathTesting"); AjState state = IncrementalStateManager.findStateManagingOutputLocation(new File(expectedOutputDir)); assertNotNull("Expected to find a state that managed output location " + expectedOutputDir + ", but did not", state); } /** * Tests that the UnwovenClassFiles corresponding to classes on the * inpath have the correct class name when there is no output directory * (ultimately tests AjBuildManager.initBcelWorld() when there is a * jar on the inpath). Only does one build. */ public void testPathResolutionWithInpathDirAndNoOutputPath() { String inpathDir = inpathTestingDir + File.separator + "injarBin" + File.separator + "pkg"; addInpathEntry(inpathDir); build("inpathTesting"); // expect to compile the aspect in 'inpathTesting' project and weave // both the aspect and the class on the inpath. checkCompileWeaveCount(1,2); // get hold of the state for this project - expect to find one AjState state = getState(); // the classes onthe inpath are recorded against the AjBuildManager // (they are deleted from the ajstate whilst cleaning up after a build) Map binarySources = state.getAjBuildManager().getBinarySourcesForThisWeave(); assertFalse("expected there to be binary sources from the inpath setting but didn't find any",binarySources.isEmpty()); List unwovenClassFiles = (List) binarySources.get(inpathDir + File.separator + "InpathClass.class"); List fileNames = new ArrayList(); // the unwovenClassFiles should have filenames that point to the output dir // (which in this case is the sandbox dir) and not where they came from. for (Iterator iterator = unwovenClassFiles.iterator(); iterator.hasNext();) { UnwovenClassFile ucf = (UnwovenClassFile) iterator.next(); if (ucf.getFilename().indexOf(expectedOutputDir) == -1) { fileNames.add(ucf.getFilename()); } } assertTrue("expected to find UnwovenClassFile from directory\n" + expectedOutputDir + ", \n but found files " + fileNames, fileNames.isEmpty()); } /** * Tests that the UnwovenClassFiles corresponding to classes on the * inpath have the correct class name when there is no output directory * (ultimately tests AjState.createUnwovenClassFile(BinarySourceFile) * and ensures the unwovenClassFile has the correct name. Makes a change to * a class file on the inpath to ensure we enter this method (there is a * check that says are we the first build)) */ public void testPathResolutionAfterChangeInClassOnInpath() throws Exception { String inpathDir = inpathTestingDir + File.separator + "injarBin" + File.separator + "pkg"; addInpathEntry(inpathDir); build("inpathTesting"); // build again so that we enter // AjState.createUnwovenClassFile(BinarySourceFile) File from = new File(testdataSrcDir+File.separatorChar+"inpathTesting" +File.separatorChar+"newInpathClass" + File.separatorChar + "InpathClass.class"); File destination = new File(inpathDir + File.separatorChar + "InpathClass.class"); FileUtil.copyFile(from,destination); // get hold of the state for this project - expect to find one AjState state = getState(); AjBuildConfig buildConfig = state.getBuildConfig(); state.prepareForNextBuild(buildConfig); Map binarySources = state.getBinaryFilesToCompile(true); assertFalse("expected there to be binary sources from the inpath setting but didn't find any",binarySources.isEmpty()); List unwovenClassFiles = (List) binarySources.get(inpathDir + File.separator + "InpathClass.class"); List fileNames = new ArrayList(); // the unwovenClassFiles should have filenames that point to the output dir // (which in this case is the sandbox dir) and not where they came from. for (Iterator iterator = unwovenClassFiles.iterator(); iterator.hasNext();) { UnwovenClassFile ucf = (UnwovenClassFile) iterator.next(); if (ucf.getFilename().indexOf(expectedOutputDir) == -1) { fileNames.add(ucf.getFilename()); } } assertTrue("expected to find UnwovenClassFile from directory\n" + expectedOutputDir + ", \n but found files " + fileNames, fileNames.isEmpty()); } /** * Tests that the UnwovenClassFiles corresponding to jars on the * inpath have the correct class name when there is no output path * (ultimately tests AjBuildManager.initBcelWorld() when there is a * jar on the inpath). Only does one build. */ public void testPathResolutionWithInpathJarAndNoOutputPath() { String inpathDir = inpathTestingDir + File.separator + "inpathJar.jar"; addInpathEntry(inpathDir); build("inpathTesting"); // expect to compile the aspect in 'inpathTesting' project and weave // both the aspect and the class in the jar on the inpath. checkCompileWeaveCount(1,2); AjState state = getState(); // tests AjState.createUnwovenClassFile(BinarySourceFile) Map binarySources = state.getAjBuildManager().getBinarySourcesForThisWeave(); assertFalse("expected there to be binary sources from the inpath setting but didn't find any",binarySources.isEmpty()); List unwovenClassFiles = (List) binarySources.get(inpathDir); List fileNames = new ArrayList(); for (Iterator iterator = unwovenClassFiles.iterator(); iterator.hasNext();) { UnwovenClassFile ucf = (UnwovenClassFile) iterator.next(); if (ucf.getFilename().indexOf(expectedOutputDir) == -1) { fileNames.add(ucf.getFilename()); } } assertTrue("expected to find UnwovenClassFile from directory\n" + expectedOutputDir + ", \n but found files " + fileNames, fileNames.isEmpty()); } /** * A manifest file is in the jar on the inpath - check that it's * copied to the correct place */ public void testCopyManifest() { String inpathDir = inpathTestingDir + File.separator + "inpathJar.jar"; addInpathEntry(inpathDir); build("inpathTesting"); String resource = expectedOutputDir + File.separator + "META-INF" + File.separator + "MANIFEST.MF"; File f = new File(resource); assertTrue("expected file " + resource + " to exist but it did not",f.exists()); } /** * "resources" are contained within inpath jars - check that * a text file contained within a jar is copied and then * deleted correctly. Essentially tests AjState.deleteResources(). */ public void testAjStateDeleteResources() { String inpathDir = inpathTestingDir + File.separator + "inpathJar.jar"; addInpathEntry(inpathDir); build("inpathTesting"); AjState state = getState(); String resource = expectedOutputDir + File.separator + "inpathResource.txt"; File f = new File(resource); assertTrue("expected file " + resource + " to exist but it did not",f.exists()); // this call should delete the resources state.getFilesToCompile(true); assertFalse("did not expect the file " + resource + " to exist but it does",f.exists()); } /** * Can set to copy resources that are in inpath dirs - check that * a text file contained within such a dir is copied and then * deleted correctly. Essentially tests AjState.maybeDeleteResources(). */ public void testAjStateDeleteResourcesInInputDir() { AjBuildManager.COPY_INPATH_DIR_RESOURCES = true; try { String inpathDir = inpathTestingDir + File.separator + "injarBin" + File.separator + "pkg"; addInpathEntry(inpathDir); build("inpathTesting"); AjState state = getState(); String resource = "inDirResource.txt"; assertTrue("expected state to have resource " + resource + "but it did not", state.hasResource(resource)); // this call should delete the resources - tests AjState.deleteResources() state.getFilesToCompile(true); assertFalse("did not expect state to have resource " + resource + " but found that it did", state.hasResource(resource)); } finally { AjBuildManager.COPY_INPATH_DIR_RESOURCES = false; } } /** * Changing inpath entry from a jar to a directory between builds means * that AjState should realise somethings changed. This causes all resources * (Manifest and txt files) to be deleted. Also should be a full build. * Essentially tests AjState.removeAllResultsFromLastBuild(). */ public void testAllResourcesAreDeletedCorrectlyOnPathChange() { String inpathJar = inpathTestingDir + File.separator + "inpathJar.jar"; addInpathEntry(inpathJar); build("inpathTesting"); String resource = expectedOutputDir + File.separator + "inpathResource.txt"; File f = new File(resource); assertTrue("expected file " + resource + " to exist but it did not",f.exists()); // this should force a change and the file is deleted // tests AjState.removeAllResultsFromLastBuild() addInpathEntry(null); build("inpathTesting"); assertFalse("did not expect the file " + resource + " to exist but it does",f.exists()); checkWasFullBuild(); } public void testOutxml() { configureNonStandardCompileOptions("-outxml"); build("inpathTesting"); String resource = expectedOutputDir + File.separator + "META-INF" + File.separator + "aop-ajc.xml"; File f = new File(resource); assertTrue("expected file " + resource + " to exist but it did not",f.exists()); } public void testAspectsRecordedOnlyOnceInState() { configureNonStandardCompileOptions("-outxml"); build("inpathTesting"); AjState state = getState(); Map m = state.getAspectNamesToFileNameMap(); assertEquals("Expected only one aspect recored in the state but found " + m.size(),1,m.size()); build("inpathTesting"); m = state.getAspectNamesToFileNameMap(); assertEquals("Expected only one aspect recored in the state but found " + m.size(),1,m.size()); } private AjState getState() { // get hold of the state for this project - expect to find one AjState state = IncrementalStateManager.retrieveStateFor(inpathTestingDir + File.separator + "build.lst" ); assertNotNull("expected to find AjState for build config " + inpathTestingDir + File.separator + "build.lst but didn't", state); return state; } private void addInpathEntry(String entry) { if (entry == null) { configureInPath(null); return; } File f = new File(entry); Set s = new HashSet(); s.add(f); configureInPath(s); } /** * Sends all output to the same directory */ private static class SingleDirOutputLocMgr implements OutputLocationManager { private File classOutputLoc; private File resourceOutputLoc; private String testProjectOutputPath; private List allOutputLocations; private File outputLoc; public SingleDirOutputLocMgr(String testProjectPath) { this.testProjectOutputPath = testProjectPath + File.separator + "bin"; outputLoc = new File(testProjectOutputPath); allOutputLocations = new ArrayList(); allOutputLocations.add(outputLoc); } public File getOutputLocationForClass(File compilationUnit) { return outputLoc; } public File getOutputLocationForResource(File resource) { return outputLoc; } public List /*File*/ getAllOutputLocations() { return allOutputLocations; } public File getDefaultOutputLocation() { return outputLoc; } } }