/******************************************************************************* * Copyright (c) 2009, 2015 EclipseSource and others. * 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://www.eclipse.org/legal/epl-v10.html * * Contributors: * EclipseSource - initial API and implementation *******************************************************************************/ package org.eclipse.rap.test; import java.io.*; import java.net.*; import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import org.eclipse.rap.rwt.testfixture.internal.Fixture; public class TestCollector { private static final String JAR_EXTENSION = ".jar"; private static final String CLASS_EXTENSION = ".class"; private final URLClassLoader classLoader; private final List<Thread> threads; private final List<Throwable> problems; private final List<Class<?>> tests; TestCollector() { classLoader = ( URLClassLoader )getClass().getClassLoader(); threads = new Vector<Thread>(); problems = new Vector<Throwable>(); tests = new Vector<Class<?>>(); } Class<?>[] collectTests() { initializeFixture(); try { scanClasspath(); } catch( IOException ioe ) { throw new RuntimeException( ioe ); } return sortTests(); } protected boolean acceptPath( File file ) { return file.toString().contains( ".test" ); } protected boolean acceptClassName( String className ) { return className.endsWith( "_Test" ); } private void scanClasspath() throws IOException { URL[] urls = classLoader.getURLs(); for( int i = 0; i < urls.length; i++ ) { File file = new File( URLDecoder.decode( urls[ i ].getFile(), "UTF-8" ) ); if( file.exists() && acceptPath( file ) ) { runScan( file ); } } waitForScan(); } private void waitForScan() { while( !threads.isEmpty() ) { Thread thread = threads.remove( 0 ); try { thread.join(); } catch( InterruptedException ie ) { throw new RuntimeException( ie ); } } handleProblems(); } private void handleProblems() { if( !problems.isEmpty() ) { Iterator<Throwable> iterator = problems.iterator(); while( iterator.hasNext() ) { Throwable exception = iterator.next(); exception.printStackTrace(); } throw new RuntimeException( "Unable to start test suite, see stacktraces." ); } } private void runScan( final File file ) { Thread thread = new Thread( new Runnable() { @Override public void run() { try { scan( file ); } catch( Throwable thr ) { problems.add( thr ); } } } ); threads.add( thread ); thread.setDaemon( true ); thread.start(); } private void scan( File file ) throws IOException { if( file.getName().endsWith( JAR_EXTENSION ) ) { scanJar( file ); } else { scanDirectory( file, "", file.getPath() ); } } private void scanJar( File file ) throws IOException { JarInputStream inputStream = new JarInputStream( new FileInputStream( file ), false ); try { JarEntry jarEntry = inputStream.getNextJarEntry(); while( jarEntry != null ) { if( isClassEntry( jarEntry ) ) { String className = toClassName( jarEntry ); addClass( className ); } jarEntry = inputStream.getNextJarEntry(); } } finally { inputStream.close(); } } private void scanDirectory( File file, String initialPackagePath, String rootDirectory ) { if( file.isDirectory() ) { String packagePath = computePackagePath( file, initialPackagePath, rootDirectory ); String[] files = file.list(); for( int i = 0; i < files.length; i++ ) { File directory = new File( file, files[ i ] ); scanDirectory( directory, packagePath, rootDirectory ); } } else if( isClassFile( file ) ) { String className = toClassName( file, initialPackagePath ); addClass( className ); } } private void addClass( String className ) { if( acceptClassName( className ) ) { try { tests.add( classLoader.loadClass( className ) ); } catch( ClassNotFoundException cnfe ) { throw new RuntimeException( cnfe ); } } } private Class<?>[] sortTests() { Class<?>[] result = new Class[ tests.size() ]; tests.toArray( result ); Arrays.sort( result, new Comparator<Class<?>>() { @Override public int compare( Class<?> test1, Class<?> test2 ) { return test1.getName().compareTo( test2.getName() ); } } ); return result; } private static void initializeFixture() { Fixture.setUp(); Fixture.tearDown(); } private static String computePackagePath( File file, String initialPackagePath, String rootDir ) { String result; if( file.getPath().equals( rootDir ) ) { result = ""; } else if( initialPackagePath.length() == 0 ) { result = file.getName(); } else { result = initialPackagePath + "." + file.getName(); } return result; } private static String toClassName( JarEntry jarEntry ) { String result = removeClassExtension( jarEntry.getName() ); result = result.replace( '/', '.' ); return result; } private static String toClassName( File file, String packageName ) { String result = removeClassExtension( file.getName() ); if( packageName.length() > 0 ) { result = packageName + "." + result; } return result; } private static String removeClassExtension( String name ) { return name.substring( 0, name.lastIndexOf( CLASS_EXTENSION ) ); } private static boolean isClassEntry( JarEntry jarEntry ) { return ( !jarEntry.isDirectory() ) && jarEntry.getName().endsWith( CLASS_EXTENSION ); } private static boolean isClassFile( File file ) { return file.isFile() && file.getName().endsWith( CLASS_EXTENSION ); } }