KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > model > repl > JavaInterpreterTest


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.model.repl;
35
36 import edu.rice.cs.drjava.DrJava;
37 import edu.rice.cs.drjava.DrJavaTestCase;
38 import edu.rice.cs.drjava.config.OptionConstants;
39 import edu.rice.cs.drjava.config.OptionListener;
40 import edu.rice.cs.drjava.config.OptionEvent;
41 import edu.rice.cs.drjava.model.repl.newjvm.ClassPathManager;
42 import edu.rice.cs.util.swing.Utilities;
43
44 import junit.framework.*;
45
46 /** Tests the functionality of the repl interpreter.
47   * @version $Id: JavaInterpreterTest.java 4057 2007-01-16 00:06:10Z dlsmith $
48   */

49 public final class JavaInterpreterTest extends DrJavaTestCase {
50   private JavaInterpreter _interpreter;
51   static public boolean testValue;
52
53   /** The setup method run before each test. */
54   protected void setUp() throws Exception JavaDoc {
55     super.setUp();
56     _interpreter = new DynamicJavaAdapter(new ClassPathManager());
57     testValue = false;
58   }
59
60   /** Asserts that the results of interpreting the first of each
61     * Pair is equal to the second.
62     * @param cases an array of Pairs
63     */

64   private void tester(Pair[] cases) throws ExceptionReturnedException {
65     for (int i = 0; i < cases.length; i++) {
66       Object JavaDoc out = _interpreter.interpret(cases[i].first());
67       assertEquals(cases[i].first() + " interpretation wrong!", cases[i].second(), out);
68     }
69   }
70
71   /** Make sure interpreting simple constants works.
72     * Note that strings and characters are quoted.
73     */

74   public void testConstants() throws ExceptionReturnedException {
75     Pair[] cases = new Pair[] {
76       Pair.make("5", new Integer JavaDoc(5)),
77         Pair.make("1356", new Integer JavaDoc(1356)),
78         Pair.make("true", Boolean.TRUE),
79         Pair.make("false", Boolean.FALSE),
80         Pair.make("\'c\'", "'" + new Character JavaDoc('c') + "'"),
81         Pair.make("1.345", new Double JavaDoc(1.345)),
82         Pair.make("\"buwahahahaha!\"", "\"buwahahahaha!\""),
83         Pair.make("\"yah\\\"eh\\\"\"", "\"yah\"eh\"\""),
84         Pair.make("'\\''", "'" + new Character JavaDoc('\'') + "'")
85     };
86     tester(cases);
87   }
88
89   /** Test simple operations with Booleans */
90   public void testBooleanOps() throws ExceptionReturnedException {
91     Pair[] cases = new Pair[] {
92       //and
93
Pair.make("true && false", Boolean.FALSE), Pair.make("true && true",
94           Boolean.TRUE),
95       //or
96
Pair.make("true || true", Boolean.TRUE), Pair.make("false || true", Boolean.TRUE),
97           Pair.make("false || false", Boolean.FALSE),
98       // not
99
Pair.make("!true", Boolean.FALSE), Pair.make("!false", Boolean.TRUE),
100           //equals
101
Pair.make("true == true", Boolean.TRUE), Pair.make("false == true", Boolean.FALSE),
102           Pair.make("false == false", Boolean.TRUE),
103       // xor
104
Pair.make("false ^ false", Boolean.valueOf(false ^ false)), Pair.make("false ^ true ",
105           Boolean.valueOf(false ^ true))
106     };
107     tester(cases);
108   }
109
110   /** Tests short circuiting */
111   public void testShortCircuit() throws ExceptionReturnedException {
112     Pair[] cases = new Pair[] {
113       Pair.make("false && (3 == 1/0)", Boolean.FALSE),
114       Pair.make("true || (1/0 != 43)", Boolean.TRUE)
115     };
116     tester(cases);
117   }
118
119   /**
120    * put your documentation comment here
121    */

122   public void testIntegerOps() throws ExceptionReturnedException {
123     Pair[] cases = new Pair[] {
124 // // plus
125
// Pair.make("5+6", new Integer(5 + 6)),
126
// // minus
127
// Pair.make("6-5", new Integer(6 - 5)),
128
// // times
129
// Pair.make("6*5", new Integer(6*5)),
130
// // divide
131
// Pair.make("6/5", new Integer(6/5)),
132
// // modulo
133
// Pair.make("6%5", new Integer(6%5)),
134
// // bit and
135
// Pair.make("6&5", new Integer(6 & 5)),
136
// // bit or
137
// Pair.make("6 | 5", new Integer(6 | 5)),
138
// // bit xor
139
// Pair.make("6^5", new Integer(6 ^ 5)),
140
// // bit complement
141
// Pair.make("~6", new Integer(~6)),
142
// unary plus
143
// Pair.make("+5", new Integer(+5)),
144
// // unary minus
145
// Pair.make("-5", new Integer(-5)),
146
// left shift
147
Pair.make("400 << 5", new Integer JavaDoc(400 << 5)),
148       // right shift
149
Pair.make("400 >> 5", new Integer JavaDoc(400 >> 5)),
150       // unsigned right shift
151
Pair.make("400 >>> 5", new Integer JavaDoc(400 >>> 5)),
152 // // less than
153
// Pair.make("5 < 4", Boolean.valueOf(5 < 4)),
154
// // less than or equal to
155
// Pair.make("4 <= 4", Boolean.valueOf(4 <= 4)), Pair.make("4 <= 5", Boolean.valueOf(4 <= 5)),
156
// // greater than
157
// Pair.make("5 > 4", Boolean.valueOf(5 > 4)), Pair.make("5 > 5", Boolean.valueOf(5 > 5)),
158
// // greater than or equal to
159
// Pair.make("5 >= 4", Boolean.valueOf(5 >= 4)), Pair.make("5 >= 5", Boolean.valueOf(5 >= 5)),
160
// // equal to
161
// Pair.make("5 == 5", Boolean.valueOf(5 == 5)), Pair.make("5 == 6", Boolean.valueOf(
162
// 5 == 6)),
163
// // not equal to
164
Pair.make("5 != 6", Boolean.valueOf(5 != 6)), Pair.make("5 != 5", Boolean.valueOf(5 != 5))
165     };
166     tester(cases);
167   }
168
169   /**
170    * put your documentation comment here
171    */

172   public void testDoubleOps() throws ExceptionReturnedException {
173     Pair[] cases = new Pair[] {
174       // less than
175
Pair.make("5.6 < 6.7", Boolean.valueOf(5.6 < 6.7)),
176       // less than or equal to
177
Pair.make("5.6 <= 5.6", Boolean.valueOf(5.6 <= 5.6)),
178       // greater than
179
Pair.make("5.6 > 4.5", Boolean.valueOf(5.6 > 4.5)),
180       // greater than or equal to
181
Pair.make("5.6 >= 56.4", Boolean.valueOf(5.6 >= 56.4)),
182       // equal to
183
Pair.make("5.4 == 5.4", Boolean.valueOf(5 == 5)),
184       // not equal to
185
Pair.make("5.5 != 5.5", Boolean.valueOf(5 != 5)),
186       // unary plus
187
Pair.make("+5.6", new Double JavaDoc(+5.6)),
188       // unary minus
189
Pair.make("-5.6", new Double JavaDoc(-5.6)),
190       // times
191
Pair.make("5.6 * 4.5", new Double JavaDoc(5.6*4.5)),
192       // divide
193
Pair.make("5.6 / 3.4", new Double JavaDoc(5.6/3.4)),
194       // modulo
195
Pair.make("5.6 % 3.4", new Double JavaDoc(5.6%3.4)),
196       // plus
197
Pair.make("5.6 + 6.7", new Double JavaDoc(5.6 + 6.7)),
198       // minus
199
Pair.make("4.5 - 3.4", new Double JavaDoc(4.5 - 3.4)),
200     };
201     tester(cases);
202   }
203
204   /**
205    * put your documentation comment here
206    */

207   public void testStringOps() throws ExceptionReturnedException {
208     Pair[] cases = new Pair[] {
209       // concatenation
210
Pair.make("\"yeah\" + \"and\"", "\"yeah" + "and\""),
211       // equals
212
Pair.make("\"yeah\".equals(\"yeah\")", Boolean.valueOf("yeah".equals("yeah"))),
213
214     };
215     tester(cases);
216   }
217
218   /**
219    * put your documentation comment here
220    */

221   public void testCharacterOps() throws ExceptionReturnedException{
222     Pair[] cases = new Pair[] {
223       // equals
224
Pair.make("'c' == 'c'", Boolean.valueOf('c' == 'c'))
225     };
226     tester(cases);
227   }
228
229   /**
230    * Tests that String and character declarations do not return
231    * a result, while the variables themselves return a quoted result.
232    */

233   public void testSemicolon() throws ExceptionReturnedException {
234     Pair[] cases = new Pair[] {
235       Pair.make("'c' == 'c'", Boolean.valueOf('c' == 'c')),
236       Pair.make("'c' == 'c';", JavaInterpreter.NO_RESULT),
237       Pair.make("String s = \"hello\"", JavaInterpreter.NO_RESULT),
238       Pair.make("String x = \"hello\";", JavaInterpreter.NO_RESULT),
239       Pair.make("char c = 'c'", JavaInterpreter.NO_RESULT),
240       Pair.make("Character d = new Character('d')", JavaInterpreter.NO_RESULT),
241       Pair.make("s", "\"hello\""), Pair.make("s;", JavaInterpreter.NO_RESULT),
242       Pair.make("x", "\"hello\""), Pair.make("x;", JavaInterpreter.NO_RESULT),
243       Pair.make("c", "'c'"), Pair.make("d", "'d'")
244     };
245     tester(cases);
246   }
247
248   /**
249    * Tests that null can be used in instanceof expressions.
250    */

251   public void testNullInstanceOf() throws ExceptionReturnedException {
252     Pair[] cases = new Pair[] {
253       Pair.make("null instanceof Object", Boolean.valueOf(null instanceof Object JavaDoc)),
254       Pair.make("null instanceof String", Boolean.valueOf(null instanceof String JavaDoc))
255     };
256     tester(cases);
257   }
258
259   /**
260    * Tests simple variable definitions which broke the initial implementation
261    * of variable redefinition (tested by testVariableRedefinition).
262    */

263   public void testVariableDefinition() throws ExceptionReturnedException {
264     _interpreter.interpret("int a = 5;");
265     _interpreter.interpret("int b = a;");
266
267     _interpreter.interpret("int c = a++;");
268   }
269
270   /**
271    * Tests that variables are assigned default values.
272    */

273   public void testVariableDefaultValues() throws ExceptionReturnedException {
274     _interpreter.interpret("byte b");
275     _interpreter.interpret("short s");
276     _interpreter.interpret("int i");
277     _interpreter.interpret("long l");
278     _interpreter.interpret("float f");
279     _interpreter.interpret("double d");
280     _interpreter.interpret("char c");
281     _interpreter.interpret("boolean bool");
282     _interpreter.interpret("String str");
283     Pair[] cases = new Pair[] {
284       Pair.make("b", new Byte JavaDoc((byte)0)),
285       Pair.make("s", new Short JavaDoc((short)0)),
286       Pair.make("i", new Integer JavaDoc(0)),
287       Pair.make("l", new Long JavaDoc(0L)),
288       Pair.make("f", new Float JavaDoc(0.0f)),
289       Pair.make("d", new Double JavaDoc(0.0d)),
290       Pair.make("c", "'" + new Character JavaDoc('\u0000') + "'"), // quotes are added around chars
291
Pair.make("bool", Boolean.valueOf(false)),
292       Pair.make("str", null)
293     };
294     tester(cases);
295   }
296
297   /**
298    * Tests that variable declarations with errors will not allow the interpreter
299    * to not define the variable. This will get rid of annoying "Error:
300    * Redefinition of 'variable'" messages after fixing the error. Note that if
301    * the error occurs during the evaluation of the right hand side then the
302    * variable is defined. This is for two reasons: The compiler would have
303    * accepted this variable declaration so that no more variables could have
304    * been defined with the same name afterwards, and we don't know how to make
305    * sure the evaluation doesn't return errors without actually evaluating which
306    * may have side-effects.
307    */

308   public void testVariableRedefinition() throws ExceptionReturnedException{
309     // test error in NameVisitor
310
try {
311       _interpreter.interpret("String s = abc;");
312       fail("variable definition should have failed");
313     }
314     catch (ExceptionReturnedException e) {
315       // Correct; it should fail
316
}
317     // test error in TypeChecker
318
try {
319       _interpreter.interpret("Vector v = new Vector();");
320       fail("variable definition should have failed");
321     }
322     catch (ExceptionReturnedException e) {
323       // Correct; it should fail
324
}
325     try {
326       _interpreter.interpret("File f;");
327       fail("variable definition should have failed");
328     }
329     catch (ExceptionReturnedException e) {
330       // Correct; it should fail
331
}
332     try {
333       // make sure we can redefine
334
_interpreter.interpret("import java.util.Vector;");
335       _interpreter.interpret("Vector v = new Vector();");
336       _interpreter.interpret("String s = \"abc\";");
337       _interpreter.interpret("import java.io.File;");
338       _interpreter.interpret("File f = new File(\"\");");
339     }
340     catch (ExceptionReturnedException e) {
341       fail("These interpret statements shouldn't cause errors");
342     }
343     // test error in EvaluationVisitor
344

345     // Integer.getInteger("somebadproperty") should be null
346
try {
347       _interpreter.interpret("String z = new String(Integer.getInteger(\"somebadproperty\").toString());");
348       fail("variable definition should have failed");
349     }
350     catch (ExceptionReturnedException e) {
351     }
352     // The DynamcjavaAdapter should have undone the binding made
353
// for "z" when the first definition fails. Defining it again
354
// should work.
355
_interpreter.interpret("String z = \"z\";");
356     
357   }
358
359   /** Ensure that the interpreter rejects assignments where the right type is not a subclass of the left type. */
360   public void testIncompatibleAssignment() throws ExceptionReturnedException {
361     try {
362       _interpreter.interpret("Integer i = new Object()");
363       fail("incompatible assignment should have failed");
364     }
365     catch (ExceptionReturnedException e) {
366       // Correct; it should fail
367
}
368     try {
369       _interpreter.interpret("Integer i2 = (Integer)new Object();");
370       fail("incompatible assignment should have failed");
371     }
372     catch (ExceptionReturnedException e) {
373       // Correct; it should fail
374
}
375
376     // Check that a correct assignment doesn't fail
377
_interpreter.interpret("Object o = new Integer(3)");
378   }
379
380  /** Test the operation of the TypeCheckerExtension by performing the operations ((false) ? 2/0 : 1) and
381   * ((false) ? 2%0 : 1), which should not throw Exceptions in the Java interpreter.
382   */

383   public void testTypeCheckerExtension() {
384     try { _interpreter.interpret("(false) ? 2/0 : 1 "); }
385     catch(ExceptionReturnedException e) {
386       if ( e.getContainedException() instanceof ArithmeticException JavaDoc ) {
387         fail("testTypeCheckerExtension failed to prevent short circuit DivideByZeroException");
388       }
389     }
390
391     try { _interpreter.interpret("(false) ? 2%0 : 1 "); }
392     catch(ExceptionReturnedException e) {
393       if ( e.getContainedException() instanceof ArithmeticException JavaDoc ) {
394         fail("testTypeCheckerExtension failed to prevent short circuit DivideByZeroException");
395       }
396     }
397   }
398
399   /** Test the operation of the EvaluationVisitorExtension by performing a computation with no results (interpreter
400    * should return NO_RESULT and not null)
401    */

402   public void testEvaluationVisitorExtensionNO_RESULT() {
403     try {
404       Object JavaDoc out = _interpreter.interpret("true;");
405       assertEquals("testEvaluationVisitorExtension", JavaInterpreter.NO_RESULT, out);
406     }
407     catch(ExceptionReturnedException e) {
408       fail("testEvaluationVisitorExtension Exception returned for none exceptional code!" + e);
409     }
410   }
411
412   /** Test that a variable can be defined in the interpreter by an external source. */
413   public void testDefineVariableExternally() throws ExceptionReturnedException {
414     _interpreter.defineVariable("foo", "hello");
415     assertEquals("manipulated externally defined variable",
416                  "\"ello\"", _interpreter.interpret("foo.substring(1,5)"));
417     _interpreter.defineVariable("x", 3);
418     assertEquals("externally defined variable x",
419                  new Integer JavaDoc(3), _interpreter.interpret("x"));
420     assertEquals("incremented externally defined variable x",
421                  new Integer JavaDoc(4), _interpreter.interpret("++x"));
422   }
423
424   /** Test that the value of a variable can be queried externally. */
425   public void testQueryVariableExternally() {
426     _interpreter.defineVariable("x", 7);
427     // Get value of variable externally
428
assertEquals("external query for x",
429                  new Integer JavaDoc(7), _interpreter.getVariable("x"));
430
431     // Undefined variable
432
try {
433       _interpreter.getVariable("undefined");
434       fail("Should have thrown IllegalStateException");
435     }
436     catch (IllegalStateException JavaDoc e) {
437       // good, that's what we want
438
}
439   }
440
441   /** Test that a constant can be defined in the interpreter by an external source. */
442   public void testDefineConstantExternally() {
443     _interpreter.defineConstant("y", 3);
444     try {
445       _interpreter.interpret("y = 4");
446       fail("should not be able to assign to a constant");
447     }
448     catch (ExceptionReturnedException e) {
449       // correct, it should fail
450
}
451   }
452
453   /** Test that arrays initializers are accepted. */
454   public void testInitializeArrays() throws ExceptionReturnedException {
455     try {
456       _interpreter.interpret("int i[] = new int[]{1,2,3};");
457       _interpreter.interpret("int j[][] = new int[][]{{1}, {2,3}};");
458       _interpreter.interpret("int k[][][][] = new int[][][][]{{{{1},{2,3}}}};");
459     }
460     catch(IllegalArgumentException JavaDoc iae) {
461       fail("Legal array initializations were not accepted.");
462     }
463   }
464
465   /** Test that array cloning works. */
466   public void testArrayCloning() throws ExceptionReturnedException {
467     try { _interpreter.interpret("new int[]{0}.clone()"); }
468     catch(RuntimeException JavaDoc e) { fail("Array cloning failed."); }
469   }
470   
471   /** Test that the Interactions Pane will or won't allow access to private members
472    * given the value of the ALLOW_PRIVATE_ACCESS configuration option.
473    */

474   public void testAllowPrivateAccess() throws ExceptionReturnedException {
475     // The real option listener is in DefaultGlobalModel, so add one here.
476
DrJava.getConfig().addOptionListener(OptionConstants.ALLOW_PRIVATE_ACCESS, new OptionListener<Boolean JavaDoc>() {
477       public void optionChanged(OptionEvent<Boolean JavaDoc> oce) {
478         _interpreter.setPrivateAccessible(oce.value.booleanValue());
479       }
480     });
481     DrJava.getConfig().setSetting(OptionConstants.ALLOW_PRIVATE_ACCESS, Boolean.valueOf(false));
482     Utilities.clearEventQueue();
483 // System.err.println("\nPrivate Access = " + _interpreter.getPrivateAccessible());
484
try {
485       _interpreter.interpret("class A { private int i = 0; }");
486       _interpreter.interpret("new A().i");
487       System.out.println("Private access erroneously succeeded");
488       fail("Should not have access to the private field i inside class A.");
489     }
490     catch (ExceptionReturnedException ere) {
491       assertTrue(ere.getContainedException() instanceof IllegalAccessException JavaDoc);
492     }
493     DrJava.getConfig().setSetting(OptionConstants.ALLOW_PRIVATE_ACCESS, Boolean.valueOf(true));
494     Utilities.clearEventQueue();
495     assertEquals("Should be able to access private field i whose value should be 0",
496                  new Integer JavaDoc(0),
497                  _interpreter.interpret("new A().i"));
498   }
499
500   /**
501    * Tests that declaring a void method in the Interactions Pane won't cause a bad type
502    * exception. Tests bug #915906 "Methods in Interactions no longer work".
503    */

504   public void testDeclareVoidMethod() {
505     try { _interpreter.interpret("void method() {}"); }
506     catch (ExceptionReturnedException ere) { fail("Should be able to declare void methods."); }
507   }
508
509   /**
510    * Tests that a call to user-defined void method returns NO_RESULT, instead of null.
511    * This test does not pass, it is currently broken.
512    */

513   public void testUserDefinedVoidMethod() throws ExceptionReturnedException {
514      Object JavaDoc result = _interpreter.interpret("public void foo() {}; foo()");
515      assertSame("Should have returned NO_RESULT.", Interpreter.NO_RESULT, result);
516    }
517 }
518
519 /**
520  * A structure to contain a String and an Object pair.
521  * This class is used to help test the JavaInterpreter.
522  * TODO: Is there a reason this is declared explicitly? Maybe for the
523  * sake of serialization or reflection?
524  */

525 class Pair extends edu.rice.cs.plt.tuple.Pair<String JavaDoc, Object JavaDoc> {
526   /**
527    * Constructs a pair.
528    * @param f the first item in the pair
529    * @param s the second in the pair
530    */

531   public Pair(String JavaDoc f, Object JavaDoc s) { super(f, s); }
532
533   /**
534    * Makes a new pair.
535    * @param first the first item in the pair
536    * @param second the second in the pair
537    * @return the new Pair
538    */

539   public static Pair make(String JavaDoc first, Object JavaDoc second) { return new Pair(first, second); }
540
541 }
542
Popular Tags