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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
|
/* *******************************************************************
* Copyright (c) 2003 Contributors
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Wes Isberg initial implementation
* ******************************************************************/
package org.aspectj.testing.drivers;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.ajdt.internal.core.builder.AjState;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHolder;
import org.aspectj.bridge.MessageHandler;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.testing.harness.bridge.AjcTest;
import org.aspectj.testing.harness.bridge.AjcTest.Spec;
import org.aspectj.testing.harness.bridge.RunSpecIterator;
import org.aspectj.testing.harness.bridge.Sandbox;
import org.aspectj.testing.harness.bridge.Validator;
import org.aspectj.testing.run.IRunIterator;
import org.aspectj.testing.run.RunStatus;
import org.aspectj.testing.run.Runner;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
/*
* Adapt Harness tests to JUnit driver. This renders suite files as TestSuite
* and AjcTest as TestCase. When run, aborts are reported as error and fails as
* failures, with all messages stuffed into the one JUnit exception message.
* Test options are supported, but no harness options. The TestSuite
* implementation prevents us from re-running tests. In the Eclipse JUnit test
* runner, the tests display hierarchically and with annotations and with
* messages. You can stop the tests, but not traverse to the source or re-run
* the test.
*/
public class AjctestsAdapter extends TestSuite {
public static final String VERBOSE_NAME = AjctestsAdapter.class.getName()
+ ".VERBOSE";
private static final boolean VERBOSE = HarnessJUnitUtil
.readBooleanSystemProperty(VERBOSE_NAME);
/**
* Factory to make and populate suite without options.
*
* @param suitePath
* the String path to a harness suite file
* @return AjctestJUnitSuite populated with tests
*/
public static AjctestsAdapter make(String suitePath) {
return make(suitePath, null);
}
/**
* Factory to make and populate suite
*
* @param suitePath
* the String path to a harness suite file
* @param options
* the String[] options to use when creating tests
* @return AjctestJUnitSuite populated with tests
*/
public static AjctestsAdapter make(String suitePath, String[] options) {
AjctestsAdapter result = new AjctestsAdapter(suitePath, options);
AjcTest.Spec[] tests = AjcTest.Suite.getTests(result.getSpec());
if (VERBOSE) {
log("loading " + tests.length + " tests in " + suitePath);
}
for (Spec ajcTest : tests) {
result.addTest(new AjcTestSpecAsTest(ajcTest, result));
}
return result;
}
private static void log(String message) {
System.err.println(message);
System.err.flush();
}
private final String suitePath;
private final String[] options;
private AjcTest.Suite.Spec spec;
private Runner runner;
private Validator validator;
private IMessageHolder holder;
private Sandbox sandbox;
private File suiteDir;
private String name;
private AjctestsAdapter(String suitePath, String[] options) {
this.suitePath = suitePath;
String[] opts = new String[0];
if (!HarnessJUnitUtil.isEmpty(options)) {
opts = new String[options.length];
System.arraycopy(options, 0, opts, 0, opts.length);
}
this.options = opts;
}
@Override
public void addTest(Test test) {
if (!(test instanceof AjcTestSpecAsTest)) {
String m = "expecting AjcTestSpecAsTest, got "
+ (null == test ? "null test" : test.getClass().getName()
+ ": " + test);
throw new IllegalArgumentException(m);
}
super.addTest(test);
}
@SuppressWarnings("rawtypes")
@Override
public void addTestSuite(Class testClass) {
throw new Error("unimplemented");
}
@Override
public String getName() {
if (null == name) {
name = HarnessJUnitUtil.cleanTestName(suitePath
+ Arrays.asList(options));
}
return name;
}
/**
* Callback from test to run it using suite-wide holder, etc. The caller is
* responsible for calling result.startTest(test) and result.endTest(test);
*
* @param test
* the AjcTestSpecAsTest to run
* @param result
* the TestResult for any result messages (may be null)
*/
protected void runTest(AjcTestSpecAsTest test, TestResult result) {
final Runner runner = getRunner();
final Sandbox sandbox = getSandbox();
final Validator validator = getValidator();
int numIncomplete = 0;
final RunStatus status = new RunStatus(new MessageHandler(), runner);
status.setIdentifier(test.toString());
try {
IMessageHolder holder = getHolder();
holder.clearMessages();
IRunIterator steps = test.spec.makeRunIterator(sandbox, validator);
if (0 < holder.numMessages(IMessage.ERROR, true)) {
MessageUtil.handleAll(status, holder, IMessage.INFO, true,
false);
} else {
runner.runIterator(steps, status, null);
}
if (steps instanceof RunSpecIterator) {
numIncomplete = ((RunSpecIterator) steps).getNumIncomplete();
}
} finally {
try {
// reportResult handles null TestResult
HarnessJUnitUtil
.reportResult(null, status, test, numIncomplete);
} finally {
validator.deleteTempFiles(true);
}
}
}
private File getSuiteDir() {
if (null == suiteDir) {
File file = new File(suitePath);
file = file.getParentFile();
if (null == file) {
file = new File(".");
}
suiteDir = file;
}
return suiteDir;
}
private Validator getValidator() {
if (null == validator) {
validator = new Validator(getHolder());
// XXX lock if keepTemp?
}
return validator;
}
private Runner getRunner() {
if (null == runner) {
runner = new Runner();
}
return runner;
}
private IMessageHolder getHolder() {
if (null == holder) {
holder = new MessageHandler();
}
return holder;
}
private AjcTest.Suite.Spec getSpec() {
if (null == spec) {
IMessageHolder holder = getHolder();
spec = HarnessJUnitUtil.getSuiteSpec(suitePath, options,
getHolder());
if (VERBOSE && holder.hasAnyMessage(null, true)) {
MessageUtil.print(System.err, holder, "skip ",
MessageUtil.MESSAGE_MOST);
}
holder.clearMessages();
}
return spec;
}
private Sandbox getSandbox() {
if (null == sandbox) {
sandbox = new Sandbox(spec.getSuiteDirFile(), getValidator());
}
return sandbox;
}
/**
* Wrap AjcTest.Spec for lookup by description
*
* @author wes
*/
public static class SpecTests {
private static final HashMap<String,SpecTests> TESTS = new HashMap<>();
// private static void putSpecTestsFor(String id, SpecTests tests) {
// TESTS.put(id, tests);
// }
private static SpecTests getSpecTestsFor(String id) {
SpecTests result = TESTS.get(id);
if (null == result) {
throw new Error("no tests found for " + id);
}
return result;
}
// ------------------------------------
final AjctestsAdapter mAjctestsAdapter;
private final Map<String,AjcTest.Spec> mDescriptionToAjcTestSpec;
// ------------------------------------
private SpecTests(AjctestsAdapter ajctestsAdapter, AjcTest.Spec[] tests) {
mAjctestsAdapter = ajctestsAdapter;
Map<String,AjcTest.Spec> map = new HashMap<>();
for (Spec test : tests) {
map.put(test.getDescription(), test);
}
mDescriptionToAjcTestSpec = Collections.unmodifiableMap(map);
}
/**
* @param description
* the String description of the test
* @throws IllegalArgumentException
* if testName is not found
*/
protected void runTest(String description) {
AjcTest.Spec spec = getSpec(description);
AjctestsAdapter.AjcTestSpecAsTest ajcTestAsSpec = new AjctestsAdapter.AjcTestSpecAsTest(
spec, mAjctestsAdapter);
// runTest handles null TestResult
mAjctestsAdapter.runTest(ajcTestAsSpec, null);
}
/**
* @param description
* the String description of the test
* @throws IllegalArgumentException
* if testName is not found
*/
private AjcTest.Spec getSpec(String description) {
AjcTest.Spec spec = mDescriptionToAjcTestSpec
.get(description);
if (null == spec) {
throw new IllegalArgumentException("no test for " + description);
}
return spec;
}
/**
* makeUsingTestClass(..) extends this to create TestCase with
* test_{name} for each test case.
*/
public static class TestClass extends TestCase {
public TestClass() {
}
private SpecTests mTests;
/**
* Called by code generated in makeUsingTestClass(..)
*
* @param description
* the String identifier of the test stored in SpecTests
* mTests.
* @throws Error
* on first and later uses if getTestsFor() returns
* null.
*/
public final void runTest(String description) {
if (null == mTests) {
String classname = getClass().getName();
mTests = getSpecTestsFor(classname);
}
mTests.runTest(description);
}
}
}
/** Wrap AjcTest.Spec as a TestCase. Run by delegation to suite */
private static class AjcTestSpecAsTest extends TestCase implements
HarnessJUnitUtil.IHasAjcSpec {
// this could implement Test, but Ant batchtest fails to pull name
final String name;
final AjcTest.Spec spec;
AjctestsAdapter suite;
AjcTestSpecAsTest(AjcTest.Spec spec, AjctestsAdapter suite) {
super(HarnessJUnitUtil.cleanTestName(spec.getDescription()));
this.name = HarnessJUnitUtil.cleanTestName(spec.getDescription());
this.suite = suite;
this.spec = spec;
spec.setSuiteDir(suite.getSuiteDir());
}
@Override
public int countTestCases() {
return 1;
}
@Override
public AjcTest.Spec getAjcTestSpec() {
return spec;
}
@Override
public void run(TestResult result) {
if (null == suite) {
throw new Error("need to re-init");
}
try {
AjState.FORCE_INCREMENTAL_DURING_TESTING = true;
result.startTest(this);
suite.runTest(this, result);
} finally {
result.endTest(this);
suite = null;
AjState.FORCE_INCREMENTAL_DURING_TESTING = false;
}
}
@Override
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
}
|