import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

import java.io.IOException;
import java.util.function.Supplier;

import org.junit.jupiter.api.Test;

public class MinimalTest {

    public <T> T supply(Supplier<T> supplier) {
        return supplier.get();
    }

    public @FunctionalInterface interface BadSupplier1<X1 extends Exception, T> {
        T get() throws X1;
    }

    public <X1 extends Exception, T> T supply(Class<X1> x1, BadSupplier1<X1, T> supplier) throws X1 {
        return supplier.get();
    }

    public @FunctionalInterface interface BadSupplier2<X1 extends Exception, X2 extends Exception, T> {
        T get() throws X1, X2;
    }

    public <X1 extends Exception, X2 extends Exception, T> T supply(Class<X1> x1, Class<X2> x2, BadSupplier2<X1, X2, T> supplier) throws X1, X2 {
        return supplier.get();
    }

    public @Test void test() {
        assertDoesNotThrow(() -> supply(() -> null));
        assertThrowsExactly(IOException.class, () -> supply(IOException.class, () -> {
            throw new IOException("To be expected");
        }));
        assertThrowsExactly(ClassNotFoundException.class, () -> supply(ClassNotFoundException.class, () -> {
            throw new ClassNotFoundException("To be expected");
        }));
        assertThrowsExactly(IOException.class, () -> supply(IOException.class, IOException.class, () -> {
            throw new IOException("To be expected");
        }));
        assertThrowsExactly(ClassNotFoundException.class, () -> supply(ClassNotFoundException.class, ClassNotFoundException.class, () -> {
            throw new ClassNotFoundException("To be expected");
        }));
// BREAKS ON NEXT LINE in javac but compiles and runs fine with ecj
        assertThrowsExactly(IOException.class, () -> supply(IOException.class, ClassNotFoundException.class, () -> {
            throw new IOException("To be expected");
        }));
    }
} 