Upload files to "java/base"
This commit is contained in:
281
java/base/Runner.java
Normal file
281
java/base/Runner.java
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
package base;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Runner {
|
||||||
|
List<String> run(final TestCounter counter, final List<String> input);
|
||||||
|
|
||||||
|
default List<String> run(final TestCounter counter, final String... input) {
|
||||||
|
return run(counter, List.of(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
default void testEquals(
|
||||||
|
final TestCounter counter,
|
||||||
|
final List<String> input,
|
||||||
|
final List<String> expected
|
||||||
|
) {
|
||||||
|
counter.test(() -> {
|
||||||
|
final List<String> actual = run(counter, input);
|
||||||
|
for (int i = 0; i < Math.min(expected.size(), actual.size()); i++) {
|
||||||
|
final String exp = expected.get(i);
|
||||||
|
final String act = actual.get(i);
|
||||||
|
if (!exp.equalsIgnoreCase(act)) {
|
||||||
|
Asserts.assertEquals("Line " + (i + 1), exp, act);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Asserts.assertEquals(
|
||||||
|
"Number of lines",
|
||||||
|
expected.size(),
|
||||||
|
actual.size()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static Packages packages(final String... packages) {
|
||||||
|
return new Packages(List.of(packages));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface CommentRunner {
|
||||||
|
List<String> run(
|
||||||
|
String comment,
|
||||||
|
TestCounter counter,
|
||||||
|
List<String> input
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final class Packages {
|
||||||
|
|
||||||
|
private final List<String> packages;
|
||||||
|
|
||||||
|
private Packages(final List<String> packages) {
|
||||||
|
this.packages = packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Runner std(final String className) {
|
||||||
|
final CommentRunner main = main(className);
|
||||||
|
return (counter, input) ->
|
||||||
|
counter.call("io", () -> {
|
||||||
|
final ByteArrayOutputStream baos =
|
||||||
|
new ByteArrayOutputStream();
|
||||||
|
try (
|
||||||
|
final PrintWriter writer = new PrintWriter(
|
||||||
|
baos,
|
||||||
|
false,
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
input.forEach(writer::println);
|
||||||
|
}
|
||||||
|
|
||||||
|
final InputStream oldIn = System.in;
|
||||||
|
try {
|
||||||
|
System.setIn(
|
||||||
|
new ByteArrayInputStream(baos.toByteArray())
|
||||||
|
);
|
||||||
|
return main.run(
|
||||||
|
String.format("[%d input lines]", input.size()),
|
||||||
|
counter,
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
System.setIn(oldIn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ConfusingMainMethod")
|
||||||
|
public CommentRunner main(final String className) {
|
||||||
|
final Method method = findMain(className);
|
||||||
|
|
||||||
|
return (comment, counter, input) -> {
|
||||||
|
counter.format(
|
||||||
|
"Running test %02d: java %s %s%n",
|
||||||
|
counter.getTestNo(),
|
||||||
|
method.getDeclaringClass().getName(),
|
||||||
|
comment
|
||||||
|
);
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||||
|
final PrintStream oldOut = System.out;
|
||||||
|
try {
|
||||||
|
System.setOut(
|
||||||
|
new PrintStream(out, false, StandardCharsets.UTF_8)
|
||||||
|
);
|
||||||
|
method.invoke(
|
||||||
|
null,
|
||||||
|
new Object[] { input.toArray(String[]::new) }
|
||||||
|
);
|
||||||
|
final BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(
|
||||||
|
new ByteArrayInputStream(out.toByteArray()),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
);
|
||||||
|
final List<String> result = new ArrayList<>();
|
||||||
|
while (true) {
|
||||||
|
final String line = reader.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
result.add("");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.add(line.trim());
|
||||||
|
}
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
final Throwable cause = e.getCause();
|
||||||
|
throw Asserts.error(
|
||||||
|
"main thrown exception %s: %s",
|
||||||
|
cause.getClass().getSimpleName(),
|
||||||
|
cause
|
||||||
|
);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw Asserts.error(
|
||||||
|
"Cannot invoke main: %s: %s",
|
||||||
|
e.getClass().getSimpleName(),
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
System.setOut(oldOut);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method findMain(final String className) {
|
||||||
|
try {
|
||||||
|
final URL url = new File(".").toURI().toURL();
|
||||||
|
final List<String> candidates = packages
|
||||||
|
.stream()
|
||||||
|
.flatMap(pkg -> {
|
||||||
|
final String prefix = pkg.isEmpty() ? pkg : pkg + ".";
|
||||||
|
return Stream.of(
|
||||||
|
prefix + className,
|
||||||
|
prefix + "$" + className
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
//noinspection ClassLoaderInstantiation,resource,IOResourceOpenedButNotSafelyClosed
|
||||||
|
final URLClassLoader classLoader = new URLClassLoader(
|
||||||
|
new URL[] { url }
|
||||||
|
);
|
||||||
|
for (final String candidate : candidates) {
|
||||||
|
try {
|
||||||
|
final Class<?> loaded = classLoader.loadClass(
|
||||||
|
candidate
|
||||||
|
);
|
||||||
|
if (!Modifier.isPublic(loaded.getModifiers())) {
|
||||||
|
throw Asserts.error(
|
||||||
|
"Class %s is not public",
|
||||||
|
candidate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final Method main = loaded.getMethod(
|
||||||
|
"main",
|
||||||
|
String[].class
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
!Modifier.isPublic(main.getModifiers()) ||
|
||||||
|
!Modifier.isStatic(main.getModifiers())
|
||||||
|
) {
|
||||||
|
throw Asserts.error(
|
||||||
|
"Method main of class %s should be public and static",
|
||||||
|
candidate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return main;
|
||||||
|
} catch (final ClassNotFoundException e) {
|
||||||
|
// Ignore
|
||||||
|
} catch (final NoSuchMethodException e) {
|
||||||
|
throw Asserts.error(
|
||||||
|
"Could not find method main(String[]) in class %s",
|
||||||
|
candidate,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw Asserts.error(
|
||||||
|
"Could not find neither of classes %s",
|
||||||
|
candidates
|
||||||
|
);
|
||||||
|
} catch (final MalformedURLException e) {
|
||||||
|
throw Asserts.error("Invalid path", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getClassName(
|
||||||
|
final String pkg,
|
||||||
|
final String className
|
||||||
|
) {
|
||||||
|
return pkg.isEmpty() ? className : pkg + "." + className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Runner args(final String className) {
|
||||||
|
final CommentRunner main = main(className);
|
||||||
|
// final AtomicReference<String> prev = new AtomicReference<>("");
|
||||||
|
return (counter, input) -> {
|
||||||
|
final int total =
|
||||||
|
input.stream().mapToInt(String::length).sum() +
|
||||||
|
input.size() * 3;
|
||||||
|
final String comment =
|
||||||
|
total <= 300
|
||||||
|
? input
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.joining("\" \"", "\"", "\""))
|
||||||
|
: input.size() <= 100
|
||||||
|
? String.format(
|
||||||
|
"[%d arguments, sizes: %s]",
|
||||||
|
input.size(),
|
||||||
|
input
|
||||||
|
.stream()
|
||||||
|
.mapToInt(String::length)
|
||||||
|
.mapToObj(String::valueOf)
|
||||||
|
.collect(Collectors.joining(", "))
|
||||||
|
)
|
||||||
|
: String.format(
|
||||||
|
"[%d arguments, total size: %d]",
|
||||||
|
input.size(),
|
||||||
|
total
|
||||||
|
);
|
||||||
|
// assert comment.length() <= 5 || !prev.get().equals(comment) : "Duplicate tests " + comment;
|
||||||
|
// prev.set(comment);
|
||||||
|
return main.run(comment, counter, input);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Runner files(final String className) {
|
||||||
|
final Runner args = args(className);
|
||||||
|
return (counter, input) ->
|
||||||
|
counter.call("io", () -> {
|
||||||
|
final Path inf = counter.getFile("in");
|
||||||
|
final Path ouf = counter.getFile("out");
|
||||||
|
Files.write(inf, input);
|
||||||
|
args.run(counter, List.of(inf.toString(), ouf.toString()));
|
||||||
|
final List<String> output = Files.readAllLines(ouf);
|
||||||
|
Files.delete(inf);
|
||||||
|
Files.delete(ouf);
|
||||||
|
return output;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
202
java/base/Selector.java
Normal file
202
java/base/Selector.java
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
package base;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public final class Selector {
|
||||||
|
|
||||||
|
private final Class<?> owner;
|
||||||
|
private final List<String> modes;
|
||||||
|
private final Set<String> variantNames = new LinkedHashSet<>();
|
||||||
|
private final Map<String, Consumer<TestCounter>> variants =
|
||||||
|
new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public Selector(final Class<?> owner, final String... modes) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.modes = List.of(modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Selector variant(
|
||||||
|
final String name,
|
||||||
|
final Consumer<TestCounter> operations
|
||||||
|
) {
|
||||||
|
Asserts.assertTrue(
|
||||||
|
"Duplicate variant " + name,
|
||||||
|
variants.put(name.toLowerCase(), operations) == null
|
||||||
|
);
|
||||||
|
variantNames.add(name);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void check(
|
||||||
|
final boolean condition,
|
||||||
|
final String format,
|
||||||
|
final Object... args
|
||||||
|
) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new IllegalArgumentException(String.format(format, args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||||
|
public void main(final String... args) {
|
||||||
|
try {
|
||||||
|
final String mode;
|
||||||
|
if (modes.isEmpty()) {
|
||||||
|
check(
|
||||||
|
args.length >= 1,
|
||||||
|
"At least one argument expected, found %s",
|
||||||
|
args.length
|
||||||
|
);
|
||||||
|
mode = "";
|
||||||
|
} else {
|
||||||
|
check(
|
||||||
|
args.length >= 2,
|
||||||
|
"At least two arguments expected, found %s",
|
||||||
|
args.length
|
||||||
|
);
|
||||||
|
mode = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> vars = Arrays.stream(args)
|
||||||
|
.skip(modes.isEmpty() ? 0 : 1)
|
||||||
|
.flatMap(arg -> Arrays.stream(arg.split("[ +]+")))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
test(mode, vars);
|
||||||
|
} catch (final IllegalArgumentException e) {
|
||||||
|
System.err.println("ERROR: " + e.getMessage());
|
||||||
|
if (modes.isEmpty()) {
|
||||||
|
System.err.println("Usage: " + owner.getName() + " VARIANT...");
|
||||||
|
} else {
|
||||||
|
System.err.println(
|
||||||
|
"Usage: " + owner.getName() + " MODE VARIANT..."
|
||||||
|
);
|
||||||
|
System.err.println("Modes: " + String.join(", ", modes));
|
||||||
|
}
|
||||||
|
System.err.println("Variants: " + String.join(", ", variantNames));
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test(final String mode, List<String> vars) {
|
||||||
|
final int modeNo = modes.isEmpty() ? -1 : modes.indexOf(mode);
|
||||||
|
check(modes.isEmpty() || modeNo >= 0, "Unknown mode '%s'", mode);
|
||||||
|
if (variantNames.contains("Base") && !vars.contains("Base")) {
|
||||||
|
vars = new ArrayList<>(vars);
|
||||||
|
vars.add(0, "Base");
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.forEach(variant ->
|
||||||
|
check(
|
||||||
|
variants.containsKey(variant.toLowerCase()),
|
||||||
|
"Unknown variant '%s'",
|
||||||
|
variant
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final Map<String, String> properties = modes.isEmpty()
|
||||||
|
? Map.of("variant", String.join("+", vars))
|
||||||
|
: Map.of("variant", String.join("+", vars), "mode", mode);
|
||||||
|
final TestCounter counter = new TestCounter(owner, modeNo, properties);
|
||||||
|
counter.printHead();
|
||||||
|
vars.forEach(variant ->
|
||||||
|
counter.scope("Testing " + variant, () ->
|
||||||
|
variants.get(variant.toLowerCase()).accept(counter)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
counter.printStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V extends Tester> Composite<V> composite(
|
||||||
|
final Class<?> owner,
|
||||||
|
final Function<TestCounter, V> factory,
|
||||||
|
final String... modes
|
||||||
|
) {
|
||||||
|
return new Composite<>(
|
||||||
|
owner,
|
||||||
|
factory,
|
||||||
|
(tester, counter) -> tester.test(),
|
||||||
|
modes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> Composite<V> composite(
|
||||||
|
final Class<?> owner,
|
||||||
|
final Function<TestCounter, V> factory,
|
||||||
|
final BiConsumer<V, TestCounter> tester,
|
||||||
|
final String... modes
|
||||||
|
) {
|
||||||
|
return new Composite<>(owner, factory, tester, modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getModes() {
|
||||||
|
return modes.isEmpty() ? List.of("~") : modes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getVariants() {
|
||||||
|
return List.copyOf(variants.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public static final class Composite<V> {
|
||||||
|
|
||||||
|
private final Selector selector;
|
||||||
|
private final Function<TestCounter, V> factory;
|
||||||
|
private final BiConsumer<V, TestCounter> tester;
|
||||||
|
private List<Consumer<? super V>> base;
|
||||||
|
|
||||||
|
private Composite(
|
||||||
|
final Class<?> owner,
|
||||||
|
final Function<TestCounter, V> factory,
|
||||||
|
final BiConsumer<V, TestCounter> tester,
|
||||||
|
final String... modes
|
||||||
|
) {
|
||||||
|
selector = new Selector(owner, modes);
|
||||||
|
this.factory = factory;
|
||||||
|
this.tester = tester;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public final Composite<V> variant(
|
||||||
|
final String name,
|
||||||
|
final Consumer<? super V>... parts
|
||||||
|
) {
|
||||||
|
if ("Base".equalsIgnoreCase(name)) {
|
||||||
|
base = List.of(parts);
|
||||||
|
return v(name.toLowerCase());
|
||||||
|
} else {
|
||||||
|
return v(name, parts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
private Composite<V> v(
|
||||||
|
final String name,
|
||||||
|
final Consumer<? super V>... parts
|
||||||
|
) {
|
||||||
|
selector.variant(name, counter -> {
|
||||||
|
final V variant = factory.apply(counter);
|
||||||
|
for (final Consumer<? super V> part : base) {
|
||||||
|
part.accept(variant);
|
||||||
|
}
|
||||||
|
for (final Consumer<? super V> part : parts) {
|
||||||
|
part.accept(variant);
|
||||||
|
}
|
||||||
|
tester.accept(variant, counter);
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Selector selector() {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
236
java/base/TestCounter.java
Normal file
236
java/base/TestCounter.java
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
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<String, ?> properties;
|
||||||
|
private final ExtendedRandom random;
|
||||||
|
|
||||||
|
private final long start = System.currentTimeMillis();
|
||||||
|
private int passed;
|
||||||
|
|
||||||
|
public TestCounter(
|
||||||
|
final Class<?> owner,
|
||||||
|
final int mode,
|
||||||
|
final Map<String, ?> 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 <T> void testForEach(
|
||||||
|
final Iterable<? extends T> items,
|
||||||
|
final Consumer<? super T> action
|
||||||
|
) {
|
||||||
|
for (final T item : items) {
|
||||||
|
test(() -> action.accept(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T testV(final Supplier<T> 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> T call(final String message, final SupplierE<T> 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> T fail(final String format, final Object... args) {
|
||||||
|
return fail(Asserts.error(format, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T fail(final Throwable throwable) {
|
||||||
|
return fail(
|
||||||
|
throwable,
|
||||||
|
"%s: %s",
|
||||||
|
throwable.getClass().getSimpleName(),
|
||||||
|
throwable.getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> 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 <T> Either<Exception, T> get(final SupplierE<T> 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<T> extends Supplier<Either<Exception, T>> {
|
||||||
|
T getE() throws Exception;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Either<Exception, T> get() {
|
||||||
|
try {
|
||||||
|
return Either.right(getE());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return Either.left(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface RunnableE extends SupplierE<Void> {
|
||||||
|
void run() throws Exception;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Void getE() throws Exception {
|
||||||
|
run();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
java/base/Tester.java
Normal file
21
java/base/Tester.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public abstract class Tester extends BaseChecker {
|
||||||
|
|
||||||
|
protected Tester(final TestCounter counter) {
|
||||||
|
super(counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void test();
|
||||||
|
|
||||||
|
public void run(final Class<?> test, final String... args) {
|
||||||
|
System.out.println(
|
||||||
|
"=== Testing " + test.getSimpleName() + " " + String.join(" ", args)
|
||||||
|
);
|
||||||
|
test();
|
||||||
|
counter.printStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
16
java/base/Unit.java
Normal file
16
java/base/Unit.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Georgiy Korneev (kgeorgiy@kgeorgiy.info)
|
||||||
|
*/
|
||||||
|
public final class Unit {
|
||||||
|
|
||||||
|
public static final Unit INSTANCE = new Unit();
|
||||||
|
|
||||||
|
private Unit() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "unit";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user