Improving test coverage, more language consistency

This commit is contained in:
Andy Clement
2009-04-06 19:04:04 +00:00
parent 55bdd07580
commit a9f30fe377
7 changed files with 177 additions and 106 deletions

View File

@@ -42,19 +42,14 @@ public class OperatorGreaterThanOrEqual extends Operator {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return BooleanTypedValue.forValue(op1.doubleValue() >= op2.doubleValue());
}
else if (op1 instanceof Float || op2 instanceof Float) {
return BooleanTypedValue.forValue(op1.floatValue() >= op2.floatValue());
}
else if (op1 instanceof Long || op2 instanceof Long) {
return BooleanTypedValue.forValue( op1.longValue() >= op2.longValue());
}
else {
return BooleanTypedValue.forValue(op1.intValue() >= op2.intValue());
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() >= rightNumber.doubleValue());
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue( leftNumber.longValue() >= rightNumber.longValue());
} else {
return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
}
}
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) >= 0);

View File

@@ -21,11 +21,18 @@ import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelException;
import org.springframework.expression.spel.SpelMessages;
/**
* Implements the minus operator. If there is only one operand it is a unary minus.
* The minus operator supports:
* <ul>
* <li>subtraction of doubles (floats are represented as doubles)
* <li>subtraction of longs
* <li>subtraction of integers
* <li>subtraction of an int from a string of one character (effectively decreasing that character), so 'd'-3='a'
* </ul>
* It can be used as a unary operator for numbers (double/long/int). The standard promotions are performed
* when the operand types vary (double-int=double).
* For other options it defers to the registered overloader.
*
* @author Andy Clement
* @since 3.0
@@ -36,43 +43,24 @@ public class OperatorMinus extends Operator {
super(payload);
}
@Override
public String getOperatorName() {
return "-";
}
@Override
public String toStringAST() {
if (getRightOperand() == null) { // unary minus
return new StringBuilder().append("-").append(getLeftOperand()).toString();
}
return super.toStringAST();
}
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
SpelNodeImpl leftOp = getLeftOperand();
SpelNodeImpl rightOp = getRightOperand();
if (rightOp == null) {// If only one operand, then this is unary minus
Object left = leftOp.getValueInternal(state).getValue();
if (left instanceof Number) {
Number n = (Number) left;
if (left instanceof Double) {
Object operand = leftOp.getValueInternal(state).getValue();
if (operand instanceof Number) {
Number n = (Number) operand;
if (operand instanceof Double) {
return new TypedValue(0 - n.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
}
else if (left instanceof Float) {
return new TypedValue(0 - n.floatValue(),FLOAT_TYPE_DESCRIPTOR);
}
else if (left instanceof Long) {
} else if (operand instanceof Long) {
return new TypedValue(0 - n.longValue(),LONG_TYPE_DESCRIPTOR);
}
else {
} else {
return new TypedValue(0 - n.intValue(),INTEGER_TYPE_DESCRIPTOR);
}
}
throw new SpelException(SpelMessages.CANNOT_NEGATE_TYPE, left.getClass().getName());
}
else {
return state.operate(Operation.SUBTRACT, operand, null);
} else {
Object left = leftOp.getValueInternal(state).getValue();
Object right = rightOp.getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) {
@@ -80,19 +68,32 @@ public class OperatorMinus extends Operator {
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() - op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() - op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Long || op2 instanceof Long) {
} else if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() - op2.longValue(),LONG_TYPE_DESCRIPTOR);
}
else {
} else {
return new TypedValue(op1.intValue() - op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
}
} else if (left instanceof String && right instanceof Integer && ((String)left).length()==1) {
String theString = (String) left;
Integer theInteger = (Integer) right;
// implements character - int (ie. b - 1 = a)
return new TypedValue(Character.toString((char) (theString.charAt(0) - theInteger)),STRING_TYPE_DESCRIPTOR);
}
return state.operate(Operation.SUBTRACT, left, right);
}
}
@Override
public String getOperatorName() {
return "-";
}
@Override
public String toStringAST() {
if (getRightOperand() == null) { // unary minus
return new StringBuilder().append("-").append(getLeftOperand().toStringAST()).toString();
}
return super.toStringAST();
}
}

View File

@@ -48,14 +48,9 @@ public class OperatorModulus extends Operator {
Number op2 = (Number) operandTwo;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() % op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() % op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Long || op2 instanceof Long) {
} else if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() % op2.longValue(),LONG_TYPE_DESCRIPTOR);
}
else {
} else {
return new TypedValue(op1.intValue() % op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
}
}

View File

@@ -32,6 +32,8 @@ import org.springframework.expression.spel.ExpressionState;
* Otherwise, if either operand is of type long, the other is converted to long.<br>
* Otherwise, both operands are converted to type int.
*
* <p>
*
* @author Andy Clement
* @since 3.0
*/
@@ -55,28 +57,22 @@ public class OperatorMultiply extends Operator {
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
if (operandOne instanceof Number && operandTwo instanceof Number) {
Number op1 = (Number) operandOne;
Number op2 = (Number) operandTwo;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() * op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
Number leftNumber = (Number) operandOne;
Number rightNumber = (Number) operandTwo;
if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(leftNumber.doubleValue() * rightNumber.doubleValue(), DOUBLE_TYPE_DESCRIPTOR);
} else if (leftNumber instanceof Long || rightNumber instanceof Long) {
return new TypedValue(leftNumber.longValue() * rightNumber.longValue(), LONG_TYPE_DESCRIPTOR);
} else {
return new TypedValue(leftNumber.intValue() * rightNumber.intValue(), INTEGER_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() * op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() * op2.longValue(),LONG_TYPE_DESCRIPTOR);
}
else {
return new TypedValue(op1.intValue() * op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
}
}
else if (operandOne instanceof String && operandTwo instanceof Integer) {
} else if (operandOne instanceof String && operandTwo instanceof Integer) {
int repeats = (Integer) operandTwo;
StringBuilder result = new StringBuilder();
for (int i = 0; i < repeats; i++) {
result.append(operandOne);
}
return new TypedValue(result.toString(),STRING_TYPE_DESCRIPTOR);
return new TypedValue(result.toString(), STRING_TYPE_DESCRIPTOR);
}
return state.operate(Operation.MULTIPLY, operandOne, operandTwo);
}

View File

@@ -23,6 +23,17 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState;
/**
* The plus operator will:
* <ul>
* <li>add doubles (floats are represented as doubles)
* <li>add longs
* <li>add integers
* <li>add a string of one character and a number (effectively increasing that character), so 'a'+3='d'
* </ul>
* It can be used as a unary operator for numbers (double/long/int). The standard promotions are performed
* when the operand types vary (double+int=double).
* For other options it defers to the registered overloader.
*
* @author Andy Clement
* @since 3.0
*/
@@ -39,7 +50,13 @@ public class OperatorPlus extends Operator {
if (rightOp == null) { // If only one operand, then this is unary plus
Object operandOne = leftOp.getValueInternal(state).getValue();
if (operandOne instanceof Number) {
return new TypedValue(((Number) operandOne).intValue(),INTEGER_TYPE_DESCRIPTOR);
if (operandOne instanceof Double) {
return new TypedValue(((Double) operandOne).doubleValue(), DOUBLE_TYPE_DESCRIPTOR);
} else if (operandOne instanceof Long) {
return new TypedValue(((Long) operandOne).longValue(), LONG_TYPE_DESCRIPTOR);
} else {
return new TypedValue(((Integer) operandOne).intValue(), INTEGER_TYPE_DESCRIPTOR);
}
}
return state.operate(Operation.ADD, operandOne, null);
}
@@ -51,28 +68,23 @@ public class OperatorPlus extends Operator {
Number op2 = (Number) operandTwo;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() + op2.doubleValue(),DOUBLE_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() + op2.floatValue(),FLOAT_TYPE_DESCRIPTOR);
}
else if (op1 instanceof Long || op2 instanceof Long) {
} else if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() + op2.longValue(),LONG_TYPE_DESCRIPTOR);
}
else { // TODO what about overflow?
} else { // TODO what about overflow?
return new TypedValue(op1.intValue() + op2.intValue(),INTEGER_TYPE_DESCRIPTOR);
}
}
else if (operandOne instanceof String && operandTwo instanceof String) {
} else if (operandOne instanceof String && operandTwo instanceof String) {
return new TypedValue(new StringBuilder((String) operandOne).append((String) operandTwo).toString(),STRING_TYPE_DESCRIPTOR);
}
else if (operandOne instanceof String && operandTwo instanceof Integer) {
String l = (String) operandOne;
Integer i = (Integer) operandTwo;
} else if (operandOne instanceof String && operandTwo instanceof Integer && ((String)operandOne).length()==1) {
String theString = (String) operandOne;
Integer theInteger = (Integer) operandTwo;
// implements character + int (ie. a + 1 = b)
if (l.length() == 1) {
return new TypedValue(Character.toString((char) (l.charAt(0) + i)),STRING_TYPE_DESCRIPTOR);
}
return new TypedValue(new StringBuilder(l).append(i).toString(),STRING_TYPE_DESCRIPTOR);
return new TypedValue(Character.toString((char) (theString.charAt(0) + theInteger)),STRING_TYPE_DESCRIPTOR);
} else if (operandOne instanceof Integer && ((operandTwo instanceof String) && ((String)operandTwo).length()==1)) {
String theString = (String) operandTwo;
Integer theInteger = (Integer) operandOne;
// implements character + int (ie. 1 + a = b)
return new TypedValue(Character.toString((char) (theString.charAt(0) + theInteger)),STRING_TYPE_DESCRIPTOR);
}
return state.operate(Operation.ADD, operandOne, operandTwo);
}
@@ -86,7 +98,7 @@ public class OperatorPlus extends Operator {
@Override
public String toStringAST() {
if (getRightOperand() == null) { // unary plus
return new StringBuilder().append("+").append(getLeftOperand()).toString();
return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString();
}
return super.toStringAST();
}