static FilterConfigurationChain excludeTags(String... tagsToExclude) {
  return new FilterConfigurationChain(new ExcludeTags(tagsToExclude));
} static void filterRun(FilterConfigurationChain configuration) {
  configuration.applyTo(DeclarationState.instance().getCurrentSuiteBeingDeclared());
} static Block ignore(final String why, final Block block) {
  return with(ignore(why), block);
} static FilterConfigurationChain includeTags(String... tagsToInclude) {
  return new FilterConfigurationChain(new IncludeTags(tagsToInclude));
} static BlockConfigurationChain tags(final String... tags) {
  return new BlockConfigurationChain().with(new BlockTagging(tags));
} static Block with(final BlockConfigurationChain configuration, final Block block) {
  return ConfiguredBlock.with(configuration.getBlockConfiguration(), block);
} static void beforeEach(final Block block) {
  DeclarationState.instance().addHook(before(block), AppliesTo.ATOMIC_ONLY, Precedence.LOCAL);
} 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 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;
} public interface Configure {

  String EXCLUDE_TAGS_PROPERTY = "spectrum.exclude.tags";
  String INCLUDE_TAGS_PROPERTY = "spectrum.include.tags";

  /**
   * Surround a {@link Block} with the {@code with} statement to add
   * configuration and metadata to it. E.g. <code>with(tags("foo"), () -&gt; {})</code>.<br>
   * Note: configuration metadata can be chained using the
   * {@link BlockConfigurationChain#and(BlockConfigurationChain)} method. E.g.
   * <code>with(tags("foo").and(ignore()), () -&gt; {})</code>
   *
   * @param configuration the chainable block configuration
   * @param block the enclosed block
   * @return a wrapped block with the given configuration
   * @see #ignore(String)
   * @see #ignore()
   * @see #focus()
   * @see #tags(String...)
   * @see #timeout(Duration)
   */
  static Block with(final BlockConfigurationChain configuration, final Block block) {
    return ConfiguredBlock.with(configuration.getBlockConfiguration(), block);
  }

  /**
   * Mark a block as ignored by surrounding it with the ignore method.
   *
   * @param why explanation of why this block is being ignored
   * @param block the block to ignore
   * @return a wrapped block which will be ignored
   */
  static Block ignore(final String why, final Block block) {
    return with(ignore(why), block);
  }

  /**
   * Mark a block as ignored by surrounding it with the ignore method.
   *
   * @param block the block to ignore
   * @return a wrapped block which will be ignored
   */
  static Block ignore(final Block block) {
    return with(ignore(), block);
  }

  /**
   * Ignore the suite or spec.
   *
   * @return a chainable configuration that will ignore the block within a {@link #with}
   */
  static BlockConfigurationChain ignore() {
    return new BlockConfigurationChain().with(new BlockIgnore());
  }

  /**
   * Ignore the suite or spec.
   *
   * @param reason why this block is ignored
   * @return a chainable configuration that will ignore the block within a {@link #with}
   */
  static BlockConfigurationChain ignore(final String reason) {
    return new BlockConfigurationChain().with(new BlockIgnore(reason));
  }

  /**
   * Tags the suite or spec that is being declared with the given strings. Depending on the current
   * filter criteria, this may lead to the item being ignored during test execution.
   *
   * @param tags tags that relate to the suite or spec
   * @return a chainable configuration that has these tags set for the block in {@link #with}
   */
  static BlockConfigurationChain tags(final String... tags) {
    return new BlockConfigurationChain().with(new BlockTagging(tags));
  }

  /**
   * Marks the suite or spec to be focused.
   *
   * @return a chainable configuration that will focus the suite or spec in the {@link #with}
   */
  static BlockConfigurationChain focus() {
    return new BlockConfigurationChain().with(new BlockFocused());
  }

  /**
   * Apply timeout to all leaf nodes from this level down. Can be superseded by a lower level having its
   * own timeout.
   * @param timeout the amount of the timeout
   * @return a chainable configuration that will apply a timeout to all leaf nodes below
   */
  static BlockConfigurationChain timeout(Duration timeout) {
    return new BlockConfigurationChain().with(new BlockTimeout(timeout));
  }

  /**
   * Filter which tests in the current suite will run.
   *
   * <br><br>
   * {@code filterRun(includeTags("foo").and(excludeTags("bar")));}
   *
   * @param configuration chainable filter configuration
   * @see #includeTags(String...)
   * @see #excludeTags(String...)
   */
  static void filterRun(FilterConfigurationChain configuration) {
    configuration.applyTo(DeclarationState.instance().getCurrentSuiteBeingDeclared());
  }

  /**
   * Set the test filter to require at least one of these tags for all following specs.
   *
   * @param tagsToInclude specs (or their parent suite) must have at least one of these
   * @return FilterConfigurationChain instance for chaining further calls
   */
  static FilterConfigurationChain includeTags(String... tagsToInclude) {
    return new FilterConfigurationChain(new IncludeTags(tagsToInclude));
  }

  /**
   * Set the test filter to exclude any following specs that have one of these tags.
   *
   * @param tagsToExclude specs and their parent suite must not have any of these
   * @return FilterConfigurationChain instance for chaining further calls
   */
  static FilterConfigurationChain excludeTags(String... tagsToExclude) {
    return new FilterConfigurationChain(new ExcludeTags(tagsToExclude));
  }

  /**
   * Uses the given class as a mix-in for JUnit rules to be applied. These rules will cascade down
   * and be applied at the level of specs or atomic specs.
   *
   * @param classWithRules Class to create and apply rules to for each spec.
   * @param <T>            type of the object
   * @return a supplier of the rules object
   */
  static <T> Supplier<T> junitMixin(final Class<T> classWithRules) {
    return Rules.applyRules(classWithRules, DeclarationState.instance()::addHook);
  }
} 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.Configure.excludeTags;
import static com.greghaskins.spectrum.Configure.filterRun;
import static com.greghaskins.spectrum.Configure.ignore;
import static com.greghaskins.spectrum.Configure.includeTags;
import static com.greghaskins.spectrum.Configure.tags;
import static com.greghaskins.spectrum.Configure.with;
import static com.greghaskins.spectrum.dsl.specification.Specification.beforeEach;
import static com.greghaskins.spectrum.dsl.specification.Specification.describe;
import static com.greghaskins.spectrum.dsl.specification.Specification.it;
import static com.greghaskins.spectrum.dsl.specification.Specification.let;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import com.greghaskins.spectrum.Configure;
import com.greghaskins.spectrum.Spectrum;
import com.greghaskins.spectrum.SpectrumHelper;
import org.junit.Assert;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.function.Supplier;
package specs;





@RunWith(Spectrum.class)
public class TaggedSpecs {

  {
    describe("A suite with tagging", () -> {