aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/junit/runner/manipulation/Ordering.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/junit/runner/manipulation/Ordering.java')
-rw-r--r--src/main/java/org/junit/runner/manipulation/Ordering.java172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/main/java/org/junit/runner/manipulation/Ordering.java b/src/main/java/org/junit/runner/manipulation/Ordering.java
new file mode 100644
index 0000000..0d0ce93
--- /dev/null
+++ b/src/main/java/org/junit/runner/manipulation/Ordering.java
@@ -0,0 +1,172 @@
+package org.junit.runner.manipulation;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.runner.Description;
+import org.junit.runner.OrderWith;
+
+/**
+ * Reorders tests. An {@code Ordering} can reverse the order of tests, sort the
+ * order or even shuffle the order.
+ *
+ * <p>In general you will not need to use a <code>Ordering</code> directly.
+ * Instead, use {@link org.junit.runner.Request#orderWith(Ordering)}.
+ *
+ * @since 4.13
+ */
+public abstract class Ordering {
+ private static final String CONSTRUCTOR_ERROR_FORMAT
+ = "Ordering class %s should have a public constructor with signature "
+ + "%s(Ordering.Context context)";
+
+ /**
+ * Creates an {@link Ordering} that shuffles the items using the given
+ * {@link Random} instance.
+ */
+ public static Ordering shuffledBy(final Random random) {
+ return new Ordering() {
+ @Override
+ boolean validateOrderingIsCorrect() {
+ return false;
+ }
+
+ @Override
+ protected List<Description> orderItems(Collection<Description> descriptions) {
+ List<Description> shuffled = new ArrayList<Description>(descriptions);
+ Collections.shuffle(shuffled, random);
+ return shuffled;
+ }
+ };
+ }
+
+ /**
+ * Creates an {@link Ordering} from the given factory class. The class must have a public no-arg
+ * constructor.
+ *
+ * @param factoryClass class to use to create the ordering
+ * @param annotatedTestClass test class that is annotated with {@link OrderWith}.
+ * @throws InvalidOrderingException if the instance could not be created
+ */
+ public static Ordering definedBy(
+ Class<? extends Ordering.Factory> factoryClass, Description annotatedTestClass)
+ throws InvalidOrderingException {
+ if (factoryClass == null) {
+ throw new NullPointerException("factoryClass cannot be null");
+ }
+ if (annotatedTestClass == null) {
+ throw new NullPointerException("annotatedTestClass cannot be null");
+ }
+
+ Ordering.Factory factory;
+ try {
+ Constructor<? extends Ordering.Factory> constructor = factoryClass.getConstructor();
+ factory = constructor.newInstance();
+ } catch (NoSuchMethodException e) {
+ throw new InvalidOrderingException(String.format(
+ CONSTRUCTOR_ERROR_FORMAT,
+ getClassName(factoryClass),
+ factoryClass.getSimpleName()));
+ } catch (Exception e) {
+ throw new InvalidOrderingException(
+ "Could not create ordering for " + annotatedTestClass, e);
+ }
+ return definedBy(factory, annotatedTestClass);
+ }
+
+ /**
+ * Creates an {@link Ordering} from the given factory.
+ *
+ * @param factory factory to use to create the ordering
+ * @param annotatedTestClass test class that is annotated with {@link OrderWith}.
+ * @throws InvalidOrderingException if the instance could not be created
+ */
+ public static Ordering definedBy(
+ Ordering.Factory factory, Description annotatedTestClass)
+ throws InvalidOrderingException {
+ if (factory == null) {
+ throw new NullPointerException("factory cannot be null");
+ }
+ if (annotatedTestClass == null) {
+ throw new NullPointerException("annotatedTestClass cannot be null");
+ }
+
+ return factory.create(new Ordering.Context(annotatedTestClass));
+ }
+
+ private static String getClassName(Class<?> clazz) {
+ String name = clazz.getCanonicalName();
+ if (name == null) {
+ return clazz.getName();
+ }
+ return name;
+ }
+
+ /**
+ * Order the tests in <code>target</code> using this ordering.
+ *
+ * @throws InvalidOrderingException if ordering does something invalid (like remove or add
+ * children)
+ */
+ public void apply(Object target) throws InvalidOrderingException {
+ /*
+ * Note that some subclasses of Ordering override apply(). The Sorter
+ * subclass of Ordering overrides apply() to apply the sort (this is
+ * done because sorting is more efficient than ordering).
+ */
+ if (target instanceof Orderable) {
+ Orderable orderable = (Orderable) target;
+ orderable.order(new Orderer(this));
+ }
+ }
+
+ /**
+ * Returns {@code true} if this ordering could produce invalid results (i.e.
+ * if it could add or remove values).
+ */
+ boolean validateOrderingIsCorrect() {
+ return true;
+ }
+
+ /**
+ * Implemented by sub-classes to order the descriptions.
+ *
+ * @return descriptions in order
+ */
+ protected abstract List<Description> orderItems(Collection<Description> descriptions);
+
+ /** Context about the ordering being applied. */
+ public static class Context {
+ private final Description description;
+
+ /**
+ * Gets the description for the top-level target being ordered.
+ */
+ public Description getTarget() {
+ return description;
+ }
+
+ private Context(Description description) {
+ this.description = description;
+ }
+ }
+
+ /**
+ * Factory for creating {@link Ordering} instances.
+ *
+ * <p>For a factory to be used with {@code @OrderWith} it needs to have a public no-arg
+ * constructor.
+ */
+ public interface Factory {
+ /**
+ * Creates an Ordering instance using the given context. Implementations
+ * of this method that do not need to use the context can return the
+ * same instance every time.
+ */
+ Ordering create(Context context);
+ }
+}