提交 59a44275 编写于 作者: A Andy Clement

Final commit before the great 'stripdown'. Used clover to determine coverage...

Final commit before the great 'stripdown'.  Used clover to determine coverage and added tests as necessary.
上级 23db8b58
......@@ -7,6 +7,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.4.0/com.springsource.org.junit-4.4.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.junit/3.8.2/com.springsource.junit-sources-3.8.2.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.antlr/com.springsource.org.antlr/3.0.1/com.springsource.org.antlr-3.0.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.antlr/com.springsource.org.antlr/3.0.1/com.springsource.org.antlr-3.0.1.jar" sourcepath="/IVY_CACHE/org.antlr/com.springsource.org.antlr/3.0.1/com.springsource.org.antlr-sources-3.0.1.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
......@@ -6,6 +6,8 @@ High Importance
in a different context then the stored executor may be incorrect. It may harmless 'fail' which would cause us to retrieve a new one, but
can it do anything malicious? In which case we either need to forget them when the context changes or store them elsewhere. Should caching be
something that can be switched on/off by the context? (shouldCacheExecutors() on the interface?)
- Expression serialization needs supporting
- expression basic interface and common package. Should LiteralExpression be settable? should getExpressionString return quoted value?
Low Importance
......@@ -13,6 +15,7 @@ Low Importance
would have taken? At the moment ternary expressions are just considered NOT writable.
- Enhance type locator interface with direct support for register/unregister imports and ability to set class loader?
- Should some of the common errors (like SpelMessages.TYPE_NOT_FOUND) be promoted to top level exceptions?
- Expression comparison - is it necessary?
Syntax
......
......@@ -24,14 +24,15 @@ public class LiteralExpression implements Expression {
}
public String getExpressionString() {
return new StringBuilder().append("'").append(literalValue).append("'").toString();
return literalValue;
// return new StringBuilder().append("'").append(literalValue).append("'").toString();
}
public Object getValue() throws EvaluationException {
public String getValue() throws EvaluationException {
return literalValue;
}
public Object getValue(EvaluationContext context) throws EvaluationException {
public String getValue(EvaluationContext context) throws EvaluationException {
return literalValue;
}
......
......@@ -25,6 +25,7 @@ import org.springframework.expression.Operation;
import org.springframework.expression.OperatorOverloader;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeUtils;
import org.springframework.expression.spel.internal.VariableScope;
......@@ -42,21 +43,21 @@ public class ExpressionState {
private EvaluationContext relatedContext;
private final Stack<VariableScope> environment = new Stack<VariableScope>();
private final Stack<VariableScope> variableScopes = new Stack<VariableScope>();
private final Stack<Object> contextObjects = new Stack<Object>();
public ExpressionState(EvaluationContext context) {
this.relatedContext = context;
createEnvironment();
relatedContext = context;
createVariableScope();
}
public ExpressionState() {
createEnvironment();
createVariableScope();
}
private void createEnvironment() {
environment.add(new VariableScope()); // create an empty top level VariableScope
private void createVariableScope() {
variableScopes.add(new VariableScope()); // create an empty top level VariableScope
}
/**
......@@ -97,37 +98,42 @@ public class ExpressionState {
return getTypeUtilities().getTypeLocator().findType(type);
}
// TODO all these methods that grab the type converter will fail badly if there isn't one...
public boolean toBoolean(Object value) throws EvaluationException {
// TODO cache TypeConverter when it is set/changed?
return ((Boolean) getTypeUtilities().getTypeConverter().convertValue(value, Boolean.TYPE)).booleanValue();
return ((Boolean) getTypeConverter().convertValue(value, Boolean.TYPE)).booleanValue();
}
public char toCharacter(Object value) throws EvaluationException {
return ((Character) getTypeUtilities().getTypeConverter().convertValue(value, Character.TYPE)).charValue();
return ((Character) getTypeConverter().convertValue(value, Character.TYPE)).charValue();
}
public short toShort(Object value) throws EvaluationException {
return ((Short) getTypeUtilities().getTypeConverter().convertValue(value, Short.TYPE)).shortValue();
return ((Short) getTypeConverter().convertValue(value, Short.TYPE)).shortValue();
}
public int toInteger(Object value) throws EvaluationException {
return ((Integer) getTypeUtilities().getTypeConverter().convertValue(value, Integer.TYPE)).intValue();
return ((Integer) getTypeConverter().convertValue(value, Integer.TYPE)).intValue();
}
public double toDouble(Object value) throws EvaluationException {
return ((Double) getTypeUtilities().getTypeConverter().convertValue(value, Double.TYPE)).doubleValue();
return ((Double) getTypeConverter().convertValue(value, Double.TYPE)).doubleValue();
}
public float toFloat(Object value) throws EvaluationException {
return ((Float) getTypeUtilities().getTypeConverter().convertValue(value, Float.TYPE)).floatValue();
return ((Float) getTypeConverter().convertValue(value, Float.TYPE)).floatValue();
}
public long toLong(Object value) throws EvaluationException {
return ((Long) getTypeUtilities().getTypeConverter().convertValue(value, Long.TYPE)).longValue();
return ((Long) getTypeConverter().convertValue(value, Long.TYPE)).longValue();
}
public byte toByte(Object value) throws EvaluationException {
return ((Byte) getTypeUtilities().getTypeConverter().convertValue(value, Byte.TYPE)).byteValue();
return ((Byte) getTypeConverter().convertValue(value, Byte.TYPE)).byteValue();
}
public TypeConverter getTypeConverter() {
// TODO cache TypeConverter when it is set/changed?
return getTypeUtilities().getTypeConverter();
}
public void setVariable(String name, Object value) {
......@@ -142,26 +148,26 @@ public class ExpressionState {
* A new scope is entered when a function is invoked
*/
public void enterScope(Map<String, Object> argMap) {
environment.push(new VariableScope(argMap));
variableScopes.push(new VariableScope(argMap));
}
public void enterScope(String name, Object value) {
environment.push(new VariableScope(name, value));
variableScopes.push(new VariableScope(name, value));
}
public void exitScope() {
environment.pop();
variableScopes.pop();
}
public void setLocalVariable(String name, Object value) {
environment.peek().setVariable(name, value);
variableScopes.peek().setVariable(name, value);
}
public Object lookupLocalVariable(String name) {
int scopeNumber = environment.size() - 1;
int scopeNumber = variableScopes.size() - 1;
for (int i = scopeNumber; i >= 0; i--) {
if (environment.get(i).definesVariable(name)) {
return environment.get(i).lookupVariable(name);
if (variableScopes.get(i).definesVariable(name)) {
return variableScopes.get(i).lookupVariable(name);
}
}
return null;
......
......@@ -45,13 +45,10 @@ public class SpelUtilities {
private static void printAST(PrintStream out, SpelNode t, String indent) {
if (t != null) {
StringBuffer sb = new StringBuffer();
String s = null;
if (t.getType() == -1)
s = "EOF";
else {
s = t.getClass().getSimpleName();
}
sb.append(indent + s + (t.getChildCount() < 2 ? "" : " #" + t.getChildCount()));
String s = (t.getType() == -1 ? "EOF" : t.getClass().getSimpleName());
sb.append(indent).append(s);
sb.append(" value=").append(t.getText());
sb.append(t.getChildCount() < 2 ? "" : " children=#" + t.getChildCount());
out.println(sb.toString());
for (int i = 0; i < t.getChildCount(); i++) {
printAST(out, t.getChild(i), indent + " ");
......
......@@ -27,11 +27,13 @@ import org.springframework.expression.spel.SpelMessages;
* The AverageProcessor operates upon an input collection and computes the average value of the elements within it. It
* will currently only operate upon Numbers and its return value type is an Integer if the input values were integers,
* otherwise it is a double.
*
* @author Andy Clement
*/
public class AverageProcessor implements DataProcessor {
public Object process(Collection<?> input, Object[] arguments, ExpressionState state) throws SpelException {
// TypeUtilities typeUtilities = state.getTypeUtilities();
// TODO could support average of other types if delegated to OperatorOverloader for addition and division
boolean allIntegerObjects = true;
int total = 0;
int numberOfElements = 0;
......
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.common;
import junit.framework.TestCase;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.SpelExpressionParser;
import org.springframework.expression.spel.standard.StandardEvaluationContext;
/**
* Test LiteralExpression
*
* @author Andy Clement
*/
public class CompositeStringExpressionTests extends TestCase {
public void testGetValue() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
Expression ex = parser.parseExpression("hello ${'world'}", DefaultTemplateParserContext.INSTANCE);
checkString("hello world", ex.getValue());
checkString("hello world", ex.getValue(String.class));
EvaluationContext ctx = new StandardEvaluationContext();
checkString("hello world", ex.getValue(ctx));
checkString("hello world", ex.getValue(ctx, String.class));
assertEquals("hello ${'world'}", ex.getExpressionString());
assertFalse(ex.isWritable(new StandardEvaluationContext()));
}
// public void testSetValue() {
// try {
// LiteralExpression lEx = new LiteralExpression("somevalue");
// lEx.setValue(new StandardEvaluationContext(), "flibble");
// fail("Should have got an exception that the value cannot be set");
// } catch (EvaluationException ee) {
// // success, not allowed - whilst here, check the expression value in the exception
// assertEquals(ee.getExpressionString(), "somevalue");
// }
// }
//
// public void testGetValueType() throws Exception {
// LiteralExpression lEx = new LiteralExpression("somevalue");
// assertEquals(String.class, lEx.getValueType());
// assertEquals(String.class, lEx.getValueType(new StandardEvaluationContext()));
// }
private void checkString(String expectedString, Object value) {
if (!(value instanceof String)) {
fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")");
}
if (!((String) value).equals(expectedString)) {
fail("Did not get expected result. Should have been '" + expectedString + "' but was '" + value + "'");
}
}
}
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.common;
import junit.framework.TestCase;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.standard.StandardEvaluationContext;
/**
* Test LiteralExpression
*
* @author Andy Clement
*/
public class LiteralExpressionTests extends TestCase {
public void testGetValue() throws Exception {
LiteralExpression lEx = new LiteralExpression("somevalue");
checkString("somevalue", lEx.getValue());
checkString("somevalue", lEx.getValue(String.class));
EvaluationContext ctx = new StandardEvaluationContext();
checkString("somevalue", lEx.getValue(ctx));
checkString("somevalue", lEx.getValue(ctx, String.class));
assertEquals("somevalue", lEx.getExpressionString());
assertFalse(lEx.isWritable(new StandardEvaluationContext()));
}
public void testSetValue() {
try {
LiteralExpression lEx = new LiteralExpression("somevalue");
lEx.setValue(new StandardEvaluationContext(), "flibble");
fail("Should have got an exception that the value cannot be set");
} catch (EvaluationException ee) {
// success, not allowed - whilst here, check the expression value in the exception
assertEquals(ee.getExpressionString(), "somevalue");
}
}
public void testGetValueType() throws Exception {
LiteralExpression lEx = new LiteralExpression("somevalue");
assertEquals(String.class, lEx.getValueType());
assertEquals(String.class, lEx.getValueType(new StandardEvaluationContext()));
}
private void checkString(String expectedString, Object value) {
if (!(value instanceof String)) {
fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")");
}
if (!((String) value).equals(expectedString)) {
fail("Did not get expected result. Should have been '" + expectedString + "' but was '" + value + "'");
}
}
}
......@@ -18,6 +18,9 @@ package org.springframework.expression.spel;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.springframework.expression.common.CompositeStringExpressionTests;
import org.springframework.expression.common.LiteralExpressionTests;
/**
* Pulls together all the tests for Spring EL into a single suite.
*
......@@ -42,9 +45,12 @@ public class AllTests {
suite.addTestSuite(TypeReferencing.class);
suite.addTestSuite(PerformanceTests.class);
suite.addTestSuite(DefaultComparatorUnitTests.class);
suite.addTestSuite(TemplateExpressionParsing.class);
suite.addTestSuite(TemplateExpressionParsingTests.class);
suite.addTestSuite(ExpressionLanguageScenarioTests.class);
suite.addTestSuite(ScenariosForSpringSecurity.class);
suite.addTestSuite(SpelUtilitiesTests.class);
suite.addTestSuite(LiteralExpressionTests.class);
suite.addTestSuite(CompositeStringExpressionTests.class);
// $JUnit-END$
return suite;
}
......
......@@ -55,6 +55,12 @@ public class BooleanExpressionTests extends ExpressionTestCase {
evaluate("true and false or false", Boolean.FALSE, Boolean.class);
}
public void testWritability() {
evaluate("true and true", Boolean.TRUE, Boolean.class, false);
evaluate("true or true", Boolean.TRUE, Boolean.class, false);
evaluate("!false", Boolean.TRUE, Boolean.class, false);
}
public void testBooleanErrors01() {
evaluateAndCheckError("1.0 or false", SpelMessages.TYPE_CONVERSION_ERROR, 0);
evaluateAndCheckError("false or 39.4", SpelMessages.TYPE_CONVERSION_ERROR, 9);
......
......@@ -47,6 +47,10 @@ public class ParsingTests extends TestCase {
parseCheck("true");
}
public void testLiteralBoolean03() {
parseCheck("!true");
}
public void testLiteralInteger01() {
parseCheck("1");
}
......
/*
* Copyright 2004-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import junit.framework.TestCase;
/**
* Tests the SpelUtilities
*
* @author Andy Clement
*/
public class SpelUtilitiesTests extends TestCase {
public void testPrintAbstractSyntaxTree01() throws Exception {
SpelExpression sEx = new SpelExpressionParser().parseExpression("1 + 2");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SpelUtilities.printAbstractSyntaxTree(new PrintStream(baos), sEx);
String theAst = baos.toString();
System.out.println(theAst);
String[] expectedLines = new String[] { "===> Expression '1 + 2' - AST start",
"OperatorPlus value=+ children=#2", " CompoundExpression value=EXPRESSION",
" IntLiteral value=1", " CompoundExpression value=EXPRESSION", " IntLiteral value=2",
"===> Expression '1 + 2' - AST end" };
checkExpected(theAst, expectedLines);
}
private static void checkExpected(String theData, String[] expectedLines) {
String[] theDataSplit = theData.split("\n");
if (theDataSplit.length != expectedLines.length) {
System.out.println("TheData:");
System.out.println(theData);
System.out.println("ExpectedData:\n" + expectedLines);
fail("Data incorrect, expected " + expectedLines.length + " but got " + theDataSplit.length + " lines");
}
for (int i = 0; i < expectedLines.length; i++) {
assertEquals("Failure in comparison at line " + i, expectedLines[i], theDataSplit[i]);
}
}
}
......@@ -23,7 +23,7 @@ import org.springframework.expression.common.DefaultTemplateParserContext;
*
* @author Andy Clement
*/
public class TemplateExpressionParsing extends ExpressionTestCase {
public class TemplateExpressionParsingTests extends ExpressionTestCase {
public void testParsingSimpleTemplateExpression01() throws Exception {
SpelExpressionParser parser = new SpelExpressionParser();
......
......@@ -61,10 +61,11 @@ public class TestScenarioCreator {
new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE }));
testContext.registerFunction("reverseString", TestScenarioCreator.class.getDeclaredMethod("reverseString",
new Class[] { String.class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge", TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge",
new Class[] { String[].class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2", TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2",
new Class[] { Integer.TYPE,String[].class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge", TestScenarioCreator.class
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge", new Class[] { String[].class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2", TestScenarioCreator.class
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2", new Class[] { Integer.TYPE,
String[].class }));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
......@@ -86,8 +87,8 @@ public class TestScenarioCreator {
*/
private static void createTestClassloader(StandardEvaluationContext testContext) {
try {
ClassLoader cl = new URLClassLoader(new URL[] { new File("target/test-classes/testcode.jar").toURI().toURL() },
Thread.currentThread().getContextClassLoader());
ClassLoader cl = new URLClassLoader(new URL[] { new File("target/test-classes/testcode.jar").toURI()
.toURL() }, Thread.currentThread().getContextClassLoader());
testContext.setClassLoader(cl);
} catch (MalformedURLException mue) {
mue.printStackTrace();
......@@ -97,7 +98,7 @@ public class TestScenarioCreator {
/**
* Create the root context object, an Inventor instance. Non-qualified property and method references will be
* resolved against this context object.
*
*
* @param testContext the evaluation context in which to set the root object
*/
private static void setupRootContextObject(StandardEvaluationContext testContext) {
......@@ -113,11 +114,10 @@ public class TestScenarioCreator {
/**
* Create a context configuration that tests can reference into using the
* @() language construct.
* at(context:objectName) will index a particular object within a particular context. The 'root' context will be used
* for references where no context is specified, eg.
* @() language construct. at(context:objectName) will index a particular object within a particular context. The
* 'root' context will be used for references where no context is specified, eg.
* @(orange).
*
*
* @param testContext the evaluation context in which to register the new references
*/
private static void populateContextMap(StandardEvaluationContext testContext) {
......@@ -205,21 +205,21 @@ public class TestScenarioCreator {
return backwards.toString();
}
public static String varargsFunctionReverseStringsAndMerge(String...strings) {
public static String varargsFunctionReverseStringsAndMerge(String... strings) {
StringBuilder sb = new StringBuilder();
if (strings!=null) {
for (int i=strings.length-1;i>=0;i--) {
if (strings != null) {
for (int i = strings.length - 1; i >= 0; i--) {
sb.append(strings[i]);
}
}
return sb.toString();
}
public static String varargsFunctionReverseStringsAndMerge2(int j, String...strings) {
public static String varargsFunctionReverseStringsAndMerge2(int j, String... strings) {
StringBuilder sb = new StringBuilder();
sb.append(j);
if (strings!=null) {
for (int i=strings.length-1;i>=0;i--) {
if (strings != null) {
for (int i = strings.length - 1; i >= 0; i--) {
sb.append(strings[i]);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册