1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - Initial API and implementation
13  * 		tammo.freese@offis.de - tests for swapping files and folders
14  ******************************************************************************/
15 package org.eclipse.core.tests.resources;
16 
17 import java.io.ByteArrayInputStream;
18 import java.io.IOException;
19 import org.eclipse.core.internal.resources.Workspace;
20 import org.eclipse.core.resources.*;
21 import org.eclipse.core.runtime.*;
22 import org.eclipse.core.runtime.jobs.Job;
23 
24 /**
25  * Tests behavior of IResourceChangeListener, including validation
26  * that correct deltas are received for all types of workspace changes.
27  */
28 public class IResourceChangeListenerTest extends ResourceTest {
29 	class SimpleListener implements IResourceChangeListener {
30 		Object source;
31 		int trigger;
32 
33 		@Override
resourceChanged(IResourceChangeEvent event)34 		public void resourceChanged(IResourceChangeEvent event) {
35 			source = event.getSource();
36 			trigger = event.getBuildKind();
37 		}
38 	}
39 
40 	protected static final String VERIFIER_NAME = "TestListener";
41 	IFile file1; //below folder1
42 	IFile file2; //below folder1
43 	IFile file3; //below folder2
44 	IFolder folder1; //below project2
45 	IFolder folder2; //below folder1
46 	IFolder folder3; //same as file1
47 	/* some random resource handles */
48 	IProject project1;
49 	IFile project1MetaData;
50 	IProject project2;
51 	IFile project2MetaData;
52 	ResourceDeltaVerifier verifier;
53 
_testBenchMark_1GBYQEZ()54 	public void _testBenchMark_1GBYQEZ() {
55 		// start with a clean workspace
56 		getWorkspace().removeResourceChangeListener(verifier);
57 		try {
58 			getWorkspace().getRoot().delete(false, getMonitor());
59 		} catch (CoreException e) {
60 			fail("0.0", e);
61 		}
62 		// create the listener
63 		IResourceChangeListener listener = new IResourceChangeListener() {
64 			public int fCounter;
65 
66 			@Override
67 			public void resourceChanged(IResourceChangeEvent event) {
68 				try {
69 					System.out.println("Start");
70 					for (int i = 0; i < 10; i++) {
71 						fCounter = 0;
72 						long start = System.currentTimeMillis();
73 						IResourceDelta delta = event.getDelta();
74 						delta.accept(delta2 -> {
75 							fCounter++;
76 							return true;
77 						});
78 						long end = System.currentTimeMillis();
79 						System.out.println("    Number of deltas: " + fCounter + ". Time needed: " + (end - start));
80 					}
81 					System.out.println("End");
82 				} catch (CoreException e) {
83 					fail("1.0", e);
84 				}
85 			}
86 		};
87 		// add the listener
88 		getWorkspace().addResourceChangeListener(listener);
89 		// setup the test data
90 		IWorkspaceRunnable body = monitor -> {
91 			IProject project = getWorkspace().getRoot().getProject("Test");
92 			IProjectDescription description = getWorkspace().newProjectDescription(project.getName());
93 			IPath root = getWorkspace().getRoot().getLocation();
94 			IPath contents = root.append("temp/testing");
95 			description.setLocation(contents);
96 			project.create(description, getMonitor());
97 			project.open(getMonitor());
98 			project.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
99 		};
100 		try {
101 			getWorkspace().run(body, getMonitor());
102 		} catch (CoreException e) {
103 			fail("2.0", e);
104 		}
105 		// touch all resources (so that they appear in the delta)
106 		body = monitor -> {
107 			IResourceVisitor visitor = resource -> {
108 				resource.touch(getMonitor());
109 				return true;
110 			};
111 			getWorkspace().getRoot().accept(visitor);
112 		};
113 		try {
114 			getWorkspace().run(body, getMonitor());
115 		} catch (CoreException e) {
116 			fail("3.0", e);
117 		}
118 		// un-register our listener
119 		getWorkspace().removeResourceChangeListener(listener);
120 	}
121 
122 	/**
123 	 * Tests that the builder is receiving an appropriate delta
124 	 *
125 	 * @see SortBuilderPlugin
126 	 * @see SortBuilder
127 	 */
assertDelta()128 	public void assertDelta() {
129 		assertTrue(verifier.getMessage(), verifier.isDeltaValid());
130 	}
131 
132 	/**
133 	 * Asserts that a manual traversal of the delta does not find the given
134 	 * resources.
135 	 */
assertNotDeltaIncludes(String message, IResourceDelta delta, IResource[] resources)136 	void assertNotDeltaIncludes(String message, IResourceDelta delta, IResource[] resources) {
137 		try {
138 			IResource deltaResource = delta.getResource();
139 			for (IResource resource : resources) {
140 				assertTrue(message, !deltaResource.equals(resource));
141 			}
142 			IResourceDelta[] children = delta.getAffectedChildren();
143 			for (IResourceDelta element : children) {
144 				assertNotDeltaIncludes(message, element, resources);
145 			}
146 		} catch (RuntimeException e) {
147 			fail(message, e);
148 		}
149 	}
150 
151 	/**
152 	 * Asserts that a visitor traversal of the delta does not find the given
153 	 * resources.
154 	 */
assertNotDeltaVisits(final String message, IResourceDelta delta, final IResource[] resources)155 	void assertNotDeltaVisits(final String message, IResourceDelta delta, final IResource[] resources) {
156 		try {
157 			delta.accept(delta2 -> {
158 				IResource deltaResource = delta2.getResource();
159 				for (IResource resource : resources) {
160 					assertTrue(message, !deltaResource.equals(resource));
161 				}
162 				return true;
163 			});
164 		} catch (CoreException | RuntimeException e) {
165 			fail(message, e);
166 		}
167 	}
168 
169 	/**
170 	 * Runs code to handle a core exception
171 	 */
handleCoreException(CoreException e)172 	protected void handleCoreException(CoreException e) {
173 		fail("IResourceChangeListenerTest", e);
174 	}
175 
176 	/**
177 	 * Sets the workspace autobuilding to the desired value.
178 	 */
setAutoBuilding(boolean value)179 	protected void setAutoBuilding(boolean value) {
180 		IWorkspace workspace = getWorkspace();
181 		if (workspace.isAutoBuilding() == value) {
182 			return;
183 		}
184 		IWorkspaceDescription desc = workspace.getDescription();
185 		desc.setAutoBuilding(value);
186 		try {
187 			workspace.setDescription(desc);
188 		} catch (CoreException e) {
189 			fail("failed to set workspace description", e);
190 		}
191 	}
192 
193 	/**
194 	 * Sets up the fixture, for example, open a network connection. This method
195 	 * is called before a test is executed.
196 	 */
197 	@Override
setUp()198 	protected void setUp() throws Exception {
199 		super.setUp();
200 		// Create some resource handles
201 		project1 = getWorkspace().getRoot().getProject("Project" + 1);
202 		project2 = getWorkspace().getRoot().getProject("Project" + 2);
203 		folder1 = project1.getFolder("Folder" + 1);
204 		folder2 = folder1.getFolder("Folder" + 2);
205 		folder3 = folder1.getFolder("File" + 1);
206 		file1 = folder1.getFile("File" + 1);
207 		file2 = folder1.getFile("File" + 2);
208 		file3 = folder2.getFile("File" + 1);
209 		project1MetaData = project1.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
210 		project2MetaData = project2.getFile(IProjectDescription.DESCRIPTION_FILE_NAME);
211 		// Create and open a project, folder and file
212 		IWorkspaceRunnable body = monitor -> {
213 			project1.create(getMonitor());
214 			project1.open(getMonitor());
215 			folder1.create(true, true, getMonitor());
216 			file1.create(getRandomContents(), true, getMonitor());
217 		};
218 		verifier = new ResourceDeltaVerifier();
219 		getWorkspace().addResourceChangeListener(verifier, IResourceChangeEvent.POST_CHANGE);
220 		try {
221 			getWorkspace().run(body, getMonitor());
222 		} catch (CoreException e) {
223 			fail("1.0", e);
224 		}
225 		//ensure all background jobs are done before we reset the delta verifier
226 		waitForBuild();
227 		waitForRefresh();
228 		verifier.reset();
229 	}
230 
231 	/**
232 	 * Tears down the fixture, for example, close a network connection. This
233 	 * method is called after a test is executed.
234 	 */
235 	@Override
tearDown()236 	protected void tearDown() throws Exception {
237 		getWorkspace().removeResourceChangeListener(verifier);
238 		super.tearDown();
239 		ensureDoesNotExistInWorkspace(getWorkspace().getRoot());
240 	}
241 
242 	/*
243 	 * Create a resource change listener and register it for POST_BUILD
244 	 * events. Ensure that you are able to modify the workspace tree.
245 	 */
test_1GDK9OG()246 	public void test_1GDK9OG() {
247 		// create the resource change listener
248 		IResourceChangeListener listener = event -> {
249 			try {
250 				IWorkspaceRunnable body = monitor -> {
251 					// modify the tree.
252 					IResourceDeltaVisitor visitor = delta -> {
253 						IResource resource = delta.getResource();
254 						try {
255 							resource.touch(getMonitor());
256 						} catch (RuntimeException e) {
257 							throw e;
258 						}
259 						resource.createMarker(IMarker.PROBLEM);
260 						return true;
261 					};
262 					event.getDelta().accept(visitor);
263 				};
264 				getWorkspace().run(body, getMonitor());
265 			} catch (CoreException e) {
266 				fail("1.0", e);
267 			}
268 		};
269 		// register the listener with the workspace.
270 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_BUILD);
271 		try {
272 			IWorkspaceRunnable body = new IWorkspaceRunnable() {
273 				// cause a delta by touching all resources
274 				final IResourceVisitor visitor = resource -> {
275 					resource.touch(getMonitor());
276 					return true;
277 				};
278 
279 				@Override
280 				public void run(IProgressMonitor monitor) throws CoreException {
281 					getWorkspace().getRoot().accept(visitor);
282 				}
283 			};
284 			getWorkspace().run(body, getMonitor());
285 			//wait for autobuild so POST_BUILD will fire
286 			try {
287 				Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
288 			} catch (OperationCanceledException | InterruptedException e) {
289 				//ignore
290 			}
291 		} catch (CoreException e) {
292 			fail("2.0", e);
293 		} finally {
294 			// cleanup: ensure that the listener is removed
295 			getWorkspace().removeResourceChangeListener(listener);
296 		}
297 	}
298 
testAddAndRemoveFile()299 	public void testAddAndRemoveFile() {
300 		try {
301 			verifier.reset();
302 			getWorkspace().run((IWorkspaceRunnable) m -> {
303 				m.beginTask("Creating and deleting", 100);
304 				try {
305 					file2.create(getRandomContents(), true, SubMonitor.convert(m, 50));
306 					file2.delete(true, SubMonitor.convert(m, 50));
307 				} finally {
308 					m.done();
309 				}
310 			}, getMonitor());
311 			//should not have been verified since there was no change
312 			assertTrue("Unexpected notification on no change", !verifier.hasBeenNotified());
313 		} catch (CoreException e) {
314 			handleCoreException(e);
315 		}
316 	}
317 
testAddAndRemoveFolder()318 	public void testAddAndRemoveFolder() {
319 		try {
320 			verifier.reset();
321 			getWorkspace().run((IWorkspaceRunnable) m -> {
322 				m.beginTask("Creating and deleting", 100);
323 				try {
324 					folder2.create(true, true, SubMonitor.convert(m, 50));
325 					folder2.delete(true, SubMonitor.convert(m, 50));
326 				} finally {
327 					m.done();
328 				}
329 			}, getMonitor());
330 			//should not have been verified since there was no change
331 			assertTrue("Unexpected notification on no change", !verifier.hasBeenNotified());
332 		} catch (CoreException e) {
333 			handleCoreException(e);
334 		}
335 	}
336 
testAddFile()337 	public void testAddFile() {
338 		try {
339 			verifier.addExpectedChange(file2, IResourceDelta.ADDED, 0);
340 			file2.create(getRandomContents(), true, getMonitor());
341 			assertDelta();
342 		} catch (CoreException e) {
343 			handleCoreException(e);
344 		}
345 	}
346 
testAddFileAndFolder()347 	public void testAddFileAndFolder() {
348 		try {
349 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
350 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, 0);
351 			getWorkspace().run((IWorkspaceRunnable) m -> {
352 				m.beginTask("Creating folder and file", 100);
353 				try {
354 					folder2.create(true, true, SubMonitor.convert(m, 50));
355 					file3.create(getRandomContents(), true, SubMonitor.convert(m, 50));
356 				} finally {
357 					m.done();
358 				}
359 			}, getMonitor());
360 			assertDelta();
361 		} catch (CoreException e) {
362 			handleCoreException(e);
363 		}
364 	}
365 
testAddFolder()366 	public void testAddFolder() {
367 		try {
368 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
369 			folder2.create(true, true, getMonitor());
370 			assertDelta();
371 		} catch (CoreException e) {
372 			handleCoreException(e);
373 		}
374 	}
375 
testAddProject()376 	public void testAddProject() {
377 		try {
378 			verifier.addExpectedChange(project2, IResourceDelta.ADDED, 0);
379 			verifier.addExpectedChange(project2MetaData, IResourceDelta.ADDED, 0);
380 			project2.create(getMonitor());
381 			assertDelta();
382 		} catch (CoreException e) {
383 			handleCoreException(e);
384 		}
385 	}
386 
387 	/*
388 	 * Create a resource change listener and register it for POST_CHANGE events.
389 	 * Ensure that you are NOT able to modify the workspace tree.
390 	 */
testBug45996()391 	public void testBug45996() {
392 		// create the resource change listener
393 		IResourceChangeListener listener = event -> {
394 			boolean failed = false;
395 			try {
396 				IWorkspaceRunnable body = monitor -> {
397 					// modify the tree.
398 					IResourceDeltaVisitor visitor = delta -> {
399 						IResource resource = delta.getResource();
400 						try {
401 							resource.touch(getMonitor());
402 						} catch (RuntimeException e) {
403 							throw e;
404 						}
405 						resource.createMarker(IMarker.PROBLEM);
406 						return true;
407 					};
408 					event.getDelta().accept(visitor);
409 				};
410 				getWorkspace().run(body, getMonitor());
411 			} catch (CoreException e) {
412 				//should fail
413 				failed = true;
414 			}
415 			assertTrue("1.0", failed);
416 		};
417 		// register the listener with the workspace.
418 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
419 		try {
420 			IWorkspaceRunnable body = new IWorkspaceRunnable() {
421 				// cause a delta by touching all resources
422 				final IResourceVisitor visitor = resource -> {
423 					resource.touch(getMonitor());
424 					return true;
425 				};
426 
427 				@Override
428 				public void run(IProgressMonitor monitor) throws CoreException {
429 					getWorkspace().getRoot().accept(visitor);
430 				}
431 			};
432 			getWorkspace().run(body, getMonitor());
433 		} catch (CoreException e) {
434 			fail("2.0", e);
435 		} finally {
436 			// cleanup: ensure that the listener is removed
437 			getWorkspace().removeResourceChangeListener(listener);
438 		}
439 	}
440 
testBuildKind()441 	public void testBuildKind() {
442 		SimpleListener preBuild = new SimpleListener();
443 		SimpleListener postBuild = new SimpleListener();
444 		SimpleListener postChange = new SimpleListener();
445 		final IWorkspace workspace = getWorkspace();
446 		try {
447 			setAutoBuilding(false);
448 			workspace.addResourceChangeListener(preBuild, IResourceChangeEvent.PRE_BUILD);
449 			workspace.addResourceChangeListener(postBuild, IResourceChangeEvent.POST_BUILD);
450 			workspace.addResourceChangeListener(postChange, IResourceChangeEvent.POST_CHANGE);
451 
452 			final int[] triggers = new int[] {IncrementalProjectBuilder.INCREMENTAL_BUILD, IncrementalProjectBuilder.FULL_BUILD, IncrementalProjectBuilder.CLEAN_BUILD,};
453 			for (int i = 0; i < triggers.length; i++) {
454 				final int trigger = triggers[i];
455 				workspace.run((IWorkspaceRunnable) monitor -> {
456 					file1.touch(null);
457 					workspace.build(trigger, monitor);
458 				}, getMonitor());
459 				assertEquals("1.0." + i, workspace, preBuild.source);
460 				assertEquals("1.1." + i, workspace, postBuild.source);
461 				assertEquals("1.2." + i, workspace, postChange.source);
462 				assertEquals("1.3." + i, trigger, preBuild.trigger);
463 				assertEquals("1.4." + i, trigger, postBuild.trigger);
464 				assertEquals("1.5." + i, 0, postChange.trigger);
465 
466 				workspace.run((IWorkspaceRunnable) monitor -> {
467 					file1.touch(null);
468 					project1.build(trigger, getMonitor());
469 				}, getMonitor());
470 				assertEquals("2.0." + i, project1, preBuild.source);
471 				assertEquals("2.2." + i, project1, postBuild.source);
472 				assertEquals("2.2." + i, workspace, postChange.source);
473 				assertEquals("2.3." + i, trigger, preBuild.trigger);
474 				assertEquals("2.4." + i, trigger, postBuild.trigger);
475 				assertEquals("2.5." + i, 0, postChange.trigger);
476 
477 			}
478 
479 			//test autobuild trigger
480 			setAutoBuilding(true);
481 			file1.touch(null);
482 			waitForBuild();
483 			int trigger = IncrementalProjectBuilder.AUTO_BUILD;
484 			assertEquals("1.0", workspace, preBuild.source);
485 			assertEquals("1.1", workspace, postBuild.source);
486 			assertEquals("1.2", workspace, postChange.source);
487 			assertEquals("1.3", trigger, preBuild.trigger);
488 			assertEquals("1.4", trigger, postBuild.trigger);
489 			assertEquals("1.5", 0, postChange.trigger);
490 
491 		} catch (CoreException e) {
492 			fail("4.99", e);
493 		} finally {
494 			workspace.removeResourceChangeListener(preBuild);
495 			workspace.removeResourceChangeListener(postBuild);
496 			workspace.removeResourceChangeListener(postChange);
497 			setAutoBuilding(true);
498 		}
499 	}
500 
testChangeFile()501 	public void testChangeFile() {
502 		try {
503 			/* change file1's contents */
504 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
505 			file1.setContents(getRandomContents(), true, false, getMonitor());
506 			assertDelta();
507 		} catch (CoreException e) {
508 			handleCoreException(e);
509 		}
510 	}
511 
testChangeFileToFolder()512 	public void testChangeFileToFolder() {
513 		try {
514 			/* change file1 into a folder */
515 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.CONTENT | IResourceDelta.TYPE | IResourceDelta.REPLACED);
516 			getWorkspace().run((IWorkspaceRunnable) m -> {
517 				m.beginTask("Deleting and Creating", 100);
518 				try {
519 					file1.delete(true, SubMonitor.convert(m, 50));
520 					folder3.create(true, true, SubMonitor.convert(m, 50));
521 				} finally {
522 					m.done();
523 				}
524 			}, getMonitor());
525 			assertDelta();
526 		} catch (CoreException e) {
527 			handleCoreException(e);
528 		}
529 	}
530 
testChangeFolderToFile()531 	public void testChangeFolderToFile() {
532 		try {
533 			/* change to a folder */
534 			verifier.reset();
535 			getWorkspace().run((IWorkspaceRunnable) m -> {
536 				file1.delete(true, getMonitor());
537 				folder3.create(true, true, getMonitor());
538 			}, null);
539 			/* now change back to a file and verify */
540 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.CONTENT | IResourceDelta.TYPE | IResourceDelta.REPLACED);
541 			getWorkspace().run((IWorkspaceRunnable) m -> {
542 				m.beginTask("Deleting and Creating", 100);
543 				try {
544 					folder3.delete(true, SubMonitor.convert(m, 50));
545 					file1.create(getRandomContents(), true, SubMonitor.convert(m, 50));
546 				} finally {
547 					m.done();
548 				}
549 			}, getMonitor());
550 			assertDelta();
551 		} catch (CoreException e) {
552 			handleCoreException(e);
553 		}
554 	}
555 
testChangeProject()556 	public void testChangeProject() {
557 		try {
558 			verifier.reset();
559 			getWorkspace().run((IWorkspaceRunnable) m -> {
560 				project2.create(getMonitor());
561 				project2.open(getMonitor());
562 			}, null);
563 			IProjectDescription desc = project2.getDescription();
564 			desc.setReferencedProjects(new IProject[] {project1});
565 			verifier.addExpectedChange(project2, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
566 			verifier.addExpectedChange(project2MetaData, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
567 			project2.setDescription(desc, IResource.FORCE, getMonitor());
568 			assertDelta();
569 		} catch (CoreException e) {
570 			handleCoreException(e);
571 		}
572 	}
573 
testCopyChangeFile()574 	public void testCopyChangeFile() {
575 		try {
576 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
577 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, 0, null, null);
578 			getWorkspace().run((IWorkspaceRunnable) m -> {
579 				m.beginTask("Creating and moving", 150);
580 				try {
581 					folder2.create(true, true, SubMonitor.convert(m, 50));
582 					file1.copy(file3.getFullPath(), true, SubMonitor.convert(m, 50));
583 					file3.setContents(getRandomContents(), IResource.NONE, SubMonitor.convert(m, 50));
584 				} finally {
585 					m.done();
586 				}
587 			}, getMonitor());
588 			assertDelta();
589 		} catch (CoreException e) {
590 			handleCoreException(e);
591 		}
592 	}
593 
testCopyFile()594 	public void testCopyFile() {
595 		try {
596 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
597 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, 0, null, null);
598 			getWorkspace().run((IWorkspaceRunnable) m -> {
599 				m.beginTask("Creating and moving", 100);
600 				try {
601 					folder2.create(true, true, SubMonitor.convert(m, 50));
602 					file1.copy(file3.getFullPath(), true, SubMonitor.convert(m, 50));
603 				} finally {
604 					m.done();
605 				}
606 			}, getMonitor());
607 			assertDelta();
608 		} catch (CoreException e) {
609 			handleCoreException(e);
610 		}
611 	}
612 
testCloseOpenReplaceFile()613 	public void testCloseOpenReplaceFile() {
614 		try {
615 			// FIXME: how to do this?
616 			//workspace.save(getMonitor());
617 			//workspace.close(getMonitor());
618 			//workspace.open(getMonitor());
619 			verifier.reset();
620 			getWorkspace().addResourceChangeListener(verifier);
621 			/* change file1's contents */
622 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.REPLACED | IResourceDelta.CONTENT);
623 			getWorkspace().run((IWorkspaceRunnable) m -> {
624 				m.beginTask("Deleting and Creating", 100);
625 				try {
626 					file1.delete(true, SubMonitor.convert(m, 50));
627 					file1.create(getRandomContents(), true, SubMonitor.convert(m, 50));
628 				} finally {
629 					m.done();
630 				}
631 			}, getMonitor());
632 			assertDelta();
633 		} catch (CoreException e) {
634 			handleCoreException(e);
635 		}
636 	}
637 
testDeleteInPostBuildListener()638 	public void testDeleteInPostBuildListener() {
639 		// create the resource change listener
640 		IResourceChangeListener listener = event -> {
641 			try {
642 				event.getDelta().accept(delta -> {
643 					IResource resource = delta.getResource();
644 					if (resource.getType() == IResource.FILE) {
645 						try {
646 							((IFile) resource).delete(true, true, null);
647 						} catch (RuntimeException e) {
648 							throw e;
649 						}
650 					}
651 					return true;
652 				});
653 			} catch (CoreException e) {
654 				fail("1.0", e);
655 			}
656 		};
657 		// register the listener with the workspace.
658 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_BUILD);
659 		try {
660 			getWorkspace().run((IWorkspaceRunnable) monitor -> getWorkspace().getRoot().accept(resource -> {
661 				resource.touch(getMonitor());
662 				return true;
663 			}), getMonitor());
664 		} catch (CoreException e) {
665 			fail("2.0", e);
666 		} finally {
667 			// cleanup: ensure that the listener is removed
668 			getWorkspace().removeResourceChangeListener(listener);
669 		}
670 	}
671 
672 	/**
673 	 * Tests deleting a file, then moving another file to that deleted location.
674 	 * See bug 27527.
675 	 */
testDeleteMoveFile()676 	public void testDeleteMoveFile() {
677 		try {
678 			verifier.reset();
679 			file2.create(getRandomContents(), IResource.NONE, getMonitor());
680 			verifier.reset();
681 			int flags = IResourceDelta.REPLACED | IResourceDelta.MOVED_FROM | IResourceDelta.CONTENT;
682 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, flags, file2.getFullPath(), null);
683 			verifier.addExpectedChange(file2, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file1.getFullPath());
684 			getWorkspace().run((IWorkspaceRunnable) m -> {
685 				m.beginTask("deleting and moving", 100);
686 				try {
687 					file1.delete(IResource.NONE, SubMonitor.convert(m, 50));
688 					file2.move(file1.getFullPath(), IResource.NONE, SubMonitor.convert(m, 50));
689 				} finally {
690 					m.done();
691 				}
692 			}, getMonitor());
693 			assertDelta();
694 		} catch (CoreException e) {
695 			handleCoreException(e);
696 		}
697 	}
698 
testDeleteProject()699 	public void testDeleteProject() throws CoreException {
700 		//test that marker deltas are fired when projects are deleted
701 		verifier.reset();
702 		final IMarker marker = project1.createMarker(IMarker.TASK);
703 		class Listener1 implements IResourceChangeListener {
704 			public boolean done = false;
705 
706 			@Override
707 			public void resourceChanged(IResourceChangeEvent event) {
708 				done = true;
709 				IMarkerDelta[] deltas = event.findMarkerDeltas(IMarker.TASK, false);
710 				assertEquals("1.0", 1, deltas.length);
711 				assertEquals("1.1", marker.getId(), deltas[0].getId());
712 				assertEquals("1.2", IResourceDelta.REMOVED, deltas[0].getKind());
713 				synchronized (this) {
714 					notifyAll();
715 				}
716 			}
717 		}
718 		Listener1 listener = new Listener1();
719 		try {
720 			getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
721 			project1.delete(true, false, getMonitor());
722 			synchronized (listener) {
723 				int i = 0;
724 				while (!listener.done) {
725 					try {
726 						listener.wait(1000);
727 					} catch (InterruptedException e) {
728 					}
729 					assertTrue("2.0", ++i < 60);
730 				}
731 			}
732 		} finally {
733 			getWorkspace().removeResourceChangeListener(listener);
734 		}
735 	}
736 
testDeleteFolderDuringRefresh()737 	public void testDeleteFolderDuringRefresh() throws CoreException {
738 		project1 = getWorkspace().getRoot().getProject(getUniqueString());
739 		project1.create(getMonitor());
740 		project1.open(getMonitor());
741 
742 		project2 = getWorkspace().getRoot().getProject(getUniqueString());
743 		project2.create(getMonitor());
744 		project2.open(getMonitor());
745 
746 		assertTrue("1.0", project1.isOpen());
747 		assertTrue("2.0", project2.isOpen());
748 
749 		final IFolder f = project1.getFolder(getUniqueString());
750 		f.create(true, true, getMonitor());
751 
752 		// the listener checks if an attempt to modify the tree succeeds if made in a job
753 		// that belongs to FAMILY_MANUAL_REFRESH
754 		class Listener1 implements IResourceChangeListener {
755 			public boolean wasPerformed = false;
756 
757 			@Override
758 			public void resourceChanged(IResourceChangeEvent event) {
759 				new Job("deleteFolder") {
760 					@Override
761 					public boolean belongsTo(Object family) {
762 						return family == ResourcesPlugin.FAMILY_MANUAL_REFRESH;
763 					}
764 
765 					@Override
766 					protected IStatus run(IProgressMonitor monitor) {
767 						try {
768 							f.delete(true, getMonitor());
769 							wasPerformed = true;
770 						} catch (Exception e) {
771 							fail("3.0", e);
772 						}
773 						return Status.OK_STATUS;
774 					}
775 				}.schedule();
776 			}
777 		}
778 
779 		Listener1 listener1 = new Listener1();
780 
781 		// perform a refresh to test the added listeners
782 		try {
783 			getWorkspace().addResourceChangeListener(listener1, IResourceChangeEvent.PRE_REFRESH);
784 
785 			project2.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
786 			Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_REFRESH, null);
787 
788 			assertTrue("4.0", listener1.wasPerformed);
789 			assertDoesNotExistInWorkspace("5.0", f);
790 		} catch (InterruptedException e) {
791 			fail("6.0", e);
792 		} catch (CoreException e) {
793 			fail("7.0", e);
794 		} finally {
795 			getWorkspace().removeResourceChangeListener(listener1);
796 		}
797 	}
798 
testRefreshOtherProjectDuringRefresh()799 	public void testRefreshOtherProjectDuringRefresh() throws Exception {
800 		final IProject p = getWorkspace().getRoot().getProject(getUniqueString());
801 		p.create(null);
802 		p.open(null);
803 
804 		project1 = getWorkspace().getRoot().getProject(getUniqueString());
805 		project1.create(null);
806 		project1.open(null);
807 
808 		assertTrue("1.0", p.isOpen());
809 		assertTrue("2.0", project1.isOpen());
810 
811 		// the listener checks if an attempt to modify the tree succeeds if made in a job
812 		// that belongs to FAMILY_MANUAL_REFRESH
813 		class Listener1 implements IResourceChangeListener {
814 			public boolean wasPerformed = false;
815 
816 			@Override
817 			public void resourceChanged(final IResourceChangeEvent event) {
818 				new Job("refreshProject") {
819 					@Override
820 					public boolean belongsTo(Object family) {
821 						return family == ResourcesPlugin.FAMILY_MANUAL_REFRESH;
822 					}
823 
824 					@Override
825 					protected IStatus run(IProgressMonitor monitor) {
826 						try {
827 							if (event.getResource() != p) {
828 								p.refreshLocal(IResource.DEPTH_INFINITE, null);
829 							}
830 							wasPerformed = true;
831 						} catch (Exception e) {
832 							fail("3.0", e);
833 						}
834 						return Status.OK_STATUS;
835 					}
836 				}.schedule();
837 			}
838 		}
839 
840 		Listener1 listener1 = new Listener1();
841 
842 		// the listener checks if an attempt to modify the tree in the refresh thread fails
843 		class Listener2 implements IResourceChangeListener {
844 			@Override
845 			public void resourceChanged(IResourceChangeEvent event) {
846 				try {
847 					if (event.getResource() != p) {
848 						p.refreshLocal(IResource.DEPTH_INFINITE, null);
849 					}
850 					fail("4.0");
851 				} catch (Exception e) {
852 					// should fail
853 				}
854 			}
855 		}
856 
857 		Listener2 listener2 = new Listener2();
858 
859 		// perform a refresh to test the added listeners
860 		try {
861 			getWorkspace().addResourceChangeListener(listener1, IResourceChangeEvent.PRE_REFRESH);
862 			getWorkspace().addResourceChangeListener(listener2, IResourceChangeEvent.PRE_REFRESH);
863 
864 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
865 			Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_REFRESH, null);
866 
867 			assertTrue("5.0", listener1.wasPerformed);
868 		} catch (InterruptedException e) {
869 			fail("6.0", e);
870 		} catch (CoreException e) {
871 			fail("7.0", e);
872 		} finally {
873 			getWorkspace().removeResourceChangeListener(listener1);
874 			getWorkspace().removeResourceChangeListener(listener2);
875 		}
876 	}
877 
testPreRefreshNotification()878 	public void testPreRefreshNotification() throws Exception {
879 		final IWorkspaceRoot root = getWorkspace().getRoot();
880 
881 		project1 = root.getProject(getUniqueString());
882 		project1.create(null);
883 		project1.open(null);
884 
885 		assertTrue("1.0", project1.isOpen());
886 
887 		class Listener1 implements IResourceChangeListener {
888 			public boolean wasPerformed = false;
889 			public Object eventSource;
890 			public Object eventResource;
891 
892 			@Override
893 			public void resourceChanged(final IResourceChangeEvent event) {
894 				wasPerformed = true;
895 				eventSource = event.getSource();
896 				eventResource = event.getResource();
897 			}
898 		}
899 
900 		Listener1 listener1 = new Listener1();
901 
902 		// perform a refresh to test the added listeners
903 		try {
904 			getWorkspace().addResourceChangeListener(listener1, IResourceChangeEvent.PRE_REFRESH);
905 
906 			root.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
907 			Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_REFRESH, null);
908 
909 			assertTrue("2.0", listener1.wasPerformed);
910 			assertEquals("3.0", getWorkspace(), listener1.eventSource);
911 			assertEquals("4.0", null, listener1.eventResource);
912 
913 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
914 			Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_REFRESH, null);
915 
916 			assertTrue("5.0", listener1.wasPerformed);
917 			assertEquals("6.0", project1, listener1.eventSource);
918 			assertEquals("7.0", project1, listener1.eventResource);
919 		} catch (InterruptedException e) {
920 			fail("8.0", e);
921 		} catch (CoreException e) {
922 			fail("9.0", e);
923 		} finally {
924 			getWorkspace().removeResourceChangeListener(listener1);
925 		}
926 	}
927 
928 	/**
929 	 * Tests that phantom members don't show up in resource deltas when standard
930 	 * traversal and visitor are used.
931 	 */
testHiddenPhantomChanges()932 	public void testHiddenPhantomChanges() {
933 		final IWorkspace workspace = getWorkspace();
934 		final IFolder phantomFolder = project1.getFolder("PhantomFolder");
935 		final IFile phantomFile = folder1.getFile("PhantomFile");
936 		final IResource[] phantomResources = new IResource[] {phantomFolder, phantomFile};
937 		final QualifiedName partner = new QualifiedName("Test", "Infected");
938 		IResourceChangeListener listener = event -> {
939 			//make sure the delta doesn't include the phantom members
940 			assertNotDeltaIncludes("1.0", event.getDelta(), phantomResources);
941 			//make sure a visitor does not find phantom members
942 			assertNotDeltaVisits("1.1", event.getDelta(), phantomResources);
943 		};
944 		workspace.addResourceChangeListener(listener);
945 		workspace.getSynchronizer().add(partner);
946 		ensureDoesNotExistInWorkspace(phantomResources);
947 		try {
948 			//create a phantom folder
949 			workspace.run((IWorkspaceRunnable) monitor -> workspace.getSynchronizer().setSyncInfo(partner, phantomFolder, new byte[] {1}), getMonitor());
950 			//create children in phantom folder
951 			IFile fileInFolder = phantomFolder.getFile("FileInPrivateFolder");
952 			workspace.getSynchronizer().setSyncInfo(partner, fileInFolder, new byte[] {1});
953 			//modify children in phantom folder
954 			workspace.getSynchronizer().setSyncInfo(partner, fileInFolder, new byte[] {2});
955 			//delete children in phantom folder
956 			workspace.getSynchronizer().flushSyncInfo(partner, fileInFolder, IResource.DEPTH_INFINITE);
957 			//delete phantom folder and change some other file
958 			workspace.run((IWorkspaceRunnable) monitor -> {
959 				phantomFolder.delete(IResource.NONE, getMonitor());
960 				file1.setContents(getRandomContents(), IResource.NONE, getMonitor());
961 			}, getMonitor());
962 			//create phantom file
963 			workspace.run((IWorkspaceRunnable) monitor -> workspace.getSynchronizer().setSyncInfo(partner, phantomFile, new byte[] {2}), getMonitor());
964 			//modify phantom file
965 			workspace.getSynchronizer().setSyncInfo(partner, phantomFile, new byte[] {3});
966 			//delete phantom file
967 			workspace.getSynchronizer().flushSyncInfo(partner, phantomFile, IResource.DEPTH_INFINITE);
968 		} catch (CoreException e) {
969 			handleCoreException(e);
970 		} finally {
971 			workspace.removeResourceChangeListener(listener);
972 		}
973 	}
974 
975 	/**
976 	 * Tests that team private members don't show up in resource deltas when
977 	 * standard traversal and visitor are used.
978 	 */
testHiddenTeamPrivateChanges()979 	public void testHiddenTeamPrivateChanges() {
980 		IWorkspace workspace = getWorkspace();
981 		final IFolder teamPrivateFolder = project1.getFolder("TeamPrivateFolder");
982 		final IFile teamPrivateFile = folder1.getFile("TeamPrivateFile");
983 		final IResource[] privateResources = new IResource[] {teamPrivateFolder, teamPrivateFile};
984 		IResourceChangeListener listener = event -> {
985 			//make sure the delta doesn't include the team private members
986 			assertNotDeltaIncludes("1.0", event.getDelta(), privateResources);
987 			//make sure a visitor does not find team private members
988 			assertNotDeltaVisits("1.1", event.getDelta(), privateResources);
989 		};
990 		workspace.addResourceChangeListener(listener);
991 		try {
992 			//create a team private folder
993 			workspace.run((IWorkspaceRunnable) monitor -> {
994 				teamPrivateFolder.create(true, true, getMonitor());
995 				teamPrivateFolder.setTeamPrivateMember(true);
996 			}, getMonitor());
997 			//create children in team private folder
998 			IFile fileInFolder = teamPrivateFolder.getFile("FileInPrivateFolder");
999 			fileInFolder.create(getRandomContents(), true, getMonitor());
1000 			//modify children in team private folder
1001 			fileInFolder.setContents(getRandomContents(), IResource.NONE, getMonitor());
1002 			//delete children in team private folder
1003 			fileInFolder.delete(IResource.NONE, getMonitor());
1004 			//delete team private folder and change some other file
1005 			workspace.run((IWorkspaceRunnable) monitor -> {
1006 				teamPrivateFolder.delete(IResource.NONE, getMonitor());
1007 				file1.setContents(getRandomContents(), IResource.NONE, getMonitor());
1008 			}, getMonitor());
1009 			//create team private file
1010 			workspace.run((IWorkspaceRunnable) monitor -> {
1011 				teamPrivateFile.create(getRandomContents(), true, getMonitor());
1012 				teamPrivateFile.setTeamPrivateMember(true);
1013 			}, getMonitor());
1014 			//modify team private file
1015 			teamPrivateFile.setContents(getRandomContents(), IResource.NONE, getMonitor());
1016 			//delete team private file
1017 			teamPrivateFile.delete(IResource.NONE, getMonitor());
1018 		} catch (CoreException e) {
1019 			handleCoreException(e);
1020 		} finally {
1021 			workspace.removeResourceChangeListener(listener);
1022 		}
1023 	}
1024 
testModifyMoveFile()1025 	public void testModifyMoveFile() {
1026 		try {
1027 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
1028 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1029 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM | IResourceDelta.CONTENT, file1.getFullPath(), null);
1030 			getWorkspace().run((IWorkspaceRunnable) m -> {
1031 				m.beginTask("Creating and moving", 100);
1032 				try {
1033 					folder2.create(true, true, SubMonitor.convert(m, 50));
1034 					file1.setContents(getRandomContents(), IResource.NONE, getMonitor());
1035 					file1.move(file3.getFullPath(), true, SubMonitor.convert(m, 50));
1036 				} finally {
1037 					m.done();
1038 				}
1039 			}, getMonitor());
1040 			assertDelta();
1041 		} catch (CoreException e) {
1042 			handleCoreException(e);
1043 		}
1044 	}
1045 
testMoveFile()1046 	public void testMoveFile() {
1047 		try {
1048 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
1049 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1050 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, file1.getFullPath(), null);
1051 			getWorkspace().run((IWorkspaceRunnable) m -> {
1052 				m.beginTask("Creating and moving", 100);
1053 				try {
1054 					folder2.create(true, true, SubMonitor.convert(m, 50));
1055 					file1.move(file3.getFullPath(), true, SubMonitor.convert(m, 50));
1056 				} finally {
1057 					m.done();
1058 				}
1059 			}, getMonitor());
1060 			assertDelta();
1061 		} catch (CoreException e) {
1062 			handleCoreException(e);
1063 		}
1064 	}
1065 
testMoveFileAddMarker()1066 	public void testMoveFileAddMarker() {
1067 		try {
1068 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
1069 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1070 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM | IResourceDelta.MARKERS, file1.getFullPath(), null);
1071 			getWorkspace().run((IWorkspaceRunnable) m -> {
1072 				m.beginTask("Creating and moving", 100);
1073 				try {
1074 					folder2.create(true, true, SubMonitor.convert(m, 50));
1075 					file1.move(file3.getFullPath(), true, SubMonitor.convert(m, 50));
1076 					file3.createMarker(IMarker.TASK);
1077 				} finally {
1078 					m.done();
1079 				}
1080 			}, getMonitor());
1081 			assertDelta();
1082 		} catch (CoreException e) {
1083 			handleCoreException(e);
1084 		}
1085 	}
1086 
1087 	/**
1088 	 * Regression test for bug 42514
1089 	 */
testMoveFileDeleteFolder()1090 	public void testMoveFileDeleteFolder() {
1091 		try {
1092 			//file2 moved to file1, and colliding folder3 is deleted
1093 			file1.delete(IResource.NONE, null);
1094 			file2.create(getRandomContents(), IResource.NONE, null);
1095 			folder3.create(IResource.NONE, true, null);
1096 			verifier.reset();
1097 			verifier.addExpectedChange(file2, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file1.getFullPath());
1098 			int flags = IResourceDelta.MOVED_FROM | IResourceDelta.REPLACED | IResourceDelta.TYPE | IResourceDelta.CONTENT;
1099 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, flags, file2.getFullPath(), null);
1100 			getWorkspace().run((IWorkspaceRunnable) m -> {
1101 				m.beginTask("Deleting and moving", 100);
1102 				try {
1103 					folder3.delete(IResource.FORCE, SubMonitor.convert(m, 50));
1104 					file2.move(file1.getFullPath(), true, SubMonitor.convert(m, 50));
1105 				} finally {
1106 					m.done();
1107 				}
1108 			}, getMonitor());
1109 			assertDelta();
1110 		} catch (CoreException e) {
1111 			handleCoreException(e);
1112 		}
1113 	}
1114 
testMoveFileDeleteSourceParent()1115 	public void testMoveFileDeleteSourceParent() {
1116 		try {
1117 			file1.delete(IResource.NONE, null);
1118 			create(file3, true);
1119 			verifier.reset();
1120 			verifier.addExpectedChange(folder2, IResourceDelta.REMOVED, 0, null, null);
1121 			verifier.addExpectedChange(file1, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, file3.getFullPath(), null);
1122 			verifier.addExpectedChange(file3, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file1.getFullPath());
1123 			getWorkspace().run((IWorkspaceRunnable) m -> {
1124 				m.beginTask("Creating and moving", 100);
1125 				try {
1126 					file3.move(file1.getFullPath(), true, SubMonitor.convert(m, 50));
1127 					folder2.delete(IResource.NONE, SubMonitor.convert(m, 50));
1128 				} finally {
1129 					m.done();
1130 				}
1131 			}, getMonitor());
1132 			assertDelta();
1133 		} catch (CoreException e) {
1134 			handleCoreException(e);
1135 		}
1136 	}
1137 
testMoveModifyFile()1138 	public void testMoveModifyFile() {
1139 		try {
1140 			verifier.addExpectedChange(folder2, IResourceDelta.ADDED, 0);
1141 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1142 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM | IResourceDelta.CONTENT, file1.getFullPath(), null);
1143 			getWorkspace().run((IWorkspaceRunnable) m -> {
1144 				m.beginTask("Creating and moving", 100);
1145 				try {
1146 					folder2.create(true, true, SubMonitor.convert(m, 50));
1147 					file1.move(file3.getFullPath(), true, SubMonitor.convert(m, 50));
1148 					file3.setContents(getRandomContents(), IResource.NONE, getMonitor());
1149 				} finally {
1150 					m.done();
1151 				}
1152 			}, getMonitor());
1153 			assertDelta();
1154 		} catch (CoreException e) {
1155 			handleCoreException(e);
1156 		}
1157 	}
1158 
testMoveMoveFile()1159 	public void testMoveMoveFile() {
1160 		file2 = project1.getFile("File2");
1161 		file3 = project1.getFile("File3");
1162 		try {
1163 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1164 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, file1.getFullPath(), null);
1165 			getWorkspace().run((IWorkspaceRunnable) m -> {
1166 				m.beginTask("moving and moving file", 100);
1167 				try {
1168 					file1.move(file2.getFullPath(), false, null);
1169 					file2.move(file3.getFullPath(), false, null);
1170 				} finally {
1171 					m.done();
1172 				}
1173 			}, getMonitor());
1174 			assertDelta();
1175 		} catch (CoreException e) {
1176 			handleCoreException(e);
1177 		}
1178 	}
1179 
testMoveMoveFolder()1180 	public void testMoveMoveFolder() {
1181 		folder2 = project1.getFolder("Folder2");
1182 		folder3 = project1.getFolder("Folder3");
1183 		file3 = folder3.getFile(file1.getName());
1184 		try {
1185 			verifier.addExpectedChange(folder1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, folder3.getFullPath());
1186 			verifier.addExpectedChange(folder3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, folder1.getFullPath(), null);
1187 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, file3.getFullPath());
1188 			verifier.addExpectedChange(file3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, file1.getFullPath(), null);
1189 			getWorkspace().run((IWorkspaceRunnable) m -> {
1190 				m.beginTask("moving and moving folder", 100);
1191 				try {
1192 					folder1.move(folder2.getFullPath(), false, null);
1193 					folder2.move(folder3.getFullPath(), false, null);
1194 				} finally {
1195 					m.done();
1196 				}
1197 			}, getMonitor());
1198 			assertDelta();
1199 		} catch (CoreException e) {
1200 			handleCoreException(e);
1201 		}
1202 	}
1203 
1204 	/**
1205 	 * Move a project via rename. Note that the DESCRIPTION flag should be set
1206 	 * in the delta for the destination only.
1207 	 */
testMoveProject1()1208 	public void testMoveProject1() {
1209 		try {
1210 			verifier.reset();
1211 			verifier.addExpectedChange(project1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, project2.getFullPath());
1212 			verifier.addExpectedChange(project1.getFile(".project"), IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, project2.getFile(".project").getFullPath());
1213 			verifier.addExpectedChange(folder1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, project2.getFolder(folder1.getProjectRelativePath()).getFullPath());
1214 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, project2.getFile(file1.getProjectRelativePath()).getFullPath());
1215 			verifier.addExpectedChange(project2, IResourceDelta.ADDED, IResourceDelta.OPEN | IResourceDelta.DESCRIPTION | IResourceDelta.MOVED_FROM, project1.getFullPath(), null);
1216 			verifier.addExpectedChange(project2.getFile(".project"), IResourceDelta.ADDED, IResourceDelta.CONTENT | IResourceDelta.MOVED_FROM, project1.getFile(".project").getFullPath(), null);
1217 			verifier.addExpectedChange(project2.getFolder(folder1.getProjectRelativePath()), IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, folder1.getFullPath(), null);
1218 			verifier.addExpectedChange(project2.getFile(file1.getProjectRelativePath()), IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, file1.getFullPath(), null);
1219 			getWorkspace().run((IWorkspaceRunnable) m -> {
1220 				m.beginTask("Creating and moving", 100);
1221 				try {
1222 					project1.move(project2.getFullPath(), IResource.NONE, SubMonitor.convert(m, 50));
1223 				} finally {
1224 					m.done();
1225 				}
1226 			}, getMonitor());
1227 			assertDelta();
1228 		} catch (CoreException e) {
1229 			handleCoreException(e);
1230 		}
1231 	}
1232 
1233 	/**
1234 	 * Move a project via a location change only. Note that the DESCRIPTION flag
1235 	 * should be set in the delta.
1236 	 */
testMoveProject2()1237 	public void testMoveProject2() {
1238 		final IPath path = getRandomLocation();
1239 		try {
1240 			verifier.addExpectedChange(project1, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
1241 			getWorkspace().run((IWorkspaceRunnable) m -> {
1242 				m.beginTask("Creating and moving", 100);
1243 				try {
1244 					IProjectDescription desc = project1.getDescription();
1245 					desc.setLocation(path);
1246 					project1.move(desc, IResource.NONE, SubMonitor.convert(m, 50));
1247 				} finally {
1248 					m.done();
1249 				}
1250 			}, getMonitor());
1251 			assertDelta();
1252 		} catch (CoreException e) {
1253 			handleCoreException(e);
1254 		} finally {
1255 			Workspace.clear(path.toFile());
1256 		}
1257 	}
1258 
testMulti()1259 	public void testMulti() {
1260 		class Listener1 implements IResourceChangeListener {
1261 			public boolean done = false;
1262 
1263 			@Override
1264 			public void resourceChanged(IResourceChangeEvent event) {
1265 				assertEquals("1.0", IResourceChangeEvent.POST_CHANGE, event.getType());
1266 				done = true;
1267 			}
1268 		}
1269 		class Listener2 extends Listener1 implements IResourceChangeListener {
1270 			@Override
1271 			public void resourceChanged(IResourceChangeEvent event) {
1272 				assertEquals("2.0", IResourceChangeEvent.POST_BUILD, event.getType());
1273 				done = true;
1274 			}
1275 		}
1276 		Listener1 listener1 = new Listener1();
1277 		Listener2 listener2 = new Listener2();
1278 		getWorkspace().addResourceChangeListener(listener1, IResourceChangeEvent.POST_CHANGE);
1279 		getWorkspace().addResourceChangeListener(listener2, IResourceChangeEvent.POST_BUILD);
1280 		try {
1281 			try {
1282 				project1.touch(getMonitor());
1283 			} catch (CoreException e) {
1284 				handleCoreException(e);
1285 			}
1286 			int i = 0;
1287 			while (!(listener1.done && listener2.done)) {
1288 				//timeout if the listeners are never called
1289 				assertTrue("3.0", ++i < 600);
1290 				try {
1291 					Thread.sleep(100);
1292 				} catch (InterruptedException e1) {
1293 				}
1294 			}
1295 		} finally {
1296 			getWorkspace().removeResourceChangeListener(listener1);
1297 			getWorkspace().removeResourceChangeListener(listener2);
1298 		}
1299 	}
1300 
testProjectDescriptionComment()1301 	public void testProjectDescriptionComment() {
1302 		try {
1303 			/* change file1's contents */
1304 			verifier.addExpectedChange(project1, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
1305 			verifier.addExpectedChange(project1MetaData, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1306 			IProjectDescription description = project1.getDescription();
1307 			description.setComment("new comment");
1308 			project1.setDescription(description, IResource.NONE, getMonitor());
1309 			assertDelta();
1310 		} catch (CoreException e) {
1311 			handleCoreException(e);
1312 		}
1313 	}
1314 
testProjectDescriptionDynamicRefs()1315 	public void testProjectDescriptionDynamicRefs() {
1316 		try {
1317 			/* change file1's contents */
1318 			verifier.addExpectedChange(project1, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
1319 			IProjectDescription description = project1.getDescription();
1320 			description.setDynamicReferences(new IProject[] {project2});
1321 			project1.setDescription(description, IResource.NONE, getMonitor());
1322 			assertDelta();
1323 		} catch (CoreException e) {
1324 			handleCoreException(e);
1325 		}
1326 	}
1327 
testProjectDescriptionNatures()1328 	public void testProjectDescriptionNatures() {
1329 		try {
1330 			/* change file1's contents */
1331 			verifier.addExpectedChange(project1, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
1332 			verifier.addExpectedChange(project1MetaData, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1333 			IProjectDescription description = project1.getDescription();
1334 			description.setNatureIds(new String[] {NATURE_SIMPLE});
1335 			project1.setDescription(description, IResource.NONE, getMonitor());
1336 			assertDelta();
1337 		} catch (CoreException e) {
1338 			handleCoreException(e);
1339 		}
1340 	}
1341 
testProjectDescriptionStaticRefs()1342 	public void testProjectDescriptionStaticRefs() {
1343 		try {
1344 			/* change file1's contents */
1345 			verifier.addExpectedChange(project1, IResourceDelta.CHANGED, IResourceDelta.DESCRIPTION);
1346 			verifier.addExpectedChange(project1MetaData, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1347 			IProjectDescription description = project1.getDescription();
1348 			description.setReferencedProjects(new IProject[] {project2});
1349 			project1.setDescription(description, IResource.NONE, getMonitor());
1350 			assertDelta();
1351 		} catch (CoreException e) {
1352 			handleCoreException(e);
1353 		}
1354 	}
1355 
testRemoveFile()1356 	public void testRemoveFile() {
1357 		try {
1358 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, 0);
1359 			file1.delete(true, getMonitor());
1360 			assertDelta();
1361 		} catch (CoreException e) {
1362 			handleCoreException(e);
1363 		}
1364 	}
1365 
testRemoveFileAndFolder()1366 	public void testRemoveFileAndFolder() {
1367 		try {
1368 			verifier.addExpectedChange(folder1, IResourceDelta.REMOVED, 0);
1369 			verifier.addExpectedChange(file1, IResourceDelta.REMOVED, 0);
1370 			folder1.delete(true, getMonitor());
1371 			assertDelta();
1372 		} catch (CoreException e) {
1373 			handleCoreException(e);
1374 		}
1375 	}
1376 
testReplaceFile()1377 	public void testReplaceFile() {
1378 		try {
1379 			/* change file1's contents */
1380 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.REPLACED | IResourceDelta.CONTENT);
1381 			getWorkspace().run((IWorkspaceRunnable) m -> {
1382 				m.beginTask("Deleting and Creating", 100);
1383 				try {
1384 					file1.delete(true, SubMonitor.convert(m, 50));
1385 					file1.create(getRandomContents(), true, SubMonitor.convert(m, 50));
1386 				} finally {
1387 					m.done();
1388 				}
1389 			}, getMonitor());
1390 			assertDelta();
1391 		} catch (CoreException e) {
1392 			handleCoreException(e);
1393 		}
1394 	}
1395 
testReplaceFolderWithFolder()1396 	public void testReplaceFolderWithFolder() {
1397 		try {
1398 			folder2 = project1.getFolder("Folder2");
1399 			folder3 = project1.getFolder("Folder3");
1400 			verifier.reset();
1401 			getWorkspace().run((IWorkspaceRunnable) m -> {
1402 				file1.delete(false, null);
1403 				folder2.create(false, true, null);
1404 			}, null);
1405 			verifier.reset();
1406 			verifier.addExpectedChange(folder1, IResourceDelta.REMOVED, IResourceDelta.MOVED_TO, null, folder2.getFullPath());
1407 			int flags = IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO | IResourceDelta.REPLACED | IResourceDelta.CONTENT;
1408 			verifier.addExpectedChange(folder2, IResourceDelta.CHANGED, flags, folder1.getFullPath(), folder3.getFullPath());
1409 			verifier.addExpectedChange(folder3, IResourceDelta.ADDED, IResourceDelta.MOVED_FROM, folder2.getFullPath(), null);
1410 			getWorkspace().run((IWorkspaceRunnable) m -> {
1411 				m.beginTask("replace folder with folder", 100);
1412 				try {
1413 					folder2.move(folder3.getFullPath(), false, null);
1414 					folder1.move(folder2.getFullPath(), false, null);
1415 				} finally {
1416 					m.done();
1417 				}
1418 			}, getMonitor());
1419 			assertDelta();
1420 		} catch (CoreException e) {
1421 			handleCoreException(e);
1422 		}
1423 	}
1424 
testSetLocal()1425 	public void testSetLocal() {
1426 		try {
1427 			verifier.reset();
1428 			//set local on a file that is already local -- should be no change
1429 			file1.setLocal(true, IResource.DEPTH_INFINITE, getMonitor());
1430 			assertTrue("Unexpected notification on no change", !verifier.hasBeenNotified());
1431 			//set non-local, still shouldn't appear in delta
1432 			verifier.reset();
1433 			file1.setLocal(false, IResource.DEPTH_INFINITE, getMonitor());
1434 			assertTrue("Unexpected notification on no change", !verifier.hasBeenNotified());
1435 		} catch (CoreException e) {
1436 			handleCoreException(e);
1437 		}
1438 	}
1439 
testSwapFiles()1440 	public void testSwapFiles() {
1441 		try {
1442 			file1 = project1.getFile("File1");
1443 			file2 = project1.getFile("File2");
1444 			file3 = project1.getFile("File3");
1445 			verifier.reset();
1446 			getWorkspace().run((IWorkspaceRunnable) m -> {
1447 				file1.create(new ByteArrayInputStream(new byte[] {65}), false, null);
1448 				file2.create(new ByteArrayInputStream(new byte[] {67}), false, null);
1449 			}, null);
1450 			verifier.reset();
1451 			final int flags = IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO | IResourceDelta.REPLACED | IResourceDelta.CONTENT;
1452 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, flags, file2.getFullPath(), file2.getFullPath());
1453 			verifier.addExpectedChange(file2, IResourceDelta.CHANGED, flags, file1.getFullPath(), file1.getFullPath());
1454 			getWorkspace().run((IWorkspaceRunnable) m -> {
1455 				m.beginTask("swap files", 100);
1456 				try {
1457 					file1.move(file3.getFullPath(), false, null);
1458 					file2.move(file1.getFullPath(), false, null);
1459 					file3.move(file2.getFullPath(), false, null);
1460 				} finally {
1461 					m.done();
1462 				}
1463 			}, getMonitor());
1464 			assertDelta();
1465 		} catch (CoreException e) {
1466 			handleCoreException(e);
1467 		}
1468 	}
1469 
testSwapFolders()1470 	public void testSwapFolders() {
1471 		try {
1472 			verifier.reset();
1473 			getWorkspace().run((IWorkspaceRunnable) m -> {
1474 				folder2 = project1.getFolder("Folder2");
1475 				folder3 = project1.getFolder("Folder3");
1476 				file1.delete(false, null);
1477 				folder2.create(false, true, null);
1478 			}, null);
1479 			verifier.reset();
1480 			final int flags = IResourceDelta.MOVED_FROM | IResourceDelta.MOVED_TO | IResourceDelta.REPLACED | IResourceDelta.CONTENT;
1481 			verifier.addExpectedChange(folder1, IResourceDelta.CHANGED, flags, folder2.getFullPath(), folder2.getFullPath());
1482 			verifier.addExpectedChange(folder2, IResourceDelta.CHANGED, flags, folder1.getFullPath(), folder1.getFullPath());
1483 			getWorkspace().run((IWorkspaceRunnable) m -> {
1484 				m.beginTask("swap folders", 100);
1485 				try {
1486 					folder1.move(folder3.getFullPath(), false, null);
1487 					folder2.move(folder1.getFullPath(), false, null);
1488 					folder3.move(folder2.getFullPath(), false, null);
1489 				} finally {
1490 					m.done();
1491 				}
1492 			}, getMonitor());
1493 			assertDelta();
1494 		} catch (CoreException e) {
1495 			handleCoreException(e);
1496 		}
1497 	}
1498 
1499 	/**
1500 	 * Asserts that the delta is correct for changes to team private members.
1501 	 */
testTeamPrivateChanges()1502 	public void testTeamPrivateChanges() {
1503 		IWorkspace workspace = getWorkspace();
1504 		final IFolder teamPrivateFolder = project1.getFolder("TeamPrivateFolder");
1505 		final IFile teamPrivateFile = folder1.getFile("TeamPrivateFile");
1506 		try {
1507 			//create a team private folder
1508 			verifier.reset();
1509 			verifier.addExpectedChange(teamPrivateFolder, IResourceDelta.ADDED, 0);
1510 			workspace.run((IWorkspaceRunnable) monitor -> {
1511 				teamPrivateFolder.create(true, true, getMonitor());
1512 				teamPrivateFolder.setTeamPrivateMember(true);
1513 			}, getMonitor());
1514 			assertDelta();
1515 			verifier.reset();
1516 			//create children in team private folder
1517 			IFile fileInFolder = teamPrivateFolder.getFile("FileInPrivateFolder");
1518 			verifier.addExpectedChange(fileInFolder, IResourceDelta.ADDED, 0);
1519 			fileInFolder.create(getRandomContents(), true, getMonitor());
1520 			assertDelta();
1521 			verifier.reset();
1522 			//modify children in team private folder
1523 			verifier.addExpectedChange(fileInFolder, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1524 			fileInFolder.setContents(getRandomContents(), IResource.NONE, getMonitor());
1525 			assertDelta();
1526 			verifier.reset();
1527 			//delete children in team private folder
1528 			verifier.addExpectedChange(fileInFolder, IResourceDelta.REMOVED, 0);
1529 			fileInFolder.delete(IResource.NONE, getMonitor());
1530 			assertDelta();
1531 			verifier.reset();
1532 			//delete team private folder and change some other file
1533 			verifier.addExpectedChange(teamPrivateFolder, IResourceDelta.REMOVED, 0);
1534 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1535 			workspace.run((IWorkspaceRunnable) monitor -> {
1536 				teamPrivateFolder.delete(IResource.NONE, getMonitor());
1537 				file1.setContents(getRandomContents(), IResource.NONE, getMonitor());
1538 			}, getMonitor());
1539 			assertDelta();
1540 			verifier.reset();
1541 			//create team private file
1542 			verifier.addExpectedChange(teamPrivateFile, IResourceDelta.ADDED, 0);
1543 			workspace.run((IWorkspaceRunnable) monitor -> {
1544 				teamPrivateFile.create(getRandomContents(), true, getMonitor());
1545 				teamPrivateFile.setTeamPrivateMember(true);
1546 			}, getMonitor());
1547 			assertDelta();
1548 			verifier.reset();
1549 			//modify team private file
1550 			verifier.addExpectedChange(teamPrivateFile, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1551 			teamPrivateFile.setContents(getRandomContents(), IResource.NONE, getMonitor());
1552 			assertDelta();
1553 			verifier.reset();
1554 			//delete team private file
1555 			verifier.addExpectedChange(teamPrivateFile, IResourceDelta.REMOVED, 0);
1556 			teamPrivateFile.delete(IResource.NONE, getMonitor());
1557 			assertDelta();
1558 			verifier.reset();
1559 		} catch (CoreException e) {
1560 			handleCoreException(e);
1561 		}
1562 	}
1563 
testTwoFileChanges()1564 	public void testTwoFileChanges() {
1565 		try {
1566 			verifier.addExpectedChange(file1, IResourceDelta.CHANGED, IResourceDelta.CONTENT);
1567 			verifier.addExpectedChange(file2, IResourceDelta.ADDED, 0);
1568 			getWorkspace().run((IWorkspaceRunnable) m -> {
1569 				m.beginTask("setting contents and creating", 100);
1570 				try {
1571 					file1.setContents(getRandomContents(), true, false, SubMonitor.convert(m, 50));
1572 					file2.create(getRandomContents(), true, SubMonitor.convert(m, 50));
1573 				} finally {
1574 					m.done();
1575 				}
1576 			}, getMonitor());
1577 			assertDelta();
1578 		} catch (CoreException e) {
1579 			handleCoreException(e);
1580 		}
1581 	}
1582 
testRemoveAndCreateUnderlyingFileForLinkedResource()1583 	public void testRemoveAndCreateUnderlyingFileForLinkedResource() {
1584 		IPath path = getTempDir().addTrailingSeparator().append(getUniqueString());
1585 		try {
1586 			try {
1587 				path.toFile().createNewFile();
1588 			} catch (IOException e) {
1589 				fail("1.0", e);
1590 			}
1591 			IFile linkedFile = project1.getFile(getUniqueString());
1592 			linkedFile.createLink(path, IResource.NONE, getMonitor());
1593 
1594 			// check the delta when underlying file is removed
1595 			verifier.addExpectedChange(linkedFile, IResourceDelta.CHANGED, IResourceDelta.LOCAL_CHANGED);
1596 			path.toFile().delete();
1597 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
1598 			assertDelta();
1599 
1600 			// check the delta when underlying file is recreated
1601 			verifier.addExpectedChange(linkedFile, IResourceDelta.CHANGED, IResourceDelta.LOCAL_CHANGED | IResourceDelta.CONTENT);
1602 			try {
1603 				path.toFile().createNewFile();
1604 			} catch (IOException e) {
1605 				fail("2.0", e);
1606 			}
1607 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
1608 			assertDelta();
1609 		} catch (CoreException e) {
1610 			handleCoreException(e);
1611 		} finally {
1612 			if (path.toFile().exists()) {
1613 				path.toFile().delete();
1614 			}
1615 		}
1616 	}
1617 
testRemoveAndCreateUnderlyingFolderForLinkedResource()1618 	public void testRemoveAndCreateUnderlyingFolderForLinkedResource() {
1619 		IPath path = getTempDir().addTrailingSeparator().append(getUniqueString());
1620 		try {
1621 			path.toFile().mkdir();
1622 			IFolder linkedFolder = project1.getFolder(getUniqueString());
1623 			linkedFolder.createLink(path, IResource.NONE, getMonitor());
1624 
1625 			// check the delta when underlying folder is removed
1626 			verifier.addExpectedChange(linkedFolder, IResourceDelta.CHANGED, IResourceDelta.LOCAL_CHANGED);
1627 			path.toFile().delete();
1628 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
1629 			assertDelta();
1630 
1631 			// check the delta when underlying folder is recreated
1632 			verifier.addExpectedChange(linkedFolder, IResourceDelta.CHANGED, IResourceDelta.LOCAL_CHANGED);
1633 			path.toFile().mkdir();
1634 			project1.refreshLocal(IResource.DEPTH_INFINITE, getMonitor());
1635 			assertDelta();
1636 		} catch (CoreException e) {
1637 			handleCoreException(e);
1638 		} finally {
1639 			if (path.toFile().exists()) {
1640 				path.toFile().delete();
1641 			}
1642 		}
1643 	}
1644 
testBug228354()1645 	public void testBug228354() {
1646 		IPath path = getTempDir().addTrailingSeparator().append(getUniqueString());
1647 		try {
1648 			path.toFile().mkdir();
1649 			IFolder linkedFolder = project1.getFolder(getUniqueString());
1650 			linkedFolder.createLink(path, IResource.NONE, getMonitor());
1651 
1652 			IFolder regularFolder = project1.getFolder(getUniqueString());
1653 			regularFolder.create(true, true, getMonitor());
1654 
1655 			// check the delta when underlying folder is removed
1656 			verifier.addExpectedChange(regularFolder, IResourceDelta.REMOVED, 0);
1657 			regularFolder.delete(true, getMonitor());
1658 			assertDelta();
1659 		} catch (CoreException e) {
1660 			handleCoreException(e);
1661 		} finally {
1662 			if (path.toFile().exists()) {
1663 				path.toFile().delete();
1664 			}
1665 		}
1666 	}
1667 }