aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src/org/aspectj/systemtest/incremental/tools/MoreOutputLocationManagerTests.java
blob: 308ed42d54a1df25be4b8565a4e355c620834088 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/********************************************************************
 * 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.aspectj.ajde.core.IOutputLocationManager;
import org.aspectj.ajdt.internal.core.builder.AjBuildConfig;
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("inpathTesting", new SingleDirOutputLocMgr(inpathTestingDir));
	}

	/**
	 * 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<String,File> classNameToFileMap = state.getClassNameToFileMap();
		assertFalse("expected there to be classes ", classNameToFileMap.isEmpty());
		Set<Map.Entry<String,File>> entrySet = classNameToFileMap.entrySet();
		for (Iterator<Map.Entry<String,File>> iterator = entrySet.iterator(); iterator.hasNext();) {
			Map.Entry<String,File> entry = iterator.next();
			String className = 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("inpathTesting", 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<String,List<UnwovenClassFile>> binarySources = state.getAjBuildManager().getBinarySourcesForThisWeave();
		assertFalse("expected there to be binary sources from the inpath setting but didn't find any", binarySources.isEmpty());

		List<UnwovenClassFile> unwovenClassFiles = binarySources.get(inpathDir + File.separator + "InpathClass.class");
		List<String> 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 (UnwovenClassFile ucf: unwovenClassFiles) {
			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<String, List<UnwovenClassFile>> binarySources = state.getBinaryFilesToCompile(true);
		assertFalse("expected there to be binary sources from the inpath setting but didn't find any", binarySources.isEmpty());

		List<UnwovenClassFile> unwovenClassFiles = binarySources.get(inpathDir + File.separator + "InpathClass.class");
		List<String> 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 (UnwovenClassFile ucf: unwovenClassFiles) {
			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("inpathTesting", 1, 2);

		AjState state = getState();

		// tests AjState.createUnwovenClassFile(BinarySourceFile)
		Map<String,List<UnwovenClassFile>> binarySources = state.getAjBuildManager().getBinarySourcesForThisWeave();
		assertFalse("expected there to be binary sources from the inpath setting but didn't find any", binarySources.isEmpty());

		List<UnwovenClassFile> unwovenClassFiles = binarySources.get(inpathDir);
		List<String> fileNames = new ArrayList<>();

		for (UnwovenClassFile ucf: unwovenClassFiles) {
			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().
	 */
	// see 243376: for now don't do this, waste of cpu - ajdt better for handling resources - but is that true for inpath resources?
	// 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().
	 */
	// see 243376: for now don't do this, waste of cpu - ajdt better for handling resources - but is that true for inpath resources?
	// public void testAjStateDeleteResourcesInInputDir() {
	// // temporary problem with this on linux, think it is a filesystem lastmodtime issue
	// if (System.getProperty("os.name","").toLowerCase().equals("linux")) return;
	// if (System.getProperty("os.name","").toLowerCase().indexOf("mac")!=-1) return;
	//
	// 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("inpathTesting", "-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("inpathTesting", "-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);
		assertNotNull("expected to find AjState for build config " + inpathTestingDir + " but didn't", state);
		return state;
	}

	private void addInpathEntry(String entry) {
		if (entry == null) {
			configureInPath("inpathTesting", (Set)null);
			return;
		}
		File f = new File(entry);
		Set<File> s = new HashSet<>();
		s.add(f);
		configureInPath("inpathTesting", s);
	}

	/**
	 * Sends all output to the same directory
	 */
	private static class SingleDirOutputLocMgr implements IOutputLocationManager {

		private File classOutputLoc;
		private File resourceOutputLoc;
		private String testProjectOutputPath;
		private List<File> 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 Map<File,String> getInpathMap() {
			return Collections.emptyMap();
		}


		public File getOutputLocationForResource(File resource) {
			return outputLoc;
		}

		public List<File> getAllOutputLocations() {
			return allOutputLocations;
		}

		public File getDefaultOutputLocation() {
			return outputLoc;
		}

		public void reportFileWrite(String outputfile, int filetype) {
		}

		public void reportFileRemove(String outputfile, int filetype) {
		}

		public String getSourceFolderForFile(File sourceFile) {
			return null; // no impl
		}

		public int discoverChangesSince(File dir, long buildtime) {
			return 0; // no impl
		}
	}

}