package org.vertx.testtools; /* * Copyright 2013 Red Hat, Inc. * * Red Hat licenses this file to you 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. * * @author <a href="http://tfox.org">Tim Fox</a> */ import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import java.io.*; import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ScriptClassRunner extends JavaClassRunner { private static final String FILE_SEP = System.getProperty("file.separator"); private static final String TEST_SCRIPTS_DIR = ((System.getProperty("vertx.test.resources") == null) ? "src/test/resources" : System.getProperty("vertx.test.resources")).replace("/", FILE_SEP); public ScriptClassRunner(Class<?> klass) throws InitializationError { super(klass); } @Override protected List<FrameworkMethod> getTestMethods() { List<FrameworkMethod> meths = new ArrayList<>(); TestVerticleInfo ann = getAnnotation(); if (ann == null) { throw new IllegalArgumentException("Please annotate your test classes with TestVerticleInfo"); } String funcRegex = ann.funcRegex(); File scriptsDir = new File(TEST_SCRIPTS_DIR); if (!scriptsDir.exists()) { throw new IllegalArgumentException("Scripts directory does not exist: " + scriptsDir); } FilenameFilter filter = new RegExFileNameFilter(ann.filenameFilter()); List<File> testScripts = findTestFiles(scriptsDir, filter); if (testScripts.isEmpty()) { throw new IllegalStateException("There are no scripts in directory " + scriptsDir + " or child directories, matching filter " + filter); } Pattern funcPattern = Pattern.compile(funcRegex); for (File scriptFile: testScripts) { Path scriptFilePath = scriptFile.toPath(); Path parent = scriptFilePath.getParent(); Path filename = scriptFilePath.getFileName(); try (InputStream is = new BufferedInputStream(new FileInputStream(scriptFile))) { StringBuilder sb = new StringBuilder(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); for (String line = br.readLine(); line != null; line = br.readLine()) { sb.append(line).append("\n"); } br.close(); Matcher m = funcPattern.matcher(sb.toString()); while (m.find()) { String methodName = m.group(1); FrameworkMethod meth = new DummyFrameWorkMethod(parent + "|" + filename + "|" + methodName); meths.add(meth); } } catch (IOException e) { throw new IllegalStateException("Failed to read script " + scriptFile); } } if (meths.isEmpty()) { throw new IllegalStateException("There are no test methods in the tests sctripts"); } return meths; } private List<File> findTestFiles(File dir, FilenameFilter filter) { List<File> list = new ArrayList<>(); File[] files = dir.listFiles(filter); for (File file: files) { if (file.isDirectory()) { list.addAll(findTestFiles(file, filter)); } else { list.add(file); } } return list; } @Override protected URL getClassPath(String methodName) { try { return new File(methodName.split("\\|")[0]).toURI().toURL(); } catch (MalformedURLException e) { e.printStackTrace(); return null; } } @Override protected String getMain(String methodName) { return methodName.split("\\|")[1]; } @Override public String getActualMethodName(String methodName) { return methodName.split("\\|")[2]; } @Override protected List<FrameworkMethod> computeTestMethods() { return getTestMethods(); } private class DummyFrameWorkMethod extends FrameworkMethod { String methodName; DummyFrameWorkMethod(String methodName) { super(null); this.methodName = methodName; } @Override public Object invokeExplosively(Object target, Object... params) throws Throwable { return null; } public String getName() { return methodName; } @Override public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) { } @Override public void validatePublicVoid(boolean isStatic, List<Throwable> errors) { } @Override public void validateNoTypeParametersOnArgs(List<Throwable> errors) { } @Override public boolean isShadowedBy(FrameworkMethod other) { return false; } @Override public Annotation[] getAnnotations() { return null; } @Override public <T extends Annotation> T getAnnotation(Class<T> annotationType) { return null; } } private class RegExFileNameFilter implements FilenameFilter { final Pattern pattern; RegExFileNameFilter(String regex) { pattern = Pattern.compile(regex); } @Override public boolean accept(File dir, String name) { File f = new File(dir, name); return f.isDirectory() || pattern.matcher(name).matches(); } public String toString() { return pattern.toString(); } } }