package base; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) */ public class TestCounter extends Log { public static final int DENOMINATOR = Integer.getInteger("base.denominator", 1); public static final int DENOMINATOR2 = (int) Math.round(Math.sqrt(DENOMINATOR)); private static final String JAR_EXT = ".jar"; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); private final Class owner; private final int mode; private final Map properties; private final ExtendedRandom random; private final long start = System.currentTimeMillis(); private int passed; public TestCounter(final Class owner, final int mode, final Map properties) { Locale.setDefault(Locale.US); Asserts.checkAssert(getClass()); this.owner = owner; this.mode = mode; this.properties = properties; random = new ExtendedRandom(owner); } public int mode() { return mode; } public int getTestNo() { return passed + 1; } public void test(final Runnable action) { testV(() -> { action.run(); return null; }); } public void testForEach(final Iterable items, final Consumer action) { for (final T item : items) { test(() -> action.accept(item)); } } public T testV(final Supplier action) { return silentScope("Test " + getTestNo(), () -> { final T result = action.get(); passed++; return result; }); } private String getLine() { return getIndent() == 0 ? "=" : "-"; } public void printHead() { println("=== " + getTitle()); } public void printStatus() { format("%s%n%s%n", getLine().repeat(30), getTitle()); format("%d tests passed in %dms%n", passed, System.currentTimeMillis() - start); println("Version: " + getVersion(owner)); println(""); } private String getTitle() { return String.format("%s %s", owner.getSimpleName(), properties.isEmpty() ? "" : properties); } private static String getVersion(final Class clazz) { try { final ClassLoader cl = clazz.getClassLoader(); final URL url = cl.getResource(clazz.getName().replace('.', '/') + ".class"); if (url == null) { return "(no manifest)"; } final String path = url.getPath(); final int index = path.indexOf(JAR_EXT); if (index == -1) { return DATE_FORMAT.format(new Date(new File(path).lastModified())); } final String jarPath = path.substring(0, index + JAR_EXT.length()); try (final JarFile jarFile = new JarFile(new File(new URI(jarPath)))) { final JarEntry entry = jarFile.getJarEntry("META-INF/MANIFEST.MF"); return DATE_FORMAT.format(new Date(entry.getTime())); } } catch (final IOException | URISyntaxException e) { return "error: " + e; } } public T call(final String message, final SupplierE supplier) { return get(supplier).either(e -> fail(e, "%s", message), Function.identity()); } public void shouldFail(final String message, @SuppressWarnings("TypeMayBeWeakened") final RunnableE action) { test(() -> get(action).either(e -> null, v -> fail("%s", message))); } public T fail(final String format, final Object... args) { return fail(Asserts.error(format, args)); } public T fail(final Throwable throwable) { return fail(throwable, "%s: %s", throwable.getClass().getSimpleName(), throwable.getMessage()); } public T fail(final Throwable throwable, final String format, final Object... args) { final String message = String.format(format, args); println("ERROR: " + message); throw throwable instanceof Error ? (Error) throwable : new AssertionError(throwable); } public void checkTrue(final boolean condition, final String message, final Object... args) { if (!condition) { fail(message, args); } } public static Either get(final SupplierE supplier) { return supplier.get(); } public Path getFile(final String suffix) { return Paths.get(String.format("test%d.%s", getTestNo(), suffix)); } public ExtendedRandom random() { return random; } @FunctionalInterface public interface SupplierE extends Supplier> { T getE() throws Exception; @Override default Either get() { try { return Either.right(getE()); } catch (final Exception e) { return Either.left(e); } } } @FunctionalInterface public interface RunnableE extends SupplierE { void run() throws Exception; @Override default Void getE() throws Exception { run(); return null; } } }