Merged revisions 2121-2135 via svnmerge from
[scons.git] / src / engine / SCons / Tool / JavaCommonTests.py
1 #
2 # __COPYRIGHT__
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
25
26 import os.path
27 import sys
28 import unittest
29
30 import SCons.Tool.JavaCommon
31
32
33 # Adding trace=trace to any of the parse_jave() calls below will cause
34 # the parser to spit out trace messages of the tokens it sees and the
35 # attendant transitions.
36
37 def trace(token, newstate):
38     from SCons.Debug import Trace
39     statename = newstate.__class__.__name__
40     Trace('token = %s, state = %s\n' % (repr(token), statename))
41
42 class parse_javaTestCase(unittest.TestCase):
43
44     def test_bare_bones(self):
45         """Test a bare-bones class"""
46
47         input = """\
48 package com.sub.bar;
49
50 public class Foo
51 {
52
53      public static void main(String[] args)
54      {
55
56         /* This tests a former bug where strings would eat later code. */
57         String hello1 = new String("Hello, world!");
58
59      }
60
61 }
62 """
63         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
64         assert pkg_dir == os.path.join('com', 'sub', 'bar'), pkg_dir
65         assert classes == ['Foo'], classes
66
67
68     def test_inner_classes(self):
69         """Test parsing various forms of inner classes"""
70
71         input = """\
72 class Empty {
73 }
74
75 interface Listener {
76   public void execute();
77 }
78
79 public
80 class
81 Test implements Listener {
82   class Inner {
83     void go() {
84       use(new Listener() {
85         public void execute() {
86           System.out.println("In Inner");
87         }
88       });
89     }
90     String s1 = "class A";
91     String s2 = "new Listener() { }";
92     /* class B */
93     /* new Listener() { } */
94   }
95
96   class Inner2 {
97      Inner2() { Listener l = new Listener(); }
98   }
99
100   /* Make sure this class doesn't get interpreted as an inner class of the previous one, when "new" is used in the previous class. */
101   class Inner3 {
102
103   }
104
105   public static void main(String[] args) {
106     new Test().run();
107   }
108
109   void run() {
110     use(new Listener() {
111       public void execute() {
112         use(new Listener( ) {
113           public void execute() {
114             System.out.println("Inside execute()");
115           }
116         });
117       }
118     });
119
120     new Inner().go();
121   }
122
123   void use(Listener l) {
124     l.execute();
125   }
126 }
127
128 class Private {
129   void run() {
130     new Listener() {
131       public void execute() {
132       }
133     };
134   }
135 }
136 """
137
138         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4')
139         assert pkg_dir is None, pkg_dir
140         expect = [
141                    'Empty',
142                    'Listener',
143                    'Test$1',
144                    'Test$Inner',
145                    'Test$Inner2',
146                    'Test$Inner3',
147                    'Test$2',
148                    'Test$3',
149                    'Test',
150                    'Private$1',
151                    'Private',
152                  ]
153         assert classes == expect, classes
154
155         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5')
156         assert pkg_dir is None, pkg_dir
157         expect = [
158                    'Empty',
159                    'Listener',
160                    'Test$Inner$1',
161                    'Test$Inner',
162                    'Test$Inner2',
163                    'Test$Inner3',
164                    'Test$1',
165                    'Test$1$1',
166                    'Test',
167                    'Private$1',
168                    'Private',
169                  ]
170         assert classes == expect, (expect, classes)
171
172
173
174     def test_comments(self):
175         """Test a class with comments"""
176
177         input = """\
178 package com.sub.foo;
179
180 import java.rmi.Naming;
181 import java.rmi.RemoteException;
182 import java.rmi.RMISecurityManager;
183 import java.rmi.server.UnicastRemoteObject;
184
185 public class Example1 extends UnicastRemoteObject implements Hello {
186
187     public Example1() throws RemoteException {
188         super();
189     }
190
191     public String sayHello() {
192         return "Hello World!";
193     }
194
195     public static void main(String args[]) {
196         if (System.getSecurityManager() == null) {
197             System.setSecurityManager(new RMISecurityManager());
198         }
199         // a comment
200         try {
201             Example1 obj = new Example1();
202
203             Naming.rebind("//myhost/HelloServer", obj);
204
205             System.out.println("HelloServer bound in registry");
206         } catch (Exception e) {
207             System.out.println("Example1 err: " + e.getMessage());
208             e.printStackTrace();
209         }
210     }
211 }
212 """
213
214         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
215         assert pkg_dir == os.path.join('com', 'sub', 'foo'), pkg_dir
216         assert classes == ['Example1'], classes
217
218
219     def test_arrays(self):
220         """Test arrays of class instances"""
221
222         input = """\
223 public class Test {
224     MyClass abc = new MyClass();
225     MyClass xyz = new MyClass();
226     MyClass _array[] = new MyClass[] {
227         abc,
228         xyz
229     }
230 }
231 """
232
233         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
234         assert pkg_dir == None, pkg_dir
235         assert classes == ['Test'], classes
236
237
238
239     def test_backslash(self):
240         """Test backslash handling"""
241
242         input = """\
243 public class MyTabs
244 {
245         private class MyInternal
246         {
247         }
248         private final static String PATH = "images\\\\";
249 }
250 """
251
252         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
253         assert pkg_dir == None, pkg_dir
254         assert classes == ['MyTabs$MyInternal', 'MyTabs'], classes
255
256
257     def test_enum(self):
258         """Test the Java 1.5 enum keyword"""
259
260         input = """\
261 package p;
262 public enum a {}
263 """
264
265         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
266         assert pkg_dir == 'p', pkg_dir
267         assert classes == ['a'], classes
268
269
270     def test_anon_classes(self):
271         """Test anonymous classes"""
272
273         input = """\
274 public abstract class TestClass
275 {
276     public void completed()
277     {
278         new Thread()
279         {
280         }.start();
281
282         new Thread()
283         {
284         }.start();
285     }
286 }
287 """
288
289         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
290         assert pkg_dir == None, pkg_dir
291         assert classes == ['TestClass$1', 'TestClass$2', 'TestClass'], classes
292
293
294     def test_closing_bracket(self):
295         """Test finding a closing bracket instead of an anonymous class"""
296
297         input = """\
298 class TestSCons {
299     public static void main(String[] args) {
300         Foo[] fooArray = new Foo[] { new Foo() };
301     }
302 }
303
304 class Foo { }
305 """
306
307         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
308         assert pkg_dir == None, pkg_dir
309         assert classes == ['TestSCons', 'Foo'], classes
310
311
312     def test_dot_class_attributes(self):
313         """Test handling ".class" attributes"""
314
315         input = """\
316 public class Test extends Object
317 {
318     static {
319         Class c = Object[].class;
320         Object[] s = new Object[] {};
321     }
322 }
323 """
324
325         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
326         assert classes == ['Test'], classes
327
328         input = """\
329 public class A {
330     public class B {
331         public void F(Object[] o) {
332             F(new Object[] {Object[].class});
333         }
334         public void G(Object[] o) {
335             F(new Object[] {});
336         }
337     }
338 }
339 """
340
341         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input)
342         assert pkg_dir == None, pkg_dir
343         assert classes == ['A$B', 'A'], classes
344
345     def test_anonymous_classes_with_parentheses(self):
346         """Test finding anonymous classes marked by parentheses"""
347
348         input = """\
349 import java.io.File;
350
351 public class Foo {
352     public static void main(String[] args) {
353         File f = new File(
354             new File("a") {
355                 public String toString() {
356                     return "b";
357                 }
358             } to String()
359         ) {
360             public String toString() {
361                 return "c";
362             }
363         };
364     }
365 }
366 """
367
368         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4')
369         assert classes == ['Foo$1', 'Foo$2', 'Foo'], classes
370
371         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5')
372         assert classes == ['Foo$1', 'Foo$1$1', 'Foo'], classes
373
374
375
376     def test_nested_anonymous_inner_classes(self):
377         """Test finding nested anonymous inner classes"""
378
379         input = """\
380 // import java.util.*;
381
382 public class NestedExample
383 {
384         public NestedExample()
385         {
386                 Thread t = new Thread() {
387                         public void start()
388                         {
389                                 Thread t = new Thread() {
390                                         public void start()
391                                         {
392                                                 try {Thread.sleep(200);}
393                                                 catch (Exception e) {}
394                                         }
395                                 };
396                                 while (true)
397                                 {
398                                         try {Thread.sleep(200);}
399                                         catch (Exception e) {}
400                                 }
401                         }
402                 };
403         }
404
405
406         public static void main(String argv[])
407         {
408                 NestedExample e = new NestedExample();
409         }
410 }
411 """
412
413         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.4')
414         expect = [ 'NestedExample$1', 'NestedExample$2', 'NestedExample' ]
415         assert expect == classes, (expect, classes)
416
417         pkg_dir, classes = SCons.Tool.JavaCommon.parse_java(input, '1.5')
418         expect = [ 'NestedExample$1', 'NestedExample$1$1', 'NestedExample' ]
419         assert expect == classes, (expect, classes)
420
421
422
423 if __name__ == "__main__":
424     suite = unittest.TestSuite()
425     tclasses = [ parse_javaTestCase ]
426     for tclass in tclasses:
427         names = unittest.getTestCaseNames(tclass, 'test_')
428         suite.addTests(map(tclass, names))
429     if not unittest.TextTestRunner().run(suite).wasSuccessful():
430         sys.exit(1)