1
2
3
4
5 package xjavadoc.codeunit;
6
7 import junit.framework.TestCase;
8 import xjavadoc.*;
9 import xjavadoc.filesystem.ReaderFile;
10
11 import java.util.Iterator;
12 import java.util.StringTokenizer;
13 import java.io.StringWriter;
14 import java.io.File;
15 import java.io.Reader;
16
17 /***
18 * CodeTestCase is a JUnit extension that will let you compare two sources
19 * (typically one we keep as test data and a generated one) on the API level or
20 * on the abstract syntax tree (AST) level. This is a lot more powerful than
21 * comparing on a character by character basis, because it's only "what matters"
22 * that is compared.
23 *
24 * @author Aslak Hellesøy
25 * @created 24. februar 2003
26 */
27 public abstract class CodeTestCase extends TestCase
28 {
29 public CodeTestCase() {
30 super();
31 }
32
33 public static void assertAstEqualsDir( File expectedDir, File actualDir ) {
34 if( !expectedDir.isDirectory() ) {
35 fail(expectedDir.getAbsolutePath() + " - should have been a directory");
36 }
37
38 if( !actualDir.isDirectory() ) {
39 fail(actualDir.getAbsolutePath() + " - should have been a directory");
40 }
41
42 File[] expectedChildren = expectedDir.listFiles();
43
44 for (int i = 0; i < expectedChildren.length; i++) {
45 File expectedChild = expectedChildren[i];
46 File actualChild = getActualChild(actualDir, expectedChild );
47
48 if( !actualChild.exists() ) {
49 fail("File should have existed: " + actualChild.getAbsolutePath());
50 }
51 if( (expectedChild.isDirectory() && !actualChild.isDirectory()) || (!expectedChild.isDirectory() && actualChild.isDirectory()) ) {
52 fail("Incompatible file types: " + expectedChild.getAbsolutePath() + "," + actualChild.getAbsolutePath());
53 }
54
55 if( expectedChild.isDirectory() ) {
56 assertAstEqualsDir(expectedChild, actualChild );
57 } else if( expectedChild.getName().endsWith(".java") ) {
58 System.out.println("Comparing " + expectedChild.getAbsolutePath());
59 assertAstEquals(expectedChild, actualChild);
60 } else {
61 System.out.println("Ignoring non java file: " + expectedChild.getAbsolutePath());
62 }
63 }
64 }
65
66 private static File getActualChild(File actualDir, File expectedChild) {
67 return new File(actualDir, expectedChild.getName());
68 }
69
70
71 /***
72 * Compares both API and AST. Equivalent to calling {@link #assertAstEquals}
73 * and {@link #assertApiEquals}.
74 *
75 * @param expected the expected source
76 * @param actual the actual source
77 */
78 public static void assertEquals( File expected, File actual )
79 {
80 assertAstEquals( expected, actual );
81 assertApiEquals( expected, actual );
82 }
83
84 public static void assertEquals( Reader expected, Reader actual )
85 {
86 assertAstEquals( expected, actual );
87 assertApiEquals( expected, actual );
88 }
89
90 /***
91 * Asserts (tests) that the ASTs of two sources are equal. Does not compare the
92 * contents (tokens) of the nodes, and is forgiving with respect to those.
93 *
94 * @param expected the expected source
95 * @param actual the actual source
96 */
97 public static void assertAstEquals( File expected, File actual )
98 {
99 checkNotDir(expected, actual);
100
101 SourceClass expectedClass = new SourceClass( new XJavaDoc(), expected, true, new XTagFactory() );
102 SourceClass actualClass = new SourceClass( new XJavaDoc(), actual, true, new XTagFactory() );
103
104 assertAstEquals( expectedClass.getCompilationUnit(), actualClass.getCompilationUnit() );
105 }
106
107 public static void assertAstEquals( Reader expected, Reader actual )
108 {
109 SourceClass expectedClass = new SourceClass( new XJavaDoc(), new ReaderFile(expected), true, new XTagFactory(), null );
110 SourceClass actualClass = new SourceClass( new XJavaDoc(), new ReaderFile(actual), true, new XTagFactory(), null );
111
112 assertAstEquals( expectedClass.getCompilationUnit(), actualClass.getCompilationUnit() );
113 }
114 /***
115 * Asserts (tests) that the APIs of two sources are equal. Does not go into the
116 * method bodies to see if the implementation is equal, and is therefore more
117 * relaxed than assertAstEquals.
118 *
119 * @param expected the expected source
120 * @param actual the actual source
121 */
122 public static void assertApiEquals( File expected, File actual )
123 {
124 checkNotDir(expected, actual);
125 SourceClass expectedClass = new SourceClass( new XJavaDoc(), expected, false, new XTagFactory() );
126 SourceClass actualClass = new SourceClass( new XJavaDoc(), actual, false, new XTagFactory() );
127
128 assertApiEquals( expectedClass, actualClass );
129 }
130
131 public static void assertApiEquals( Reader expected, Reader actual )
132 {
133 SourceClass expectedClass = new SourceClass( new XJavaDoc(), new ReaderFile(expected), false, new XTagFactory(), null );
134 SourceClass actualClass = new SourceClass( new XJavaDoc(), new ReaderFile(actual), false, new XTagFactory(), null );
135
136 assertApiEquals( expectedClass, actualClass );
137 }
138
139 private static void checkNotDir(File expected, File actual) {
140 if( expected.isDirectory() ) {
141 fail(expected.getAbsolutePath() + " - should not have been a directory");
142 }
143
144 if( actual.isDirectory() ) {
145 fail(actual.getAbsolutePath() + " - should not have been a directory");
146 }
147 }
148
149 private static void assertAstEquals( SimpleNode expected, SimpleNode actual )
150 {
151
152 boolean sameNodeType = expected.getType().equals( actual.getType() );
153
154 boolean sameNumberOfChildren = expected.jjtGetNumChildren() == actual.jjtGetNumChildren();
155
156 if( !sameNodeType || !sameNumberOfChildren )
157 {
158
159 StringWriter expectedWriter = new StringWriter();
160
161 NodePrinter.print( expected, expectedWriter );
162
163 StringWriter actualWriter = new StringWriter();
164
165 NodePrinter.print( actual, actualWriter );
166
167
168 assertEquals( expectedWriter.toString(), expectedWriter.toString(), actualWriter.toString() );
169 }
170
171 for( int i = 0; i < expected.jjtGetNumChildren(); i++ )
172 {
173 xjavadoc.SimpleNode expectedChild = ( xjavadoc.SimpleNode ) expected.jjtGetChild( i );
174 xjavadoc.SimpleNode actualChild = ( xjavadoc.SimpleNode ) actual.jjtGetChild( i );
175
176 assertAstEquals( expectedChild, actualChild );
177 }
178 }
179
180 private static void assertApiEquals( SourceClass expected, SourceClass actual )
181 {
182 assertEquals( "Package names should be equal", expected.getContainingPackage().getName(), actual.getContainingPackage().getName() );
183 assertModifiersEqual( "Class modifiers should be equal", expected, actual );
184 assertNameEquals( "Class names should be equal", expected, actual );
185 assertSuperclassEquals( expected, actual );
186 assertInterfacesEqual( expected, actual );
187 assertFieldsEqual( expected, actual );
188 assertConstructorsEqual( expected, actual );
189 assertMethodsEqual( expected, actual );
190 }
191
192 private static void assertFieldsEqual( XClass expected, XClass actual )
193 {
194 assertEquals( "Number of fields should be equal", expected.getFields().size(), actual.getFields().size() );
195
196 Iterator expectedFields = expected.getFields().iterator();
197 Iterator actualFields = actual.getFields().iterator();
198
199 while( expectedFields.hasNext() )
200 {
201 XField expectedField = ( XField ) expectedFields.next();
202 XField actualField = ( XField ) actualFields.next();
203
204 assertFieldEquals( expectedField, actualField );
205 }
206 }
207
208 private static void assertConstructorsEqual( XClass expected, XClass actual )
209 {
210 assertEquals( "Number of constructors should be equal", expected.getConstructors().size(), actual.getConstructors().size() );
211
212 Iterator expectedConstructors = expected.getConstructors().iterator();
213 Iterator actualConstructors = actual.getConstructors().iterator();
214
215 while( expectedConstructors.hasNext() )
216 {
217 XConstructor expectedConstructor = ( XConstructor ) expectedConstructors.next();
218 XConstructor actualConstructor = ( XConstructor ) actualConstructors.next();
219
220 assertConstructorEquals( expectedConstructor, actualConstructor );
221 }
222 }
223
224 private static void assertMethodsEqual( XClass expected, XClass actual )
225 {
226 assertEquals( "Number of methods should be equal", expected.getMethods().size(), actual.getMethods().size() );
227
228 Iterator expectedMethods = expected.getMethods().iterator();
229 Iterator actualMethods = actual.getMethods().iterator();
230
231 while( expectedMethods.hasNext() )
232 {
233 XMethod expectedMethod = ( XMethod ) expectedMethods.next();
234 XMethod actualMethod = ( XMethod ) actualMethods.next();
235
236 assertMethodEquals( expectedMethod, actualMethod );
237 }
238 }
239
240 private static void assertFieldEquals( XField expected, XField actual )
241 {
242 assertTypeEquals( "Field types should be equal", expected, actual );
243 assertNameEquals( "Field names should be equal", expected, actual );
244 assertModifiersEqual( "Field modifiers should be equal", expected, actual );
245 }
246
247 private static void assertConstructorEquals( XConstructor expected, XConstructor actual )
248 {
249 assertNameEquals( "Constructor names should be equal", expected, actual );
250 assertModifiersEqual( "Constructor modifiers should be equal", expected, actual );
251 assertNameWithSignatureEquals( "Constructor signatures should be equal", expected, actual );
252 assertParametersEqual( "Constructor parameters should be equal", expected, actual );
253 assertThrownExceptionsEqual( "Constructor exceptions should be equal", expected, actual );
254 }
255
256 private static void assertMethodEquals( XMethod expected, XMethod actual )
257 {
258 assertTypeEquals( "Method types should be equal", expected.getReturnType(), actual.getReturnType() );
259 assertNameEquals( "Method names should be equal", expected, actual );
260 assertModifiersEqual( "Method modifiers should be equal", expected, actual );
261 assertNameWithSignatureEquals( "Method signatures should be equal", expected, actual );
262 assertParametersEqual( "Method parameters should be equal", expected, actual );
263 assertThrownExceptionsEqual( "Method exceptions should be equal", expected, actual );
264 }
265
266 private static void assertParameterEquals( XParameter expected, XParameter actual )
267 {
268 assertTypeEquals( "Parameter types should be equal", expected, actual );
269 assertNameEquals( "Parameter names should be equal", expected, actual );
270 }
271
272 private static void assertTypeEquals( String msg, Type expected, Type actual )
273 {
274 assertEquals( msg, expected.getType().getQualifiedName(), actual.getType().getQualifiedName() );
275 assertEquals( msg, expected.getDimensionAsString(), actual.getDimensionAsString() );
276 }
277
278 private static void assertNameEquals( String msg, Named expected, Named actual )
279 {
280 assertEquals( msg, expected.getName(), actual.getName() );
281 }
282
283 private static void assertSuperclassEquals( SourceClass expected, SourceClass actual )
284 {
285 String expectedSuperclass = expected.getSuperclass() != null ? expected.getSuperclass().getQualifiedName() : null;
286 String actualSuperclass = actual.getSuperclass() != null ? actual.getSuperclass().getQualifiedName() : null;
287
288 assertEquals( "Superclass is equal", expectedSuperclass, actualSuperclass );
289 }
290
291 private static void assertInterfacesEqual( SourceClass expected, SourceClass actual )
292 {
293 assertEquals( "Implemented interfaces should be equal", expected.getDeclaredInterfaces().size(), actual.getDeclaredInterfaces().size() );
294
295 Iterator declaredInterfaces = expected.getDeclaredInterfaces().iterator();
296
297 while( declaredInterfaces.hasNext() )
298 {
299 XClass declaredInterface = ( XClass ) declaredInterfaces.next();
300
301 assertTrue( "Implements " + declaredInterface.getQualifiedName(), actual.isA( declaredInterface.getQualifiedName() ) );
302 }
303 }
304
305 private static void assertModifiersEqual( String msg, XProgramElement expected, XProgramElement actual )
306 {
307 assertEquals( msg, expected.getModifiers(), actual.getModifiers() );
308 }
309
310 private static void assertNameWithSignatureEquals( String msg, XExecutableMember expected, XExecutableMember actual )
311 {
312 assertEquals( msg, expected.getNameWithSignature( false ), actual.getNameWithSignature( false ) );
313 }
314
315 private static void assertParametersEqual( String msg, XExecutableMember expected, XExecutableMember actual )
316 {
317 assertEquals( msg, expected.getParameters().size(), actual.getParameters().size() );
318
319 Iterator expectedParameters = expected.getParameters().iterator();
320 Iterator actualParameters = actual.getParameters().iterator();
321
322 while( expectedParameters.hasNext() )
323 {
324 XParameter expectedParameter = ( XParameter ) expectedParameters.next();
325 XParameter actualParameter = ( XParameter ) actualParameters.next();
326
327 assertParameterEquals( expectedParameter, actualParameter );
328 }
329 }
330
331 private static void assertThrownExceptionsEqual( String msg, XExecutableMember expected, XExecutableMember actual )
332 {
333 assertEquals( msg, expected.getThrownExceptions().size(), actual.getThrownExceptions().size() );
334
335 Iterator expectedThrownExceptions = expected.getThrownExceptions().iterator();
336
337 while( expectedThrownExceptions.hasNext() )
338 {
339 XClass expectedThrownException = ( XClass ) expectedThrownExceptions.next();
340
341 assertTrue( "Throws " + expectedThrownException.getQualifiedName(), actual.throwsException( expectedThrownException.getQualifiedName() ) );
342 }
343 }
344
345 /***
346 * Returns the directory where this class is located, provided that it's not in
347 * a jar. This is very useful for accessing the files you want to compare.
348 *
349 * @return the directory where this class is located.
350 */
351 protected File getDir()
352 {
353 return new File( getClass().getResource( "/" + getClass().getName().replace( '.', '/' ) + ".class" ).getFile() ).getParentFile();
354 }
355
356 /***
357 * Returns the root directory of the package hierarchy where this class is
358 * located, provided that it's not in a jar. This is very useful for accessing
359 * the files you want to compare.
360 *
361 * @return the root directory.
362 */
363 protected File getRootDir()
364 {
365 File dir = getDir();
366 StringTokenizer st = new StringTokenizer( getClass().getName(), "." );
367
368
369 for( int i = 0; i < st.countTokens() - 1; i++ )
370 {
371 dir = dir.getParentFile();
372 }
373 return dir;
374 }
375
376 protected XJavaDoc getXJavaDoc() {
377 return new XJavaDoc();
378 }
379 }