static void describe(final String context, final Block block) {
  final Suite suite = DeclarationState.instance()
      .getCurrentSuiteBeingDeclared()
      .addSuite(context);
  suite.applyConfigurationFromBlock(block);
  DeclarationState.instance().beginDeclaration(suite, block);
} static void fdescribe(final String context, final Block block) {
  describe(context, with(focus(), block));
} static void fit(final String behavior, final Block block) {
  it(behavior, with(focus(), block));
} static void it(final String behavior, final Block block) {
  DeclarationState.instance().getCurrentSuiteBeingDeclared().addSpec(behavior, block);
} static <T> Supplier<T> let(final ThrowingSupplier<T> supplier) {
  LetHook<T> letHook = new LetHook<>(supplier);
  DeclarationState.instance().addHook(letHook, AppliesTo.ATOMIC_ONLY, Precedence.LOCAL);

  return letHook;
} static void pending() {
  throw new AssumptionViolatedException("pending");
} static void xdescribe(final String context, final Block block) {
  describe(context, with(ignore(), block));
} static void xit(final String behavior, final Block block) {
  it(behavior);
} public final class Spectrum extends Runner {

  /**
   * A generic code block with a {@link #run()} method to perform any action. Usually defined by a
   * lambda function.
   *
   * @deprecated since 1.1.0 - use {@link com.greghaskins.spectrum.Block} instead
   */
  @Deprecated
  @FunctionalInterface
  public interface Block extends com.greghaskins.spectrum.Block {

    /**
     * Execute the code block, raising any {@code Throwable} that may occur.
     *
     * @throws Throwable any uncaught Error or Exception
     */
    @Override
    void run() throws Throwable;
  }


  /**
   * Supplier that is allowed to throw.
   *
   * @param <T> type of object to supply
   * @deprecated since 1.1.0 - use {@link com.greghaskins.spectrum.ThrowingSupplier} instead
   */
  @Deprecated
  @FunctionalInterface
  public interface ThrowingSupplier<T> extends com.greghaskins.spectrum.ThrowingSupplier<T> {

  }

  /**
   * Declare a test suite that describes the expected behavior of the system in a given context.
   *
   * @param context Description of the context for this suite
   * @param block   {@link com.greghaskins.spectrum.Block} with one or more calls to {@link
   *                #it(String, com.greghaskins.spectrum.Block) it} that define each expected
   *                behavior
   * @see Specification#describe
   */
  public static void describe(final String context, final com.greghaskins.spectrum.Block block) {
    Specification.describe(context, block);
  }

  /**
   * Focus on this specific suite, while ignoring others.
   *
   * @param context Description of the context for this suite
   * @param block   {@link com.greghaskins.spectrum.Block} with one or more calls to {@link
   *                #it(String, com.greghaskins.spectrum.Block) it} that define each expected
   *                behavior
   * @see #describe(String, com.greghaskins.spectrum.Block)
   * @see Specification#fdescribe
   */
  public static void fdescribe(final String context, final com.greghaskins.spectrum.Block block) {
    Specification.fdescribe(context, block);
  }

  /**
   * Ignore the specific suite.
   *
   * @param context Description of the context for this suite
   * @param block   {@link com.greghaskins.spectrum.Block} with one or more calls to {@link
   *                #it(String, com.greghaskins.spectrum.Block) it} that define each expected
   *                behavior
   * @see #describe(String, com.greghaskins.spectrum.Block)
   * @see Specification#xdescribe
   */
  public static void xdescribe(final String context, final com.greghaskins.spectrum.Block block) {
    Specification.xdescribe(context, block);
  }

  /**
   * Declare a spec, or test, for an expected behavior of the system in this suite context.
   *
   * @param behavior Description of the expected behavior
   * @param block    {@link com.greghaskins.spectrum.Block} that verifies the system behaves as
   *                 expected and throws a {@link java.lang.Throwable Throwable} if that expectation
   *                 is not met.
   * @see Specification#it
   */
  public static void it(final String behavior, final com.greghaskins.spectrum.Block block) {
    Specification.it(behavior, block);
  }

  /**
   * Declare a pending spec (without a block) that will be ignored.
   *
   * @param behavior Description of the expected behavior
   * @see #xit(String, com.greghaskins.spectrum.Block)
   * @see Specification#it(String)
   */
  public static void it(final String behavior) {
    Specification.it(behavior);
  }

  /**
   * Focus on this specific spec, while ignoring others.
   *
   * @param behavior Description of the expected behavior
   * @param block    {@link com.greghaskins.spectrum.Block} that verifies the system behaves as
   *                 expected and throws a {@link java.lang.Throwable Throwable} if that expectation
   *                 is not met.
   * @see #it(String, com.greghaskins.spectrum.Block)
   * @see Specification#fit
   */
  public static void fit(final String behavior, final com.greghaskins.spectrum.Block block) {
    Specification.fit(behavior, block);
  }

  /**
   * Mark a spec as ignored so that it will be skipped.
   *
   * @param behavior Description of the expected behavior
   * @param block    {@link com.greghaskins.spectrum.Block} that will not run, since this spec is
   *                 ignored.
   * @see #it(String, com.greghaskins.spectrum.Block)
   * @see Specification#xit
   */
  public static void xit(final String behavior, final com.greghaskins.spectrum.Block block) {
    Specification.xit(behavior, block);
  }


  /**
   * Declare a {@link com.greghaskins.spectrum.Block} to be run before each spec in the suite.
   *
   * <p>
   * Use this to perform setup actions that are common across tests in the context. If multiple
   * {@code beforeEach} blocks are declared, they will run in declaration order.
   * </p>
   *
   * @param block {@link com.greghaskins.spectrum.Block} to run once before each spec
   * @see Specification#beforeEach
   */
  public static void beforeEach(final com.greghaskins.spectrum.Block block) {
    Specification.beforeEach(block);
  }

  /**
   * Declare a {@link com.greghaskins.spectrum.Block Block} to be run after each spec in the current
   * suite.
   *
   * <p>
   * Use this to perform teardown or cleanup actions that are common across specs in this suite. If
   * multiple {@code afterEach} blocks are declared, they will run in declaration order.
   * </p>
   *
   * @param block {@link com.greghaskins.spectrum.Block Block} to run once after each spec
   * @see Specification#afterEach
   */
  public static void afterEach(final com.greghaskins.spectrum.Block block) {
    Specification.afterEach(block);
  }

  /**
   * Declare a {@link com.greghaskins.spectrum.Block Block} to be run once before all the specs in
   * the current suite begin.
   *
   * <p>
   * Use {@code beforeAll} and {@link #afterAll(com.greghaskins.spectrum.Block) afterAll} blocks
   * with caution: since they only run once, shared state <strong>will</strong> leak across specs.
   * </p>
   *
   * @param block {@link com.greghaskins.spectrum.Block} to run once before all specs in this suite
   * @see Specification#beforeAll
   */
  public static void beforeAll(final com.greghaskins.spectrum.Block block) {
    Specification.beforeAll(block);
  }

  /**
   * Declare a {@link com.greghaskins.spectrum.Block} to be run once after all the specs in the
   * current suite have run.
   *
   * <p>
   * Use {@link #beforeAll(com.greghaskins.spectrum.Block) beforeAll} and {@code afterAll} blocks
   * with caution: since they only run once, shared state <strong>will</strong> leak across tests.
   * </p>
   *
   * @param block {@link com.greghaskins.spectrum.Block} to run once after all specs in this suite
   * @see Specification#afterAll
   */
  public static void afterAll(final com.greghaskins.spectrum.Block block) {
    Specification.afterAll(block);
  }


  /**
   * A value that will be fresh within each spec and cannot bleed across specs.
   *
   * <p>
   * Note that {@code let} is lazy-evaluated: the {@code supplier} is not called until the first
   * time it is used.
   * </p>
   *
   * @param <T>      The type of value
   * @param supplier {@link com.greghaskins.spectrum.ThrowingSupplier} function that either
   *                 generates the value, or throws a {@link Throwable}
   * @return supplier which is refreshed for each spec's context
   * @see Specification#let
   */
  public static <T> Supplier<T> let(final com.greghaskins.spectrum.ThrowingSupplier<T> supplier) {
    return Specification.let(supplier);
  }

  private final Suite rootSuite;

  /**
   * Main constructor called via reflection by the JUnit runtime.
   *
   * @param testClass The class file that defines the current suite
   * @see org.junit.runner.Runner
   */
  public Spectrum(final Class<?> testClass) {
    this(Description.createSuiteDescription(testClass), createTestClassDefinitionBlock(testClass));
  }

  Spectrum(Description description, com.greghaskins.spectrum.Block definitionBlock) {
    this.rootSuite = Suite.rootSuite(description);
    DeclarationState.instance().beginDeclaration(this.rootSuite, definitionBlock);
  }

  @Override
  public Description getDescription() {
    return this.rootSuite.getDescription();
  }

  @Override
  public void run(final RunNotifier notifier) {
    this.rootSuite.run(new RunNotifierReporting(notifier));
  }

  /**
   * Links the test class construction to JUnit rules implementation. This creates a block which
   * when executed will perform test definition against Spectrum and also hooks JUnit rule
   * implementation to the definition based on any "@Rule" annotations on the members - see {@link
   * Rules}
   *
   * @param testClass type of the test object
   * @return a block with JUnit rules activated
   */
  private static <T> com.greghaskins.spectrum.Block createTestClassDefinitionBlock(
      final Class<T> testClass) {
    ConstructorBlock<T> constructTestClass = new ConstructorBlock<>(testClass);

    return () -> {
      constructTestClass.run();
      Rules.applyRules(constructTestClass.get(), DeclarationState.instance()::addHook);
    };
  }
} public class SpectrumHelper {
  // Allows us to hide a test class from IDE/test discovery
  public static class NullRunner extends Runner {
    private Class<?> clazz;

    public NullRunner(Class<?> clazz) {
      this.clazz = clazz;
    }

    @Override
    public Description getDescription() {
      // empty suite

      return Description.createSuiteDescription(clazz);
    }

    @Override
    public void run(RunNotifier notifier) {
      // do nothing
    }
  }

  public static class RecordingListener extends RunListener {
    private List<Description> testsStarted = new ArrayList<>();

    @Override
    public void testStarted(Description description) throws Exception {
      super.testStarted(description);
      testsStarted.add(description);
    }

    public List<Description> getTestsStarted() {
      return testsStarted;
    }
  }

  public static Result run(final Class<?> specClass) throws Exception {
    return runWithJUnit(new Spectrum(specClass));
  }

  public static Result run(final Block block) {
    return runWithJUnit(
        new Spectrum(Description.createSuiteDescription(block.getClass()), block));
  }

  /**
   * Allows a listener to listen to a run.
   * @param specClass the class to execute via Spectrum
   * @param listener the listener to use
   * @param <T> type of listener
   * @return the listener for fluent usage
   * @throws Exception on error
   */
  public static <T extends RunListener> T runWithListener(final Class<?> specClass,
      final T listener) throws Exception {
    RunNotifier notifier = new RunNotifier();
    notifier.addListener(listener);
    new Spectrum(specClass).run(notifier);

    return listener;
  }

  private static Result runWithJUnit(final Runner runner) {
    return new JUnitCore().run(Request.runner(runner));
  }
}
import static com.greghaskins.spectrum.dsl.specification.Specification.describe;
import static com.greghaskins.spectrum.dsl.specification.Specification.fdescribe;
import static com.greghaskins.spectrum.dsl.specification.Specification.fit;
import static com.greghaskins.spectrum.dsl.specification.Specification.it;
import static com.greghaskins.spectrum.dsl.specification.Specification.let;
import static com.greghaskins.spectrum.dsl.specification.Specification.pending;
import static com.greghaskins.spectrum.dsl.specification.Specification.xdescribe;
import static com.greghaskins.spectrum.dsl.specification.Specification.xit;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import com.greghaskins.spectrum.Spectrum;
import com.greghaskins.spectrum.SpectrumHelper;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import java.util.function.Supplier;
package specs;





@RunWith(Spectrum.class)
public class IgnoredSpecs {
  {
    describe("Ignored specs", () -> {
      it("are declared with `xit`", () -> {
        final Result result = SpectrumHelper.run(getSuiteWithIgnoredSpecs());
        assertThat(result.getFailureCount(), is(0));
      });

      it("ignores tests that are xit", () -> {
        final Result result = SpectrumHelper.run(getSuiteWithIgnoredSpecs());
        assertThat(result.getRunCount(), is(2));
        assertThat(result.getIgnoreCount(), is(2));
      });

      describe("with nesting", () -> {
        it("ignores only the nested spec", () -> {
          final Result result = SpectrumHelper.run(getSuiteWithNestedIgnoredSpecs());
          assertThat(result.getFailureCount(), is(0));
          assertThat(result.getRunCount(), is(1));
          assertThat(result.getIgnoreCount(), is(1));
        });
      });
    });

    describe("Ignored suites", () -> {
      it("are declared with `xdescribe`", () -> {
        final Result result = SpectrumHelper.run(getSuiteWithIgnoredSubSuites());
        assertThat(result.getFailureCount(), is(0));
      });

      it("ignores tests that are xdescribe", () -> {
        final Result result = SpectrumHelper.run(getSuiteWithIgnoredSubSuites());
        assertThat(result.getRunCount(), is(1));
        assertThat(result.getIgnoreCount(), is(3));
      });

      describe("with nesting", () -> {
        it("cause specs in nested suites to also be ignored", () -> {
          final Result result = SpectrumHelper.run(getSuiteWithNestedIgnoredSuites());
          assertThat(result.getFailureCount(), is(0));
          assertThat(result.getRunCount(), is(1));
          assertThat(result.getIgnoreCount(), is(1));
        });

        describe("and the nested suite and spec have a focus", () -> {
          it("ignores the focus", () -> {
            final Result result =
                SpectrumHelper.run(getSuiteWithNestedIgnoredSuitesAndFocusedSpecs());
            assertThat(result.getFailureCount(), is(0));
            assertThat(result.getRunCount(), is(1));
            assertThat(result.getIgnoreCount(), is(2));
          });
        });
      });
    });

    describe("Ignored specs example", () -> {
      final Supplier<Result> result = let(() -> SpectrumHelper.run(getIgnoredSpecsExample()));

      it("does not run ignored specs", () -> {
        assertThat(result.get().getFailureCount(), is(0));
      });
    });
  }

  private static Class<?> getSuiteWithIgnoredSpecs() {
    class Suite {
      {

        describe("A spec that", () -> {

          it("is not ignored and will run", () -> {
            assertThat(true, is(true));
          });

          xit("is ignored and will not run", () -> {
            assertThat(true, is(false));
          });

          it("is marked as pending and will abort but will run a bit", () -> {
            pending();
            assertThat(true, is(true));
          });

          it("does not have a block and is ignored");
        });
      }
    }

    return Suite.class;
  }

  private static Class<?> getSuiteWithNestedIgnoredSpecs() {
    class Suite {
      {

        it("should run because it isn't ignored", () -> {
          assertThat(true, is(true));
        });

        describe("a nested context", () -> {
          xit("is ignored and will not run", () -> {
            assertThat(true, is(false));
          });
        });
      }
    }

    return Suite.class;
  }

  private static Class<?> getSuiteWithIgnoredSubSuites() {
    class Suite {
      {
        describe("an un-ignored suite", () -> {
          it("is not ignored", () -> {
            assertThat(true, is(true));
          });
        });

        xdescribe("ignored describe", () -> {