blob: 3843f2394df73a736f73a309538e1e92f025aa90 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.resource.impl;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Resource related tests.
*/
public class ClassPathEntryTest extends AbstractResourceOrientedTestBase {
/**
* This test will likely not work on Windows since directories that start with . are not
* implicitly hidden there. But since Java 6 does not have a File.setHidden() function, fixing
* this test for Windows is deferred till GWT officially depends on Java 7.
*/
public void testIgnoresHiddenDirectories() throws IOException {
// Setup a /tmp/.svn/ShouldNotBeFound.java folder structure.
File tempDir = Files.createTempDir();
File nestedHiddenDir = new File(tempDir, ".svn");
nestedHiddenDir.mkdir();
File javaFile = new File(nestedHiddenDir, "ShouldNotBeFound.java");
javaFile.createNewFile();
// Perform a class path directory inspection.
DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(tempDir);
Map<AbstractResource, ResourceResolution> resources =
cpe.findApplicableResources(TreeLogger.NULL, createInclusivePathPrefixSet());
// Verify that even though we're using an ALL filter, we still didn't find any files inside the
// .svn dir, because we never even enumerate its contents.
assertTrue(resources.isEmpty());
}
public void testResourceCreated() throws IOException, InterruptedException {
// With just 1 filter definition.
testResourceCreated(Lists.newArrayList(createInclusivePathPrefixSet()));
// With multiple filter definitions.
testResourceCreated(Lists.newArrayList(createInclusivePathPrefixSet(),
createInclusivePathPrefixSet(), createInclusivePathPrefixSet()));
}
public void testForResourceListenerLeaks_pathPrefixSetIsCollected() throws Exception {
// Create a folder an initially empty folder.
PathPrefixSet pathPrefixSet = createInclusivePathPrefixSet();
DirectoryClassPathEntry classPathEntry = new DirectoryClassPathEntry(Files.createTempDir());
// Show that we are not listening.
awaitFullGc();
assertEquals(0, ResourceAccumulatorManager.getActiveListenerCount());
// Start listening for updates.
ResourceAccumulatorManager.getResources(classPathEntry, pathPrefixSet);
// Show that we are now listening for updates.
awaitFullGc();
assertEquals(1, ResourceAccumulatorManager.getActiveListenerCount());
// Dereference the pathPrefixSet to give garbage collector an opportunity to clear any weak
// references.
pathPrefixSet = null;
// Show that we are no longer listening for updates.
awaitFullGc();
assertEquals(0, ResourceAccumulatorManager.getActiveListenerCount());
// Make sure classPathEntry is not GC'd until this point.
assertNotNull(classPathEntry);
}
public void testForResourceListenerLeaks_classPathEntryIsCollected() throws Exception {
// Create a folder an initially empty folder.
PathPrefixSet pathPrefixSet = createInclusivePathPrefixSet();
DirectoryClassPathEntry classPathEntry = new DirectoryClassPathEntry(Files.createTempDir());
// Show that we are not listening.
awaitFullGc();
assertEquals(0, ResourceAccumulatorManager.getActiveListenerCount());
// Start listening for updates.
ResourceAccumulatorManager.getResources(classPathEntry, pathPrefixSet);
// Show that we are now listening for updates.
awaitFullGc();
assertEquals(1, ResourceAccumulatorManager.getActiveListenerCount());
// Dereference the classPathEntry to give the garbage collector an opportunity to clear any weak
// references.
classPathEntry = null;
// Show that we are no longer listening for updates.
awaitFullGc();
assertEquals(0, ResourceAccumulatorManager.getActiveListenerCount());
// Make sure pathPrefixSet is not GC'd until this point.
assertNotNull(pathPrefixSet);
}
public void testResourceCreated(Collection<PathPrefixSet> pathPrefixSets) throws IOException,
InterruptedException {
// Create a folder an initially empty folder.
File tempDir = Files.createTempDir();
DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(tempDir);
// Perform a class path directory inspection.
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the directory is initially empty.
assertTrue(foundResources.isEmpty());
}
// Create a file and give file events time to fire.
File createdFile = new File(tempDir, "Created.java");
createdFile.createNewFile();
Thread.sleep(10);
// Perform a class path directory inspection.
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the directory is no longer empty.
assertEquals(1, foundResources.size());
assertEquals("Created.java", foundResources.keySet().iterator().next().getPath());
}
}
public void testResourceDeleted() throws IOException, InterruptedException {
// With just 1 filter definition.
testResourceDeleted(Lists.newArrayList(createInclusivePathPrefixSet()));
// With multiple filter definitions.
testResourceDeleted(Lists.newArrayList(createInclusivePathPrefixSet(),
createInclusivePathPrefixSet(), createInclusivePathPrefixSet()));
}
private void testResourceDeleted(Collection<PathPrefixSet> pathPrefixSets) throws IOException,
InterruptedException {
// Create a folder with one initial file, that can be deleted.
File tempDir = Files.createTempDir();
File fileToDelete = new File(tempDir, "ToDelete.java");
fileToDelete.createNewFile();
DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(tempDir);
// Perform a class path directory inspection.
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the directory is not initially empty.
assertEquals(1, foundResources.size());
assertEquals("ToDelete.java", foundResources.keySet().iterator().next().getPath());
}
// Delete the file and give file events time to fire.
fileToDelete.delete();
Thread.sleep(10);
// Perform a class path directory inspection.
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the directory is now empty.
assertTrue(foundResources.isEmpty());
}
}
public void testResourceRenamed() throws IOException, InterruptedException {
// With just 1 filter definition.
testResourceRenamed(Lists.newArrayList(createInclusivePathPrefixSet()));
// With multiple filter definitions.
testResourceRenamed(Lists.newArrayList(createInclusivePathPrefixSet(),
createInclusivePathPrefixSet(), createInclusivePathPrefixSet()));
}
private void testResourceRenamed(Collection<PathPrefixSet> pathPrefixSets) throws IOException,
InterruptedException {
// Create a folder with one initial file, that can be renamed.
File tempDir = Files.createTempDir();
File fileToRename = new File(tempDir, "ToRename.java");
fileToRename.createNewFile();
DirectoryClassPathEntry cpe = new DirectoryClassPathEntry(tempDir);
// Perform class path directory inspections.
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the directory is not initially empty.
assertEquals(1, foundResources.size());
assertEquals("ToRename.java", foundResources.keySet().iterator().next().getPath());
}
// Rename the file and give file events time to fire.
fileToRename.renameTo(new File(tempDir, "Renamed.java"));
Thread.sleep(10);
for (PathPrefixSet pathPrefixSet : pathPrefixSets) {
// Perform a class path directory inspection.
Map<AbstractResource, ResourceResolution> foundResources =
cpe.findApplicableResources(TreeLogger.NULL, pathPrefixSet);
// Verify the file is seen as renamed.
assertEquals(1, foundResources.size());
assertEquals("Renamed.java", foundResources.keySet().iterator().next().getPath());
}
}
public void testAllCpe1FilesFound() throws URISyntaxException, IOException {
testAllCpe1FilesFound(getClassPathEntry1AsJar());
testAllCpe1FilesFound(getClassPathEntry1AsDirectory());
testAllCpe1FilesFound(getClassPathEntry1AsZip());
}
public void testAllCpe2FilesFound() throws URISyntaxException, IOException {
testAllCpe2FilesFound(getClassPathEntry2AsJar());
testAllCpe2FilesFound(getClassPathEntry2AsDirectory());
testAllCpe2FilesFound(getClassPathEntry2AsZip());
}
public void testPathPrefixSetChanges() throws IOException, URISyntaxException {
ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
ClassPathEntry cpe1zip = getClassPathEntry1AsZip();
ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
ClassPathEntry cpe2zip = getClassPathEntry2AsZip();
testPathPrefixSetChanges(cpe1jar, cpe2jar);
testPathPrefixSetChanges(cpe1dir, cpe2jar);
testPathPrefixSetChanges(cpe1zip, cpe2jar);
testPathPrefixSetChanges(cpe1dir, cpe2dir);
testPathPrefixSetChanges(cpe1jar, cpe2dir);
testPathPrefixSetChanges(cpe1zip, cpe2dir);
testPathPrefixSetChanges(cpe1dir, cpe2zip);
testPathPrefixSetChanges(cpe1jar, cpe2zip);
testPathPrefixSetChanges(cpe1zip, cpe2zip);
}
public void testUseOfPrefixesWithFiltering() throws IOException,
URISyntaxException {
ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
ClassPathEntry cpe1zip = getClassPathEntry1AsZip();
ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
ClassPathEntry cpe2zip = getClassPathEntry2AsZip();
testUseOfPrefixesWithFiltering(cpe1dir, cpe2jar);
testUseOfPrefixesWithFiltering(cpe1jar, cpe2jar);
testUseOfPrefixesWithFiltering(cpe1dir, cpe2jar);
testUseOfPrefixesWithFiltering(cpe1zip, cpe2jar);
testUseOfPrefixesWithFiltering(cpe1dir, cpe2dir);
testUseOfPrefixesWithFiltering(cpe1jar, cpe2dir);
testUseOfPrefixesWithFiltering(cpe1zip, cpe2dir);
testUseOfPrefixesWithFiltering(cpe1dir, cpe2zip);
testUseOfPrefixesWithFiltering(cpe1jar, cpe2zip);
testUseOfPrefixesWithFiltering(cpe1zip, cpe2zip);
}
public void testUseOfPrefixesWithoutFiltering() throws URISyntaxException,
IOException {
ClassPathEntry cpe1jar = getClassPathEntry1AsJar();
ClassPathEntry cpe1dir = getClassPathEntry1AsDirectory();
ClassPathEntry cpe1zip = getClassPathEntry1AsZip();
ClassPathEntry cpe2jar = getClassPathEntry2AsJar();
ClassPathEntry cpe2dir = getClassPathEntry2AsDirectory();
ClassPathEntry cpe2zip = getClassPathEntry2AsZip();
testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2jar);
testUseOfPrefixesWithoutFiltering(cpe1jar, cpe2jar);
testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2jar);
testUseOfPrefixesWithoutFiltering(cpe1zip, cpe2jar);
testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2dir);
testUseOfPrefixesWithoutFiltering(cpe1jar, cpe2dir);
testUseOfPrefixesWithoutFiltering(cpe1zip, cpe2dir);
testUseOfPrefixesWithoutFiltering(cpe1dir, cpe2zip);
testUseOfPrefixesWithoutFiltering(cpe1jar, cpe2zip);
testUseOfPrefixesWithoutFiltering(cpe1zip, cpe2zip);
}
public void testUseOfPrefixesWithoutFiltering(ClassPathEntry cpe1,
ClassPathEntry cpe2) {
TreeLogger logger = createTestTreeLogger();
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("com/google/gwt/user/client/", null));
pps.add(new PathPrefix("com/google/gwt/i18n/client/", null));
{
// Examine cpe1.
Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r.size());
assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
}
{
// Examine cpe2.
Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(1, r.size());
assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
}
}
private static void awaitFullGc() throws InterruptedException {
Object object = new Object();
WeakReference<Object> objectReference = new WeakReference<Object>(object);
object = null;
System.gc();
while (objectReference.get() != null) {
Thread.sleep(10);
System.gc();
}
}
// NOTE: if this test fails, ensure that the source root containing this very
// source file is *FIRST* on the classpath
private void testAllCpe1FilesFound(ClassPathEntry cpe1) {
TreeLogger logger = createTestTreeLogger();
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("", null));
Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(9, r.size());
assertPathIncluded(r, "com/google/gwt/user/User.gwt.xml");
assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
assertPathIncluded(r, "org/example/bar/client/BarClient1.txt");
assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
assertPathIncluded(r, "org/example/bar/client/etc/BarEtc.txt");
assertPathIncluded(r, "org/example/foo/client/FooClient.java");
assertPathIncluded(r, "org/example/foo/server/FooServer.java");
}
// NOTE: if this test fails, ensure that the source root containing this very
// source file is on the classpath
private void testAllCpe2FilesFound(ClassPathEntry cpe2) {
TreeLogger logger = createTestTreeLogger();
PathPrefixSet pps = createInclusivePathPrefixSet();
Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(6, r.size());
assertPathIncluded(r, "com/google/gwt/i18n/I18N.gwt.xml");
assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
assertPathIncluded(r,
"com/google/gwt/i18n/rebind/LocalizableGenerator.java");
assertPathIncluded(r, "org/example/bar/client/BarClient2.txt");
assertPathIncluded(r, "org/example/bar/client/BarClient3.txt");
assertPathIncluded(r, "org/example/foo/client/BarClient1.txt");
}
private void testPathPrefixSetChanges(ClassPathEntry cpe1, ClassPathEntry cpe2) {
TreeLogger logger = createTestTreeLogger();
{
// Filter is not set yet.
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("com/google/gwt/user/", null));
pps.add(new PathPrefix("com/google/gwt/i18n/", null));
// Examine cpe1 in the absence of the filter.
Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(4, r1.size());
assertPathIncluded(r1, "com/google/gwt/user/User.gwt.xml");
assertPathIncluded(r1, "com/google/gwt/user/client/Command.java");
assertPathIncluded(r1, "com/google/gwt/user/client/Timer.java");
assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
// Examine cpe2 in the absence of the filter.
Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(3, r2.size());
assertPathIncluded(r2, "com/google/gwt/i18n/I18N.gwt.xml");
assertPathIncluded(r2, "com/google/gwt/i18n/client/Messages.java");
assertPathIncluded(r2,
"com/google/gwt/i18n/rebind/LocalizableGenerator.java");
}
{
// Create a pps with a filter.
ResourceFilter excludeXmlFiles = new ResourceFilter() {
@Override
public boolean allows(String path) {
return !path.endsWith(".xml");
}
};
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("com/google/gwt/user/", excludeXmlFiles));
pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
// Examine cpe1 in the presence of the filter.
Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r1.size());
assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
assertPathIncluded(r1, "com/google/gwt/user/client/Command.java");
assertPathIncluded(r1, "com/google/gwt/user/client/Timer.java");
assertPathIncluded(r1, "com/google/gwt/user/client/ui/Widget.java");
// Examine cpe2 in the presence of the filter.
Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(2, r2.size());
assertPathNotIncluded(r1, "com/google/gwt/user/User.gwt.xml");
assertPathIncluded(r2, "com/google/gwt/i18n/client/Messages.java");
assertPathIncluded(r2,
"com/google/gwt/i18n/rebind/LocalizableGenerator.java");
}
{
/*
* Change the prefix path set to the zero-lenth prefix (which allows
* everything), but specify a filter that disallows everything.
*/
PathPrefixSet pps = new PathPrefixSet();
pps.add(new PathPrefix("", new ResourceFilter() {
@Override
public boolean allows(String path) {
// Exclude everything.
return false;
}
}));
// Examine cpe1 in the presence of the filter.
Set<AbstractResource> r1 = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(0, r1.size());
// Examine cpe2 in the presence of the filter.
Set<AbstractResource> r2 = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(0, r2.size());
}
}
private void testUseOfPrefixesWithFiltering(ClassPathEntry cpe1,
ClassPathEntry cpe2) {
TreeLogger logger = createTestTreeLogger();
PathPrefixSet pps = new PathPrefixSet();
ResourceFilter excludeXmlFiles = new ResourceFilter() {
@Override
public boolean allows(String path) {
return !path.endsWith(".xml");
}
};
// The prefix is intentionally starting at the module-level, not 'client'.
pps.add(new PathPrefix("com/google/gwt/user/", excludeXmlFiles));
pps.add(new PathPrefix("com/google/gwt/i18n/", excludeXmlFiles));
{
// Examine cpe1.
Set<AbstractResource> r = cpe1.findApplicableResources(logger, pps).keySet();
assertEquals(3, r.size());
// User.gwt.xml would be included but for the filter.
assertPathIncluded(r, "com/google/gwt/user/client/Command.java");
assertPathIncluded(r, "com/google/gwt/user/client/Timer.java");
assertPathIncluded(r, "com/google/gwt/user/client/ui/Widget.java");
}
{
// Examine cpe2.
Set<AbstractResource> r = cpe2.findApplicableResources(logger, pps).keySet();
assertEquals(2, r.size());
// I18N.gwt.xml would be included but for the filter.
assertPathIncluded(r, "com/google/gwt/i18n/client/Messages.java");
assertPathIncluded(r,
"com/google/gwt/i18n/rebind/LocalizableGenerator.java");
}
}
private static PathPrefixSet createInclusivePathPrefixSet() {
PathPrefixSet pathPrefixes = new PathPrefixSet();
pathPrefixes.add(new PathPrefix("", null));
return pathPrefixes;
}
}