1
2
3
4 package net.sourceforge.pmd.testframework;
5
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.Iterator;
10 import java.util.List;
11
12 import net.sourceforge.pmd.Rule;
13
14 import org.junit.Test;
15 import org.junit.runner.Description;
16 import org.junit.runner.Runner;
17 import org.junit.runner.manipulation.Filter;
18 import org.junit.runner.manipulation.Filterable;
19 import org.junit.runner.manipulation.NoTestsRemainException;
20 import org.junit.runner.notification.Failure;
21 import org.junit.runner.notification.RunNotifier;
22 import org.junit.runners.BlockJUnit4ClassRunner;
23 import org.junit.runners.model.InitializationError;
24 import org.junit.runners.model.TestClass;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class PMDTestRunner extends Runner implements Filterable {
42 private final Description desc;
43 private final Class<? extends SimpleAggregatorTst> klass;
44 private final List<TestDescriptor> allTests = new ArrayList<TestDescriptor>();
45 private BlockJUnit4ClassRunner chainedRunner;
46
47
48
49
50
51
52 public PMDTestRunner(final Class<? extends SimpleAggregatorTst> klass) throws InitializationError {
53 this.klass = klass;
54
55 desc = Description.createSuiteDescription(klass);
56 configureRuleTests();
57 configureUnitTests();
58 }
59
60 private void configureRuleTests() throws InitializationError {
61 Description root = Description.createSuiteDescription("Rule Tests");
62 try {
63 SimpleAggregatorTst test = createTestClass();
64 test.setUp();
65
66 List<Rule> rules = new ArrayList<Rule>(test.getRules());
67 Collections.sort(rules, new Comparator<Rule>() {
68 @Override
69 public int compare(Rule o1, Rule o2) {
70 return o1.getName().compareTo(o2.getName());
71 }
72 });
73
74 for (Rule r : rules) {
75 Description ruleDescription = Description.createSuiteDescription(r.getName());
76 root.addChild(ruleDescription);
77
78 TestDescriptor[] ruleTests = test.extractTestsFromXml(r);
79 for (TestDescriptor t : ruleTests) {
80 Description d = createTestDescription(t);
81 ruleDescription.addChild(d);
82 allTests.add(t);
83 }
84 }
85 if (!root.getChildren().isEmpty()) {
86 desc.addChild(root);
87 }
88 } catch (Exception e) {
89 throw new InitializationError(e);
90 }
91 }
92
93 private SimpleAggregatorTst createTestClass() {
94 try {
95 return klass.getConstructor().newInstance();
96 } catch (Exception e) {
97 throw new RuntimeException(e);
98 }
99 }
100
101 private void configureUnitTests() throws InitializationError {
102 TestClass tclass = new TestClass(klass);
103 if (!tclass.getAnnotatedMethods(Test.class).isEmpty()) {
104 Description unitTests = Description.createSuiteDescription("Unit tests");
105 chainedRunner = new BlockJUnit4ClassRunner(klass);
106 for (Description d : chainedRunner.getDescription().getChildren()) {
107 unitTests.addChild(d);
108 }
109 desc.addChild(unitTests);
110 }
111 }
112
113 @Override
114 public Description getDescription() {
115 return desc;
116 }
117
118 @Override
119 public void run(RunNotifier notifier) {
120 SimpleAggregatorTst test = createTestClass();
121 boolean regressionTestMode = TestDescriptor.inRegressionTestMode();
122
123 for (TestDescriptor t : allTests) {
124 Description d = createTestDescription(t);
125 notifier.fireTestStarted(d);
126 try {
127 if (!regressionTestMode || t.isRegressionTest()) {
128 test.runTest(t);
129 } else {
130 notifier.fireTestIgnored(d);
131 }
132 } catch (Throwable e) {
133 notifier.fireTestFailure(new Failure(d, e));
134 } finally {
135 notifier.fireTestFinished(d);
136 }
137 }
138 if (chainedRunner != null) {
139 chainedRunner.run(notifier);
140 }
141 }
142
143 private Description createTestDescription(TestDescriptor t) {
144 String d = t.getDescription().replaceAll("\n|\r", " ");
145 return Description.createTestDescription(klass, t.getRule().getName() + "::" + t.getNumberInDocument() + " " + d);
146 }
147
148 @Override
149 public void filter(Filter filter) throws NoTestsRemainException {
150 Iterator<TestDescriptor> it = allTests.iterator();
151 while (it.hasNext()) {
152 TestDescriptor t = it.next();
153 Description testDesc = createTestDescription(t);
154 if (filter.shouldRun(testDesc)) {
155 try {
156 filter.apply(t);
157 } catch (NoTestsRemainException e) {
158 it.remove();
159 }
160 } else {
161 it.remove();
162 }
163 }
164
165 boolean chainIsEmpty = false;
166 try {
167 if (chainedRunner != null) {
168 chainedRunner.filter(filter);
169 } else {
170 chainIsEmpty = true;
171 }
172 } catch (NoTestsRemainException e) {
173 chainIsEmpty = true;
174 }
175
176 if (allTests.isEmpty() && chainIsEmpty) {
177 throw new NoTestsRemainException();
178 }
179 }
180 }