Package: groovy.junit6.plugin

## [Java] Annotation Type ExpectedToFail

- groovy.junit6.plugin.ExpectedToFail

-     @Documented
      @Incubating
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE, ElementType.METHOD})
      @ExtendWith(ExpectedToFailExtension.class)
      public @interface ExpectedToFail

  Inverts the pass/fail outcome of the annotated test method (or every test method on the annotated class): a test that throws is reported as passing, and a test that completes normally is reported as failing.

  Useful for asserting that some condition reliably fails, and for testing test-infrastructure code that should propagate failures.

  Optionally constrain the expected failure by exception type or by a closure predicate evaluated against the thrown exception:

       @Test
       @ExpectedToFail(IllegalStateException)
       void mustThrowIse() { throw new IllegalStateException("boom") }

       @Test
       @ExpectedToFail({ ex instanceof RuntimeException && message.contains('boom') })
       void mustMatchPredicate() { throw new RuntimeException("kaboom!") }

  Closure predicates are evaluated with three bindings: `ex` (the thrown exception), `message` (its message, possibly `null`), and `cause` (its cause, possibly `null`). The test is reported as passing iff the predicate returns a Groovy-truthy value.

  For callers who want compile-time enforcement that the configured class is a Throwable subclass, set exception() instead of (or alongside) value(). `exception` and a closure `value` compose: the type acts as a guard that runs before the predicate, so the closure body can drop the `ex instanceof X` boilerplate. `exception` and a Throwable `value` are mutually exclusive (they would specify the type twice).

  `TestAbortedException` (the exception thrown by JUnit `Assumptions`) is never treated as the expected failure; it's always rethrown so the test is reported as aborted.

  Composition with ForkedJvm: works in either declaration order via explicit coordination between the two extensions (no reliance on annotation iteration order). When `@ExpectedToFail` is declared before `@ForkedJvm` (i.e., outer), the inversion happens in the parent JVM after the failure propagates from the fork — exercising `@ForkedJvm`'s serialization. When declared after (inner), the inversion happens inside the forked child.

  Since:
    6.0.0

- - ### Element Summary

    Optional Element Summary
    Type | Name and Description
    --- | ---
    `Class<? extends Throwable>` | `exception` Type-safe alternative to value(): declares the expected exception type with compile-time enforcement that it is a Throwable subclass.
    `String` | `reason` Optional human-readable explanation of why this test is expected to fail.
    `Class<?>` | `value` Either an expected Throwable subclass or a `Closure` predicate evaluated against the thrown exception.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Element Detail

    - #### public Class<? extends Throwable> exception

      Type-safe alternative to value(): declares the expected exception type with compile-time enforcement that it is a Throwable subclass. Defaults to Throwable, which matches anything.

      Mutually exclusive with a Throwable value(); composes with a closure value() as a type guard evaluated before the predicate.

      Default:
        Throwable.class

    - #### public String reason

      Optional human-readable explanation of why this test is expected to fail. Surfaced in the failure message when the test unexpectedly passes.

      Default:
        ""

    - #### public Class<?> value

      Either an expected Throwable subclass or a `Closure` predicate evaluated against the thrown exception. Defaults to Throwable, which matches anything.

      When set to a Throwable subclass, mutually exclusive with exception(). When set to a closure, composes with exception(): the type guard is checked first, then the closure predicate.

      Default:
        Throwable.class