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 package org.castor.xmlctf;
46
47 import java.io.File;
48 import java.io.FileInputStream;
49 import java.io.FileWriter;
50 import java.io.InputStream;
51 import java.io.PrintWriter;
52 import java.io.StringWriter;
53 import java.lang.reflect.Method;
54 import java.util.Enumeration;
55 import java.util.LinkedList;
56 import java.util.List;
57
58 import junit.framework.TestCase;
59
60 import org.castor.xmlctf.util.CTFUtils;
61 import org.exolab.castor.mapping.Mapping;
62 import org.exolab.castor.tests.framework.testDescriptor.CallMethod;
63 import org.exolab.castor.tests.framework.testDescriptor.Configuration;
64 import org.exolab.castor.tests.framework.testDescriptor.ConfigurationType;
65 import org.exolab.castor.tests.framework.testDescriptor.FailureType;
66 import org.exolab.castor.tests.framework.testDescriptor.ListenerType;
67 import org.exolab.castor.tests.framework.testDescriptor.UnitTestCase;
68 import org.exolab.castor.tests.framework.testDescriptor.Value;
69 import org.exolab.castor.tests.framework.testDescriptor.types.FailureStepType;
70 import org.exolab.castor.tests.framework.testDescriptor.types.TypeType;
71 import org.exolab.castor.util.NestedIOException;
72 import org.exolab.castor.xml.MarshalException;
73 import org.exolab.castor.xml.MarshalListener;
74 import org.exolab.castor.xml.Marshaller;
75 import org.exolab.castor.xml.Unmarshaller;
76 import org.exolab.castor.xml.XMLContext;
77 import org.xml.sax.InputSource;
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public abstract class XMLTestCase extends TestCase {
92
93
94 public static boolean _verbose;
95
96 protected static boolean _printStack;
97
98 static {
99 String v = System.getProperty(TestCaseAggregator.VERBOSE_PROPERTY);
100 _verbose = (v!=null && v.equals(Boolean.TRUE.toString()));
101
102 v = System.getProperty(TestCaseAggregator.PRINT_STACK_TRACE);
103 _printStack = (v!=null && v.equals(Boolean.TRUE.toString()));
104 }
105
106
107 protected String _suiteName;
108
109
110 protected String _rootClassName;
111
112 protected Class _rootClass;
113
114 protected boolean _hasDump;
115
116
117 protected Mapping _mapping;
118
119 protected Object _listener;
120
121 protected TypeType _listenerType;
122
123 protected String _listenerGoldFile;
124
125 protected Configuration _configuration;
126
127 protected final String _name;
128
129 protected final UnitTestCase _unitTest;
130
131 protected final File _outputRootFile;
132
133 protected final boolean _skip;
134
135 protected final FailureType _failure;
136
137 protected final CastorTestCase _test;
138
139 private XMLContext _xmlContext;
140
141
142
143
144
145
146 public XMLTestCase(final String name) {
147 super(name);
148 _name = cleanup(name);
149 throw new IllegalArgumentException("You cannot use the name-only constructor");
150 }
151
152
153
154
155
156
157
158 public XMLTestCase(final CastorTestCase test, final UnitTestCase unit) {
159 super(unit.getName());
160 _name = cleanup(unit.getName());
161 _unitTest = unit;
162 _skip = unit.getSkip();
163 _failure = unit.getFailure();
164 _test = test;
165 _outputRootFile = test.getOutputRootFile();
166 _xmlContext = null;
167 }
168
169
170
171
172
173
174
175
176 public XMLTestCase(final String name, final XMLTestCase tc) {
177 super(name);
178 _name = cleanup(tc._name);
179 _unitTest = tc._unitTest;
180 _outputRootFile = tc._outputRootFile;
181 _skip = tc._skip;
182 _failure = tc._failure;
183 _test = tc._test;
184 _xmlContext = null;
185 }
186
187 protected abstract void setUp() throws Exception;
188
189 protected abstract void tearDown() throws Exception;
190
191 public void setXMLContext(XMLContext xmlContext) {
192 _xmlContext = xmlContext;
193 }
194
195 public XMLContext getXMLContext() {
196 return _xmlContext;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 static String cleanup(final String name) {
214 return name.replaceAll("[\\*()\\t\\n\\r\\f]", " ").replaceAll(" {2,}", " ").trim();
215 }
216
217
218
219
220
221
222
223 public void setTestSuiteName(final String suiteName) {
224 _suiteName = cleanup(suiteName);
225 }
226
227
228
229
230
231 public String getTestSuiteName() {
232 return _suiteName;
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247 protected boolean checkExceptionWasExpected(final Exception exception, final FailureStepType checkStep) {
248 if (_printStack) {
249 exception.printStackTrace();
250 }
251
252 if (_failure == null || !_failure.getContent()) {
253 return false;
254 }
255 if (checkStep == null) {
256 fail("CTF coding failure ... checkStep should never be null");
257 }
258
259
260
261 String exceptionName = _failure.getException();
262 FailureStepType expectedStep = _failure.getFailureStep();
263
264
265 if (exceptionName == null && expectedStep == null) {
266 return true;
267 }
268
269
270 Exception ex = exception;
271 if (ex instanceof NestedIOException) {
272 ex = ((NestedIOException)ex).getException();
273 }
274
275 if (exceptionName != null) {
276 try {
277 Class expected = Class.forName(exceptionName);
278 if (!expected.isAssignableFrom(ex.getClass())) {
279 String complaint = "Received Exception: '" + ex.getClass().getName()
280 + ": " + ex + "' but expected: '" + exceptionName + "'.";
281
282 StringWriter sw = new StringWriter();
283 PrintWriter pw = new PrintWriter(sw);
284 pw.print(complaint);
285 if (_verbose) {
286 pw.println("Stacktrace for the Exception that was thrown:");
287 ex.printStackTrace(pw);
288 }
289 pw.flush();
290 System.out.println(sw.toString());
291
292 fail(complaint);
293 }
294
295 } catch (ClassNotFoundException cnfex) {
296 fail("The Exception specified: '" + exceptionName + "' cannot be found in the CLASSPATH");
297 }
298 }
299
300
301 if (expectedStep != null && !expectedStep.equals(checkStep)) {
302 fail("We expected to fail at test step '" + expectedStep.toString()
303 + "' but actually failed at step '" + checkStep.toString() + "'");
304 }
305
306
307 return true;
308 }
309
310
311
312
313
314
315
316
317 protected File testMarshal(final Object object, final String fileName) {
318 verbose("--> Marshaling to: '" + fileName + "'");
319
320 File marshalOutput = new File(_outputRootFile, fileName);
321
322 try {
323 Marshaller marshaller = createMarshaler(marshalOutput);
324 marshaller.marshal(object);
325 } catch (Exception e) {
326 if (!checkExceptionWasExpected(e, FailureStepType.MARSHAL_TO_DISK)) {
327 fail("Exception marshaling to disk " + e);
328 }
329 return null;
330 }
331
332 if (_failure != null && _failure.getContent() && _failure.getFailureStep() != null &&
333 _failure.getFailureStep().equals(FailureStepType.MARSHAL_TO_DISK)) {
334 fail("Unmarshaling was expected to fail, but succeeded");
335 }
336 return marshalOutput;
337 }
338
339 private Marshaller createMarshaler(final File marshalOutput) throws Exception {
340 getXMLContext().getInternalContext().getXMLClassDescriptorResolver().cleanDescriptorCache();
341 Marshaller marshaller = getXMLContext().createMarshaller();
342 marshaller.setWriter(new FileWriter(marshalOutput));
343
344
345 Configuration config = _unitTest.getConfiguration();
346 if (config == null) {
347 config = _configuration;
348 }
349
350 if (config != null) {
351 ConfigurationType marshal = config.getMarshal();
352 List returnValues = invokeEnumeratedMethods(marshaller, marshal);
353 returnValues.clear();
354 }
355
356 if (_mapping != null) {
357 marshaller.setMapping(_mapping);
358 }
359
360 if (_listener != null && _listener instanceof MarshalListener
361 && _listenerType != TypeType.UNMARSHAL) {
362 marshaller.setMarshalListener((MarshalListener)_listener);
363 }
364 return marshaller;
365 }
366
367
368
369
370
371
372
373
374
375 protected Object testUnmarshal(final File file) throws Exception {
376 verbose("--> Unmarshaling '" + file.getName() + "'\n");
377 InputStream inputStream = new FileInputStream(file);
378 Object unmarshaledObject = testUnmarshal(inputStream);
379 inputStream.close();
380 assertNotNull("Unmarshaling '" + file.getName() + "' results in a NULL object.",
381 unmarshaledObject);
382 return unmarshaledObject;
383 }
384
385
386
387
388
389
390
391
392
393
394 protected Object testUnmarshal(final InputStream stream) throws Exception {
395 Object result = null;
396 final Unmarshaller unmar = createUnmarshaler();
397 result = unmar.unmarshal(new InputSource(stream));
398 return result;
399 }
400
401 private Unmarshaller createUnmarshaler() throws Exception {
402
403 Configuration config = _unitTest.getConfiguration();
404 if (config == null) {
405 config = _configuration;
406 }
407
408 final Unmarshaller unmar;
409 if (_mapping != null) {
410
411 unmar = getXMLContext().createUnmarshaller();
412 unmar.setMapping(_mapping);
413 } else {
414 if (_test.getClassLoader() != null) {
415
416 unmar = getXMLContext().createUnmarshaller();
417 unmar.setClassLoader(_test.getClassLoader());
418 unmar.setClass(_rootClass);
419 } else {
420
421 unmar = getXMLContext().createUnmarshaller();
422 unmar.setClass(_rootClass);
423 }
424 }
425
426 if (_listener != null
427 && _listener instanceof org.exolab.castor.xml.UnmarshalListener
428 && _listenerType != TypeType.MARSHAL) {
429 unmar.setUnmarshalListener((org.exolab.castor.xml.UnmarshalListener)_listener);
430 }
431
432 if (_listener != null
433 && _listener instanceof org.castor.xml.UnmarshalListener
434 && _listenerType != TypeType.MARSHAL) {
435 unmar.setUnmarshalListener((org.castor.xml.UnmarshalListener)_listener);
436 }
437
438 unmar.setDebug(_verbose);
439
440 if (config != null) {
441 ConfigurationType unmarshal = config.getUnmarshal();
442 List returnValues = invokeEnumeratedMethods(unmar, unmarshal);
443 returnValues.clear();
444 }
445
446 return unmar;
447 }
448
449
450
451
452
453
454
455
456
457
458
459 protected List invokeEnumeratedMethods(final Object objectInvoked, final ConfigurationType config)
460 throws java.lang.Exception {
461 final List returnValues = new LinkedList();
462
463 if (config == null) {
464 return returnValues;
465 }
466
467 Enumeration methods = config.enumerateCallMethod();
468
469 while (methods.hasMoreElements()) {
470 CallMethod method = (CallMethod) methods.nextElement();
471
472 Method toBeinvoked = getInvokeMethod(objectInvoked.getClass(), method.getName(), method.getValue());
473
474 Object[] arguments = getArguments(method.getValue());
475
476 returnValues.add(toBeinvoked.invoke(objectInvoked, arguments));
477 }
478
479 return returnValues;
480 }
481
482
483
484
485
486
487
488
489
490 protected void initializeListeners(final ListenerType listener) throws ClassNotFoundException,
491 IllegalAccessException,
492 InstantiationException {
493 String listenerClassName = listener.getClassName();
494 if (listenerClassName == null || listenerClassName.length() == 0) {
495 throw new IllegalArgumentException("ClassName must be provided for Listener element.");
496 }
497
498 final Class listenerClass;
499 if (_test.getClassLoader() != null) {
500 listenerClass = _test.getClassLoader().loadClass(listenerClassName);
501 } else {
502 listenerClass = Thread.currentThread().getContextClassLoader().loadClass(listenerClassName);
503 }
504
505 Object o = listenerClass.newInstance();
506 if (o instanceof org.castor.xml.UnmarshalListener ||
507 o instanceof org.exolab.castor.xml.UnmarshalListener ||
508 o instanceof MarshalListener) {
509 _listener = o;
510 } else {
511 _listener = null;
512 }
513
514 _listenerGoldFile = listener.getGoldFile();
515 _listenerType = listener.getType();
516 }
517
518
519
520
521
522
523
524
525
526
527 protected Object buildObjectModel(final String builderName) throws java.lang.Exception {
528 Class builderClass = null;
529 if (_test.getClassLoader() != null) {
530 builderClass = _test.getClassLoader().loadClass(builderName);
531 } else {
532 builderClass = this.getClass().getClassLoader().loadClass(builderName);
533 }
534 ObjectModelBuilder builder = (ObjectModelBuilder)builderClass.newInstance();
535 return builder.buildInstance();
536 }
537
538 private Method getInvokeMethod(final Class dataBinder, final String methodName,
539 final Value[] values)
540 throws ClassNotFoundException, NoSuchMethodException {
541 if (methodName == null) {
542 throw new IllegalArgumentException("The name of the method to invoke is null");
543 }
544 Class[] argumentsClass = null;
545
546
547 if (values != null && values.length > 0) {
548 argumentsClass = new Class[values.length];
549 for (int i = 0; i < values.length; i++) {
550 Value value = values[i];
551 argumentsClass[i] = CTFUtils.getClass(value.getType(), _test.getClassLoader());
552 }
553 }
554 return dataBinder.getMethod(methodName, argumentsClass);
555 }
556
557 private Object[] getArguments(final Value[] values) throws ClassNotFoundException, MarshalException {
558 Object[] result = new Object[values.length];
559 for (int i = 0; i < values.length; i++) {
560 Value value = values[i];
561 result[i] = CTFUtils.instantiateObject(value.getType(), value.getContent(), _test.getClassLoader());
562 }
563 return result;
564 }
565
566
567
568
569
570 protected void verbose(final String message) {
571 if (_verbose) {
572 System.out.println(message);
573 }
574 }
575
576 }