// Verify how all the nodes behave with assignment (++, --, =)
@Test
public void incrementAllNodeTypes() throws SecurityException, NoSuchMethodException {
Spr9751 helper = new Spr9751();
StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression e = null;
// BooleanLiteral
expectFailNotAssignable(parser, ctx, "true++");
expectFailNotAssignable(parser, ctx, "--false");
expectFailSetValueNotSupported(parser, ctx, "true=false");
// IntLiteral
expectFailNotAssignable(parser, ctx, "12++");
expectFailNotAssignable(parser, ctx, "--1222");
expectFailSetValueNotSupported(parser, ctx, "12=16");
// LongLiteral
expectFailNotAssignable(parser, ctx, "1.0d++");
expectFailNotAssignable(parser, ctx, "--3.4d");
expectFailSetValueNotSupported(parser, ctx, "1.0d=3.2d");
// NullLiteral
expectFailNotAssignable(parser, ctx, "null++");
expectFailNotAssignable(parser, ctx, "--null");
expectFailSetValueNotSupported(parser, ctx, "null=null");
expectFailSetValueNotSupported(parser, ctx, "null=123");
// OpAnd
expectFailNotAssignable(parser, ctx, "(true && false)++");
expectFailNotAssignable(parser, ctx, "--(false AND true)");
expectFailSetValueNotSupported(parser, ctx, "(true && false)=(false && true)");
// OpDivide
expectFailNotAssignable(parser, ctx, "(3/4)++");
expectFailNotAssignable(parser, ctx, "--(2/5)");
expectFailSetValueNotSupported(parser, ctx, "(1/2)=(3/4)");
// OpEq
expectFailNotAssignable(parser, ctx, "(3==4)++");
expectFailNotAssignable(parser, ctx, "--(2==5)");
expectFailSetValueNotSupported(parser, ctx, "(1==2)=(3==4)");
// OpGE
expectFailNotAssignable(parser, ctx, "(3>=4)++");
expectFailNotAssignable(parser, ctx, "--(2>=5)");
expectFailSetValueNotSupported(parser, ctx, "(1>=2)=(3>=4)");
// OpGT
expectFailNotAssignable(parser, ctx, "(3>4)++");
expectFailNotAssignable(parser, ctx, "--(2>5)");
expectFailSetValueNotSupported(parser, ctx, "(1>2)=(3>4)");
// OpLE
expectFailNotAssignable(parser, ctx, "(3<=4)++");
expectFailNotAssignable(parser, ctx, "--(2<=5)");
expectFailSetValueNotSupported(parser, ctx, "(1<=2)=(3<=4)");
// OpLT
expectFailNotAssignable(parser, ctx, "(3<4)++");
expectFailNotAssignable(parser, ctx, "--(2<5)");
expectFailSetValueNotSupported(parser, ctx, "(1<2)=(3<4)");
// OpMinus
expectFailNotAssignable(parser, ctx, "(3-4)++");
expectFailNotAssignable(parser, ctx, "--(2-5)");
expectFailSetValueNotSupported(parser, ctx, "(1-2)=(3-4)");
// OpModulus
expectFailNotAssignable(parser, ctx, "(3%4)++");
expectFailNotAssignable(parser, ctx, "--(2%5)");
expectFailSetValueNotSupported(parser, ctx, "(1%2)=(3%4)");
// OpMultiply
expectFailNotAssignable(parser, ctx, "(3*4)++");
expectFailNotAssignable(parser, ctx, "--(2*5)");
expectFailSetValueNotSupported(parser, ctx, "(1*2)=(3*4)");
// OpNE
expectFailNotAssignable(parser, ctx, "(3!=4)++");
expectFailNotAssignable(parser, ctx, "--(2!=5)");
expectFailSetValueNotSupported(parser, ctx, "(1!=2)=(3!=4)");
// OpOr
expectFailNotAssignable(parser, ctx, "(true || false)++");
expectFailNotAssignable(parser, ctx, "--(false OR true)");
expectFailSetValueNotSupported(parser, ctx, "(true || false)=(false OR true)");
// OpPlus
expectFailNotAssignable(parser, ctx, "(3+4)++");
expectFailNotAssignable(parser, ctx, "--(2+5)");
expectFailSetValueNotSupported(parser, ctx, "(1+2)=(3+4)");
// RealLiteral
expectFailNotAssignable(parser, ctx, "1.0d++");
expectFailNotAssignable(parser, ctx, "--2.0d");
expectFailSetValueNotSupported(parser, ctx, "(1.0d)=(3.0d)");
expectFailNotAssignable(parser, ctx, "1.0f++");
expectFailNotAssignable(parser, ctx, "--2.0f");
expectFailSetValueNotSupported(parser, ctx, "(1.0f)=(3.0f)");
// StringLiteral
expectFailNotAssignable(parser, ctx, "'abc'++");
expectFailNotAssignable(parser, ctx, "--'def'");
expectFailSetValueNotSupported(parser, ctx, "'abc'='def'");
// Ternary
expectFailNotAssignable(parser, ctx, "(true?true:false)++");
expectFailNotAssignable(parser, ctx, "--(true?true:false)");
expectFailSetValueNotSupported(parser, ctx, "(true?true:false)=(true?true:false)");
// TypeReference
expectFailNotAssignable(parser, ctx, "T(String)++");
expectFailNotAssignable(parser, ctx, "--T(Integer)");
expectFailSetValueNotSupported(parser, ctx, "T(String)=T(Integer)");
// OperatorBetween
expectFailNotAssignable(parser, ctx, "(3 between {1,5})++");
expectFailNotAssignable(parser, ctx, "--(3 between {1,5})");
expectFailSetValueNotSupported(parser, ctx, "(3 between {1,5})=(3 between {1,5})");
// OperatorInstanceOf
expectFailNotAssignable(parser, ctx, "(type instanceof T(String))++");
expectFailNotAssignable(parser, ctx, "--(type instanceof T(String))");
expectFailSetValueNotSupported(parser, ctx, "(type instanceof T(String))=(type instanceof T(String))");
// Elvis
expectFailNotAssignable(parser, ctx, "(true?:false)++");
expectFailNotAssignable(parser, ctx, "--(true?:false)");
expectFailSetValueNotSupported(parser, ctx, "(true?:false)=(true?:false)");
// OpInc
expectFailNotAssignable(parser, ctx, "(iii++)++");
expectFailNotAssignable(parser, ctx, "--(++iii)");
expectFailSetValueNotSupported(parser, ctx, "(iii++)=(++iii)");
// OpDec
expectFailNotAssignable(parser, ctx, "(iii--)++");
expectFailNotAssignable(parser, ctx, "--(--iii)");
expectFailSetValueNotSupported(parser, ctx, "(iii--)=(--iii)");
// OperatorNot
expectFailNotAssignable(parser, ctx, "(!true)++");
expectFailNotAssignable(parser, ctx, "--(!false)");
expectFailSetValueNotSupported(parser, ctx, "(!true)=(!false)");
// OperatorPower
expectFailNotAssignable(parser, ctx, "(iii^2)++");
expectFailNotAssignable(parser, ctx, "--(iii^2)");
expectFailSetValueNotSupported(parser, ctx, "(iii^2)=(iii^3)");
// Assign
// iii=42
e = parser.parseExpression("iii=iii++");
assertEquals(42,helper.iii);
int return_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(42,helper.iii);
assertEquals(42,return_iii);
// Identifier
e = parser.parseExpression("iii++");
assertEquals(42,helper.iii);
return_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(42,return_iii);
assertEquals(43,helper.iii);
e = parser.parseExpression("--iii");
assertEquals(43,helper.iii);
return_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(42,return_iii);
assertEquals(42,helper.iii);
e = parser.parseExpression("iii=99");
assertEquals(42,helper.iii);
return_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(99,return_iii);
assertEquals(99,helper.iii);
// CompoundExpression
// foo.iii == 99
e = parser.parseExpression("foo.iii++");
assertEquals(99,helper.foo.iii);
int return_foo_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(99,return_foo_iii);
assertEquals(100,helper.foo.iii);
e = parser.parseExpression("--foo.iii");
assertEquals(100,helper.foo.iii);
return_foo_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(99,return_foo_iii);
assertEquals(99,helper.foo.iii);
e = parser.parseExpression("foo.iii=999");
assertEquals(99,helper.foo.iii);
return_foo_iii = e.getValue(ctx,Integer.TYPE);
assertEquals(999,return_foo_iii);
assertEquals(999,helper.foo.iii);
// ConstructorReference
expectFailNotAssignable(parser, ctx, "(new String('abc'))++");
expectFailNotAssignable(parser, ctx, "--(new String('abc'))");
expectFailSetValueNotSupported(parser, ctx, "(new String('abc'))=(new String('abc'))");
// MethodReference
expectFailNotIncrementable(parser, ctx, "m()++");
expectFailNotDecrementable(parser, ctx, "--m()");
expectFailSetValueNotSupported(parser, ctx, "m()=m()");
// OperatorMatches
expectFailNotAssignable(parser, ctx, "('abc' matches '^a..')++");
expectFailNotAssignable(parser, ctx, "--('abc' matches '^a..')");
expectFailSetValueNotSupported(parser, ctx, "('abc' matches '^a..')=('abc' matches '^a..')");
// Selection
ctx.registerFunction("isEven", Spr9751.class.getDeclaredMethod("isEven", Integer.TYPE));
expectFailNotIncrementable(parser, ctx, "({1,2,3}.?[#isEven(#this)])++");
expectFailNotDecrementable(parser, ctx, "--({1,2,3}.?[#isEven(#this)])");
expectFailNotAssignable(parser, ctx, "({1,2,3}.?[#isEven(#this)])=({1,2,3}.?[#isEven(#this)])");
// slightly diff here because return value isn't a list, it is a single entity
expectFailNotAssignable(parser, ctx, "({1,2,3}.^[#isEven(#this)])++");
expectFailNotAssignable(parser, ctx, "--({1,2,3}.^[#isEven(#this)])");
expectFailNotAssignable(parser, ctx, "({1,2,3}.^[#isEven(#this)])=({1,2,3}.^[#isEven(#this)])");
expectFailNotAssignable(parser, ctx, "({1,2,3}.$[#isEven(#this)])++");
expectFailNotAssignable(parser, ctx, "--({1,2,3}.$[#isEven(#this)])");
expectFailNotAssignable(parser, ctx, "({1,2,3}.$[#isEven(#this)])=({1,2,3}.$[#isEven(#this)])");
// FunctionReference
expectFailNotAssignable(parser, ctx, "#isEven(3)++");
expectFailNotAssignable(parser, ctx, "--#isEven(4)");
expectFailSetValueNotSupported(parser, ctx, "#isEven(3)=#isEven(5)");
// VariableReference
ctx.setVariable("wibble", "hello world");
expectFailNotIncrementable(parser, ctx, "#wibble++");
expectFailNotDecrementable(parser, ctx, "--#wibble");
e = parser.parseExpression("#wibble=#wibble+#wibble");
String s = e.getValue(ctx,String.class);
assertEquals("hello worldhello world",s);
assertEquals("hello worldhello world",ctx.lookupVariable("wibble"));
ctx.setVariable("wobble", 3);
e = parser.parseExpression("#wobble++");
assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());
int r = e.getValue(ctx,Integer.TYPE);
assertEquals(3,r);
assertEquals(4,((Integer)ctx.lookupVariable("wobble")).intValue());
e = parser.parseExpression("--#wobble");
assertEquals(4,((Integer)ctx.lookupVariable("wobble")).intValue());
r = e.getValue(ctx,Integer.TYPE);
assertEquals(3,r);
assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());
e = parser.parseExpression("#wobble=34");
assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());
r = e.getValue(ctx,Integer.TYPE);
assertEquals(34,r);
assertEquals(34,((Integer)ctx.lookupVariable("wobble")).intValue());
// Projection
expectFailNotIncrementable(parser, ctx, "({1,2,3}.![#isEven(#this)])++"); // projection would be {false,true,false}
expectFailNotDecrementable(parser, ctx, "--({1,2,3}.![#isEven(#this)])"); // projection would be {false,true,false}
expectFailNotAssignable(parser, ctx, "({1,2,3}.![#isEven(#this)])=({1,2,3}.![#isEven(#this)])");
// InlineList
expectFailNotAssignable(parser, ctx, "({1,2,3})++");
expectFailNotAssignable(parser, ctx, "--({1,2,3})");
expectFailSetValueNotSupported(parser, ctx, "({1,2,3})=({1,2,3})");
// InlineMap
expectFailNotAssignable(parser, ctx, "({'a':1,'b':2,'c':3})++");
expectFailNotAssignable(parser, ctx, "--({'a':1,'b':2,'c':3})");
expectFailSetValueNotSupported(parser, ctx, "({'a':1,'b':2,'c':3})=({'a':1,'b':2,'c':3})");
// BeanReference
ctx.setBeanResolver(new MyBeanResolver());
expectFailNotAssignable(parser, ctx, "@foo++");
expectFailNotAssignable(parser, ctx, "--@foo");
expectFailSetValueNotSupported(parser, ctx, "@foo=@bar");
// PropertyOrFieldReference
helper.iii = 42;
e = parser.parseExpression("iii++");
assertEquals(42,helper.iii);
r = e.getValue(ctx,Integer.TYPE);
assertEquals(42,r);
assertEquals(43,helper.iii);
e = parser.parseExpression("--iii");
assertEquals(43,helper.iii);
r = e.getValue(ctx,Integer.TYPE);
assertEquals(42,r);
assertEquals(42,helper.iii);
e = parser.parseExpression("iii=100");
assertEquals(42,helper.iii);
r = e.getValue(ctx,Integer.TYPE);
assertEquals(100,r);
assertEquals(100,helper.iii);