package com.atlassian.bitbucket.mesh.test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotates a test which, by executing, alters one or more test repositories in a way that requires them to be unpacked
 * again before executing further tests to ensure consistency.
 * <p>
 * By default, all {@link Repo}-annotated fields for the test class are assumed to be dirty. For tests which only use a
 * single repository, this is a sensible default and will provide the desired behaviour. However, if there are multiple
 * repositories on the test, this may not be desirable. Specific repositories can be configured by providing their field
 * name in the value array.
 * <pre>
 * <code>
 * public class ExampleTest {
 *
 *     &#064;Repo("classpath:data/first-repository.zip")
 *     private Repository first;
 *     &#064;Repo("classpath:data/second-repository.zip")
 *     private Repository second;
 *
 *     &#064;DirtiesRepo
 *     &#064;Test
 *     public void dirtiesAllTest() {
 *         //...
 *     }
 *
 *     &#064;DirtiesRepo("first")
 *     &#064;Test
 *     public void dirtiesFirstTest() {
 *         //...
 *     }
 * }
 * </code>
 * </pre>
 * In the example above, {@code dirtiesAllTest} will trigger both the {@code first} and {@code second} repositories to
 * be deleted and re-unpacked when it finishes (successfully or not). In comparison {@code dirtiesFirstTest} explicitly
 * indicates that it only dirties the {@code first} repository. To minimise the overhead of managing the repositories
 * on disk, consider carefully how many repositories are included when applying this annotation.
 * <p>
 * This annotation can be applied at the class level or the method level. If the annotation appears at both levels, the
 * method level annotation <i>supersedes and replaces</i> the class-level annotation's values. This allows applying a
 * "default" dirty set on the class and then changing it on specific methods. In general, method-level annotations are
 * expected to be the standard approach. One example of where using a class-level annotation is preferred is when using
 * an {@code @Before} method to apply standard modifications to a repository, since that implicitly means all tests in
 * the class will dirty the repository.
 *
 * @see Repo
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DirtiesRepo {

    String[] value() default "all";
}
