public class VThreadExceptionHandlerOverflow {
    public static void main(String[] args) throws InterruptedException {
        if (args.length == 1 && args[0].equals("nohandler")) {
            System.err.println("Testing without exception handler");
            startAndCheck(VThreadExceptionHandlerOverflow::noHandler1);
        } else {
            System.err.println("Testing with exception handler");
            startAndCheck(VThreadExceptionHandlerOverflow::exceptionHandler1);
        }
        System.err.println("Virtual thread was terminated unexpectedly or System.exit did not work in uncaughtExceptionHandler.");
        System.exit(1);
    }

    public static void startAndCheck(Runnable runnable) throws InterruptedException {
        Thread.Builder.OfVirtual builder = Thread.ofVirtual().uncaughtExceptionHandler((t, e) -> {
            System.err.println("UNEXPECTED EXCEPTION: " + e.toString());
            System.exit(1);
        });
        builder.start(() -> {
            try {
                runnable.run();
            } catch (StackOverflowError t) {
                System.err.println("Expected StackOverflowError");
                System.exit(0);
                return;
            }
            throw new RuntimeException("should not reach");
        }).join();
    }

    public static void exceptionHandler1() {
        try {
            exceptionHandler2();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static void exceptionHandler2() {
        try {
            exceptionHandler1();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    public static void noHandler1() {
        noHandler2();
    }

    private static void noHandler2() {
        noHandler1();
    }
}