c4c439b6fc24547614f016d21f12967714077706
[packetcable.git] / packetcable-policy-server / src / test / java / org / opendaylight / controller / packetcable / provider / test / rules / Params.java
1 /*
2  * Copyright (c) 2015 CableLabs and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.packetcable.provider.test.rules;
10
11 import java.lang.annotation.ElementType;
12 import java.lang.annotation.Retention;
13 import java.lang.annotation.RetentionPolicy;
14 import java.lang.annotation.Target;
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.Objects;
18 import java.util.Optional;
19 import org.junit.rules.ErrorCollector;
20 import org.junit.rules.TestRule;
21 import org.junit.runner.Description;
22 import org.junit.runners.model.Statement;
23
24 /**
25  * Rule that allows a test to be run with multiple parameters.<br><br>
26  * Two ways to use
27  * <ol>
28  *     <li>Individual Method Annotation - {@link Params.UseParams} <br>Used if only a few methods need to use the rule</li>
29  *     <li>Class Annotation - {@link Params.AlwaysUseParams} <br> Used if most/all methods will use the rule. Exceptions should be marked with {@link Params.DoNotUseParams}</li>
30  * </ol>
31  *
32  * @author rvail
33  */
34 public class Params<T> implements TestRule {
35
36     private final List<T> allParams;
37     private final VerifiableErrorCollector errorCollector = new VerifiableErrorCollector();
38     private Optional<T> currentParam = null;
39
40
41
42     public static <E> Params<E> of(E... allParams) {
43         return new Params<>(allParams);
44     }
45
46     public static <E extends Enum<E>> Params<E> of(Class<E> enumClass) {
47         return new Params<>(enumClass.getEnumConstants());
48     }
49
50     private Params(List<T> allParams) {
51         this.allParams = allParams;
52     }
53
54     private Params(T[] allParams) {
55         this(Arrays.asList(allParams));
56     }
57
58     public T getCurrentParam() {
59         if (currentParam == null) {
60             throw new IllegalStateException("Params.getCurrentParam called from unannotated method/class");
61         }
62         return currentParam.get();
63     }
64
65     @Override
66     public Statement apply(final Statement base, final Description description) {
67         if (!shouldUseParams(description)) {
68             return base;
69         }
70         return new Statement() {
71
72             @Override
73             public void evaluate() throws Throwable {
74
75                 for (final T param : allParams) {
76                     currentParam = Optional.of(param);
77                     try {
78                         base.evaluate();
79                     } catch (Throwable t) {
80                         errorCollector.addError(new ParamsAssertionError(currentParam, t));
81                     }
82                 }
83                 currentParam = null;
84                 errorCollector.verify();
85             }
86         };
87     }
88
89     private boolean shouldUseParams(final Description description) {
90         final UseParams useParamsAnnotation = description.getAnnotation(UseParams.class);
91         boolean testUsesParams = (useParamsAnnotation != null);
92         if (!testUsesParams) {
93             final AlwaysUseParams alwaysUseParams = description.getTestClass().getAnnotation(AlwaysUseParams.class);
94             testUsesParams = (alwaysUseParams != null);
95             if (testUsesParams) {
96                 testUsesParams = (description.getAnnotation(DoNotUseParams.class) == null);
97             }
98         }
99
100         return testUsesParams;
101     }
102
103     /**
104      * Method will use Params
105      */
106     @Retention(RetentionPolicy.RUNTIME)
107     @Target({ElementType.METHOD})
108     public @interface UseParams {
109     }
110
111
112     /**
113      * Method will not use Params
114      */
115     @Retention(RetentionPolicy.RUNTIME)
116     @Target({ElementType.METHOD})
117     public @interface DoNotUseParams {
118     }
119
120
121     /**
122      * All Methods in Class will use Params unless they are annotated with
123      * {@link Params.DoNotUseParams}
124      */
125     @Retention(RetentionPolicy.RUNTIME)
126     @Target({ElementType.TYPE})
127     public @interface AlwaysUseParams {
128     }
129
130
131     public static class ParamsAssertionError extends AssertionError {
132         ParamsAssertionError(Object param, Throwable t) {
133             super(String.format("\nParam: %s\n%s", Objects.toString(param), t));
134             // We don't care where this is thrown from we care about the passed in cause
135             // use its stack trace
136             this.setStackTrace(t.getStackTrace());
137         }
138     }
139
140
141     /**
142      * ErrorCollector.verify() is protected so extend ErrorCollector so we can call it.
143      */
144     private class VerifiableErrorCollector extends ErrorCollector {
145         public void verify() throws Throwable {
146             super.verify();
147         }
148     }
149
150 }