/
JUnitWrapperSuite.scala
207 lines (186 loc) · 7.19 KB
/
JUnitWrapperSuite.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalatestplus.junit;
import org.scalatest._
import java.lang.reflect
import java.util.Collections
import java.util.HashSet
import java.util.regex.Pattern
import org.junit.runner.Description
import org.junit.runner.JUnitCore
import org.junit.runner.Request
import org.junit.runner.Result
import org.junit.runner.notification.Failure
import org.junit.runner.notification.RunListener
import org.scalatest.Suite
/**
* <p>
* A wrapper to allow JUnit tests to be run by the ScalaTest runner.
* </p>
*
* <p>
* Instances of this trait are not thread safe.
* </p>
*
* @param junitClassName Fully qualified name of the JUnit suite
* @param loader Class loader to load the JUnit suite
*
* @author Bill Venners
* @author Daniel Watson
* @author Joel Neely
* @author George Berger
*/
class JUnitWrapperSuite(junitClassName: String, loader: ClassLoader) extends Suite {
// TODO: This may need to be made thread safe, because who
// knows what Thread JUnit will fire through this
private var theTracker = new Tracker
private val junitClass = Class.forName(junitClassName, false, loader)
/**
* Overrides to use JUnit to run the tests.
*
* @param testName an optional name of one test to run. If <code>None</code>, all relevant tests should be run.
* I.e., <code>None</code> acts like a wildcard that means run all relevant tests in this <code>Suite</code>.
* @param args the <code>Args</code> for this run
* @return a <code>Status</code> object that indicates when all tests and nested suites started by this method have completed, and whether or not a failure occurred.
*
*/
override def run(testName: Option[String], args: Args): Status = {
import args._
theTracker = tracker
val status = new StatefulStatus
val jUnitCore = new JUnitCore
jUnitCore.addListener(new MyRunListener(reporter, configMap, tracker, status))
jUnitCore.run(junitClass)
status.setCompleted()
status
}
/**
* Overrides to use JUnit's API to retrieve the expected test count.
*
* @param filter a <code>Filter</code> with which to filter tests to count based on their tags
* @return number of expected test count
*/
override def expectedTestCount(filter: Filter): Int = {
getRequest().getRunner.getDescription.testCount
}
/**
* Retrieves a JUnit4 Request object for the junit test
* class.
*
* The JUnit Request.classes() method has different
* signatures in different versions of JUnit4, so reflection
* is used here to identify and use whichever version is
* available in the junit jar on the user's classpath.
*
* @return JUnit4 Request object for the junit test class
*/
def getRequest(): Request = {
var classArgs = new Array[Class[_]](1)
classArgs(0) = junitClass
val requestClass =
try { Class.forName("org.junit.runner.Request") }
catch {
case e: ClassNotFoundException =>
throw new RuntimeException(
"Could not find class: org.junit.runner.Request. " +
"Note: a junit4 jar must be included on " +
"the classpath if using the -j option.")
}
try { // works for junit-4.4.jar
val method = requestClass.getMethod("classes", classOf[String],
classOf[Array[Class[_]]])
val result = method.invoke(null, "", classArgs)
result.asInstanceOf[Request]
}
catch {
case e: NoSuchMethodException =>
try { // works for junit-4.6.jar
val method = requestClass.getMethod("classes",
classOf[Array[Class[_]]])
val result = method.invoke(null, classArgs)
result.asInstanceOf[Request]
}
catch {
case e: NoSuchMethodException =>
throw new RuntimeException("Could not find method " +
"org.junit.runner.Request.classes. " +
"Possibly a junit version problem. " +
"Try junit-4.6.jar.")
}
}
}
/**
* Throws <code>UnsupportedOperationException</code>, because this method is unused by this
* class, given this class's <code>run</code> method delegates to JUnit to run
* its tests.
*
* <p>
* The main purpose of this method implementation is to render a compiler error an attempt
* to mix in a trait that overrides <code>runNestedSuites</code>. Because this
* trait does not actually use <code>runNestedSuites</code>, the attempt to mix
* in behavior would very likely not work.
* </p>
*
* @param args the <code>Args</code> for this run
*
* @throws UnsupportedOperationException always.
*/
override final protected def runNestedSuites(args: Args): Status = {
throw new UnsupportedOperationException
}
/**
* Throws <code>UnsupportedOperationException</code>, because this method is unused by this
* class, given this class's <code>run</code> method delegates to JUnit to run
* its tests.
*
* <p>
* The main purpose of this method implementation is to render a compiler error an attempt
* to mix in a trait that overrides <code>runTests</code>. Because this
* trait does not actually use <code>runTests</code>, the attempt to mix
* in behavior would very likely not work.
* </p>
*
* @param testName an optional name of one test to run. If <code>None</code>, all relevant tests should be run.
* I.e., <code>None</code> acts like a wildcard that means run all relevant tests in this <code>Suite</code>.
* @param args the <code>Args</code> for this run
*
* @throws UnsupportedOperationException always.
*/
override protected final def runTests(testName: Option[String], args: Args): Status = {
throw new UnsupportedOperationException
}
/**
* Throws <code>UnsupportedOperationException</code>, because this method is unused by this
* class, given this class's <code>run</code> method delegates to JUnit to run
* its tests.
*
* <p>
* The main purpose of this method implementation is to render a compiler error an attempt
* to mix in a trait that overrides <code>runTest</code>. Because this
* trait does not actually use <code>runTest</code>, the attempt to mix
* in behavior would very likely not work.
* </p>
*
* @param testName the name of one test to run.
* @param args the <code>Args</code> for this run
*
* @throws UnsupportedOperationException always.
*/
override protected final def runTest(testName: String, args: Args): Status = {
throw new UnsupportedOperationException
}
override def suiteId: String = junitClassName
}