package search; import base.MainChecker; import base.Runner; import base.Selector; import base.TestCounter; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; /** * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) */ public final class BinarySearchTest { public static final int[] SIZES = {5, 4, 2, 1, 10, 50, 100, 200, 300}; public static final int[] VALUES = new int[]{5, 4, 2, 1, 0, 10, 100, Integer.MAX_VALUE / 2}; private BinarySearchTest() { } // === Base /* package-private */ static int base(final int c, final int x, final int[] a) { return IntStream.range(0, a.length).filter(i -> Integer.compare(a[i], x) != c).findFirst().orElse(a.length); } // === Common code public static final Selector SELECTOR = new Selector(BinarySearchTest.class) .variant("Base", Solver.variant0("", Kind.DESC, BinarySearchTest::base)) ; public static void main(final String... args) { SELECTOR.main(args); } /* package-private */ static Consumer variant(final String name, final Consumer variant) { final String className = "BinarySearch" + name; return counter -> variant.accept(new Variant(counter, new MainChecker(Runner.packages("search").args(className)))); } /* package-private */ interface Solver { static Consumer variant0(final String name, final Kind kind, final Solver solver) { return variant(name, kind, true, solver); } static Consumer variant1(final String name, final Kind kind, final Solver solver) { return variant(name, kind, false, solver); } private static Consumer variant(final String name, final Kind kind, final boolean empty, final Solver solver) { final Sampler sampler = new Sampler(kind, true, true); return BinarySearchTest.variant(name, vrt -> { if (empty) { solver.test(kind, vrt); } solver.test(kind, vrt, 0); for (final int s1 : SIZES) { final int size = s1 > 3 * TestCounter.DENOMINATOR ? s1 / TestCounter.DENOMINATOR : s1; for (final int max : VALUES) { solver.test(kind, vrt, sampler.sample(vrt, size, max)); } } }); } private static int[] probes(final int[] a, final int limit) { return Stream.of( Arrays.stream(a), IntStream.range(1, a.length).map(i -> (a[i - 1] + a[i]) / 2), IntStream.of( 0, Integer.MIN_VALUE, Integer.MAX_VALUE, a.length > 0 ? a[0] - 1 : -1, a.length > 0 ? a[a.length - 1] + 1 : 1 ) ) .flatMapToInt(Function.identity()) .distinct() .sorted() .limit(limit) .toArray(); } Object solve(final int c, final int x, final int... a); default void test(final Kind kind, final Variant variant, final int... a) { test(kind, variant, a, Integer.MAX_VALUE); } default void test(final Kind kind, final Variant variant, final int[] a, final int limit) { for (final int x : probes(a, limit)) { variant.test(solve(kind.d, x, a), IntStream.concat(IntStream.of(x), Arrays.stream(a))); } } } public enum Kind { ASC(-1), DESC(1); public final int d; Kind(final int d) { this.d = d; } } public record Variant(TestCounter counter, MainChecker checker) { void test(final Object expected, final IntStream ints) { final List input = ints.mapToObj(Integer::toString).toList(); checker.testEquals(counter, input, List.of(expected.toString())); } public void test(final Object expected, final int[] a) { test(expected, Arrays.stream(a)); } } public record Sampler(Kind kind, boolean dups, boolean zero) { public int[] sample(final Variant variant, final int size, final int max) { final IntStream sorted = variant.counter.random().getRandom().ints(zero ? size : Math.max(size, 1), -max, max + 1).sorted(); final int[] ints = (dups ? sorted : sorted.distinct()).toArray(); if (kind == Kind.DESC) { final int sz = ints.length; for (int i = 0; i < sz / 2; i++) { final int t = ints[i]; ints[i] = ints[sz - i - 1]; ints[sz - i - 1] = t; } } return ints; } } }