/******************************************************************************* * Copyright (c) 2012 Pivotal Software, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.groovy.debug.tests; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IValue; import org.eclipse.jdt.debug.core.IJavaClassObject; import org.eclipse.jdt.debug.core.IJavaDebugTarget; import org.eclipse.jdt.debug.core.IJavaObject; import org.eclipse.jdt.debug.core.IJavaPrimitiveValue; import org.eclipse.jdt.debug.core.IJavaType; import org.eclipse.jdt.debug.core.IJavaValue; import org.eclipse.jdt.debug.tests.eval.Tests; /** * @author Andrew Eisenberg */ public class GroovyDebugTests extends Tests { public GroovyDebugTests(String arg) { super(arg); } @Override protected void setUp() throws Exception { super.setUp(); SanityChecker.assertJDTWeaving(); } @Override protected void tearDown() throws Exception { super.tearDown(); end(); } protected void init() throws Exception { initializeFrame("EvalSimpleTests", 43, 1); } protected void initClosure() throws Exception { // stack built differently in 2.0 and later if (GroovyUtils.GROOVY_LEVEL < 20) { initializeFrame("ClosureTests", 5, 43); } else { initializeFrame("ClosureTests", 5, 31); } } protected void initPackage() throws Exception { initializeFrame("pack.other.OtherPackageTests", 19, 1); } protected void end() throws Exception { destroyFrame(); } // boolean | boolean public void testBooleanOrBoolean() throws Throwable { init(); IValue value = eval(xBoolean + orOp + xBoolean); String typeName = value.getReferenceTypeName(); assertEquals("boolean or boolean : wrong type : ", "java.lang.Boolean", typeName); boolean booleanValue = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getBooleanValue(); assertEquals("boolean or boolean : wrong result : ", xBooleanValue | xBooleanValue, booleanValue); value = eval(xBoolean + orOp + yBoolean); typeName = value.getReferenceTypeName(); assertEquals("boolean or boolean : wrong type : ", "java.lang.Boolean", typeName); booleanValue = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getBooleanValue(); assertEquals("boolean or boolean : wrong result : ", xBooleanValue | yBooleanValue, booleanValue); value = eval(yBoolean + orOp + xBoolean); typeName = value.getReferenceTypeName(); assertEquals("boolean or boolean : wrong type : ", "java.lang.Boolean", typeName); booleanValue = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getBooleanValue(); assertEquals("boolean or boolean : wrong result : ", yBooleanValue | xBooleanValue, booleanValue); value = eval(yBoolean + orOp + yBoolean); typeName = value.getReferenceTypeName(); assertEquals("boolean or boolean : wrong type : ", "java.lang.Boolean", typeName); booleanValue = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getBooleanValue(); assertEquals("boolean or boolean : wrong result : ", yBooleanValue | yBooleanValue, booleanValue); } // test a bunch of groovy expressions in one go public void testGroovyExpressions1() throws Exception { init(); boolean expectingBoxed = GroovyUtils.GROOVY_LEVEL < 18; // ternary operator assertInteger("xVarBoolean ? xVarInt : xVarInt*2", xVarIntValue, expectingBoxed); // ternary operator reversed assertInteger("yVarBoolean ? xVarInt : xVarInt*2", xVarIntValue*2, true); // ternary operator with groovy truth assertInteger("xVarString ? xVarInt : xVarInt*2", xVarIntValue, expectingBoxed); // elvis operator assertInteger("xVarInt ?: xVarInt*2", xVarIntValue, expectingBoxed); // unary ++ assertInteger("xVarInt++", xVarIntValue+1, true); // unary -- // should have decremented variable back to original value assertInteger("xVarInt--", xVarIntValue, true); assertInteger("xVarInt+=2\nxVarInt", xVarIntValue+2, true); // assignment assertInteger("def x = 9\nxVarInt = x\nxVarInt", 9, true); } public void testListAndMap() throws Exception { init(); // literal list assertArrayList("[1, 2]", Arrays.asList(1, 2)); // literal map Map<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 1); map.put("b", 2); assertHashMap("[a:1, b:2]", map); // existing list assertArrayList("xList", Arrays.asList(1, 2, 3)); // existing map map = new HashMap<String, Integer>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); assertHashMap("xMap", map); // left shift assertArrayList("[1,2] << 3", Arrays.asList(1, 2, 3)); assertArrayList("xList<<4", Arrays.asList(1, 2, 3, 4)); } public void testForLoop() throws Exception { init(); assertArrayList("def newList = []\n" + "for (val in xList) {\n" + "newList << (val+1)\n" + "}\n" + "newList", Arrays.asList(2, 3, 4)); assertArrayList("def newList = []\n" + "for (val in [1,2,3]) {\n" + "newList << (val+1)\n" + "}\n" + "newList", Arrays.asList(2, 3, 4)); } public void testComparisons() throws Exception { init(); assertBoolean("xVarInt < 5", true, true); assertBoolean("xVarInt <= 5", true, true); assertBoolean("xVarInt > 5", false, true); assertBoolean("xVarInt >= 5", false, true); assertBoolean("xVarInt == 5", false, true); assertBoolean("xVarInt != 5", true, true); assertBoolean("xVarInt === 5", false, true); assertBoolean("xVarInt !== 5", true, true); // not sure what should be here... // assertBoolean("xVarInt <=> 5", true); } public void testIf() throws Exception { init(); assertInteger("if (xList) {\n4 } else {\n5 }", 4, true); assertInteger("if (null) {\n5 } else {\n4 }", 4, true); } // failing because proxy should implement Comparable public void testWhile() throws Exception { init(); assertInteger("def x = 0\n while(x < 5) {\nx++}\n x", 5, true); assertInteger("while(xVarInt < 5) {\nxVarInt++ }\n xVarInt", 5, true); } public void testFor() throws Exception { init(); assertInteger("def y = 0\nfor (x in xList) {\ny += x}\n y", 6, true); assertInteger("def y = 0\nfor (x in 2..4) {\ny += x}\n y", 9, true); assertInteger("def y = 0\nfor (x in xMap.entrySet()) {\ny += x.value }\n y", 6, true); } public void testStatic() throws Exception { init(); assertInteger("staticInt", 9, true); assertInteger("staticInt+=1", 10, true); assertInteger("staticInt", 10, true); // should have been incremented previously assertInteger("staticMethodInt()", 9, true); assertInteger("1+staticMethodInt()", 10, true); assertInteger("staticMethodWithArg(staticInt)", 10, true); } public void testImportedClassReference() throws Exception { init(); assertInteger("new Other().fieldX", 9, false); assertInteger("new Other().methodX()", 9, true); assertInteger("def var = new Other()\nvar.fieldX", 9, false); assertInteger("def var = new Other()\nvar.fieldX++\nvar.fieldX", 10, false); assertBoolean("new Other().fieldX < 100", true, true); } public void testNonImportedClassReference() throws Exception { init(); assertInteger("new pack.OtherNoImport().fieldX", 9, false); assertInteger("new pack.OtherNoImport().methodX()", 9, true); assertInteger("def var = new pack.OtherNoImport()\nvar.fieldX", 9, false); assertInteger("def var = new pack.OtherNoImport()\nvar.fieldX++\nvar.fieldX", 10, false); assertBoolean("new pack.OtherNoImport().fieldX < 100", true, true); } public void testGString() throws Exception { init(); assertInteger("def var = 9\n\"$var\".values[0]", 9, true); } public void testInnerClass() throws Exception { init(); assertClass("new EvalSimpleTests.InnerClass().val", ArrayList.class); } public void testOuterClass() throws Exception { init(); assertClass("new OuterClass().val", ArrayList.class); } public void testOtherClasses1() throws Exception { init(); assertBoolean("new OuterClass().val == new EvalSimpleTests.InnerClass().val", true, true); } public void testOtherClasses2() throws Exception { init(); assertInteger("def t = new OuterClass()\nt.val=[]\nt.val << 5\nt.val[0]", 5, true); } public void testInClosure1() throws Exception { initClosure(); assertInteger("val1", 1, true); assertInteger("val2", 2, true); assertInteger("val4", 4, true); assertInteger("val5()", 5, true); assertInteger("this.val5()", 5, true); assertInteger("delegate.val5()", 5, true); assertInteger("owner.val5()", 5, true); } public void testOtherPackage1() throws Exception { initPackage(); assertClass("outer.val", java.util.ArrayList.class); } public void testOtherPackage2() throws Exception { initPackage(); assertClass("inner.val", java.util.ArrayList.class); } private void assertArrayList(String expression, List<Integer> asList) throws DebugException { IValue value = eval(expression); String typeName = value.getReferenceTypeName(); assertEquals("wrong type : ", "java.util.ArrayList<E>", typeName); IJavaObject list = (IJavaObject) value; for (int i = 0; i < asList.size(); i++) { IJavaValue result = list.sendMessage("get", "(I)Ljava/lang/Object;", new IJavaValue[] { ((IJavaDebugTarget) list.getDebugTarget()).newValue(i) }, fSuspendeeThread, false); assertValueInteger(asList.get(i), result, true); } } private void assertHashMap(String expression, Map<String, Integer> asMap) throws DebugException { IValue value = eval(expression); String typeName = value.getReferenceTypeName(); assertTrue("wrong type : java.util.HashMap<K,V> || java.util.LinkedHashMap<K,V>", "java.util.HashMap<K,V>".equals(typeName) || "java.util.LinkedHashMap<K,V>".equals(typeName)); IJavaObject map = (IJavaObject) value; for (Map.Entry<String, Integer> entry: asMap.entrySet()) { IJavaValue result = map.sendMessage("get", "(Ljava/lang/Object;)Ljava/lang/Object;", new IJavaValue[] { ((IJavaDebugTarget) map.getDebugTarget()).newValue(entry.getKey()) }, fSuspendeeThread, false); assertValueInteger(entry.getValue(), result, true); } } protected void assertClass(String expression, Class<?> expected) throws DebugException { IValue value = eval(expression); assertValueClass(expected, value); } protected void assertValueClass(Class<?> expected, IValue value) throws DebugException { String typeName2 = value.getReferenceTypeName(); assertEquals("Wrong type", "java.lang.Class<T>", typeName2); IJavaType classType = ((IJavaClassObject) value).getInstanceType(); assertEquals("wrong result : ", expected.getCanonicalName(), classType.getName()); } protected void assertInteger(String expression, int expected, boolean isBoxed) throws DebugException { IValue value = eval(expression); assertValueInteger(expected, value, isBoxed); } protected void assertValueInteger(int expected, IValue value, boolean isBoxed) throws DebugException { String typeName2 = value.getReferenceTypeName(); assertEquals("unary operator : wrong type : ", isBoxed ? "java.lang.Integer" : "int", typeName2); int intValue2; if (isBoxed) { intValue2 = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getIntValue(); } else { intValue2 = ((IJavaPrimitiveValue) value).getIntValue(); } assertEquals("wrong result : ", expected, intValue2); } protected void assertBoolean(String expression, boolean expected, boolean isBoxed) throws DebugException { IValue value = eval(expression); assertValueBoolean(expected, value, isBoxed); } protected void assertValueBoolean(boolean expected, IValue value, boolean isBoxed) throws DebugException { String typeName2 = value.getReferenceTypeName(); assertEquals("unary operator : wrong type : ", isBoxed ? "java.lang.Boolean" : "boolean", typeName2); boolean booleanValue2; if (isBoxed) { booleanValue2 = ((IJavaPrimitiveValue) ((IJavaObject) value) .getField("value", false).getValue()).getBooleanValue(); } else { booleanValue2 = ((IJavaPrimitiveValue) value).getBooleanValue(); } assertEquals("wrong result : ", expected, booleanValue2); } }