Skip to content

Commit

Permalink
Polish ExpressionState[Tests]
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrannen committed Sep 30, 2023
1 parent 8fa428f commit dbf6f7d
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public ExpressionState(EvaluationContext context, TypedValue rootObject) {

public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) {
Assert.notNull(context, "EvaluationContext must not be null");
Assert.notNull(context, "'rootObject' must not be null");
Assert.notNull(configuration, "SpelParserConfiguration must not be null");
this.relatedContext = context;
this.rootObject = rootObject;
Expand Down Expand Up @@ -203,7 +204,7 @@ public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor
/*
* A new scope is entered when a function is invoked.
*/
public void enterScope(Map<String, Object> argMap) {
public void enterScope(@Nullable Map<String, Object> argMap) {
initVariableScopes().push(new VariableScope(argMap));
initScopeRootObjects().push(getActiveContextObject());
}
Expand Down Expand Up @@ -300,9 +301,10 @@ public VariableScope(@Nullable Map<String, Object> arguments) {
}

public VariableScope(String name, Object value) {
this.vars.put(name,value);
this.vars.put(name, value);
}

@Nullable
public Object lookupVariable(String name) {
return this.vars.get(name);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand All @@ -16,7 +16,6 @@

package org.springframework.expression.spel;

import java.util.HashMap;
import java.util.Map;

import org.junit.jupiter.api.Test;
Expand All @@ -34,27 +33,31 @@
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;

/**
* Tests for the expression state object - some features are not yet exploited in the language (eg nested scopes)
* Tests for {@link ExpressionState}.
*
* <p>Some features are not yet exploited in the language, such as nested scopes
* or local variables scoped to the currently evaluated expression.
*
* <p>Local variables are in variable scopes which come and go during evaluation.
* Normal/global variables are accessible through the {@link EvaluationContext}.
*
* @author Andy Clement
* @author Juergen Hoeller
*/
public class ExpressionStateTests extends AbstractExpressionTests {
class ExpressionStateTests extends AbstractExpressionTests {

private ExpressionState state = new ExpressionState(TestScenarioCreator.getTestEvaluationContext());


@Test
public void testConstruction() {
void construction() {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
ExpressionState state = new ExpressionState(context);
assertThat(state.getEvaluationContext()).isEqualTo(context);
}

// Local variables are in variable scopes which come and go during evaluation. Normal variables are
// accessible through the evaluation context

@Test
public void testLocalVariables() {
ExpressionState state = getState();

void localVariables() {
Object value = state.lookupLocalVariable("foo");
assertThat(value).isNull();

Expand All @@ -68,8 +71,7 @@ public void testLocalVariables() {
}

@Test
public void testVariables() {
ExpressionState state = getState();
void globalVariables() {
TypedValue typedValue = state.lookupVariable("foo");
assertThat(typedValue).isEqualTo(TypedValue.NULL);

Expand All @@ -85,8 +87,7 @@ public void testVariables() {
}

@Test
public void testNoVariableInterference() {
ExpressionState state = getState();
void noVariableInterference() {
TypedValue typedValue = state.lookupVariable("foo");
assertThat(typedValue).isEqualTo(TypedValue.NULL);

Expand All @@ -99,8 +100,7 @@ public void testNoVariableInterference() {
}

@Test
public void testLocalVariableNestedScopes() {
ExpressionState state = getState();
void localVariableNestedScopes() {
assertThat(state.lookupLocalVariable("foo")).isNull();

state.setLocalVariable("foo",12);
Expand All @@ -120,30 +120,26 @@ public void testLocalVariableNestedScopes() {
}

@Test
public void testRootContextObject() {
ExpressionState state = getState();
void rootContextObject() {
assertThat(state.getRootContextObject().getValue().getClass()).isEqualTo(Inventor.class);

// although the root object is being set on the evaluation context, the value in the 'state' remains what it was when constructed
// Although the root object is being set on the evaluation context,
// the value in the 'state' remains what it was when constructed.
((StandardEvaluationContext) state.getEvaluationContext()).setRootObject(null);
assertThat(state.getRootContextObject().getValue().getClass()).isEqualTo(Inventor.class);
// assertEquals(null, state.getRootContextObject().getValue());
assertThat(state.getRootContextObject().getValue()).isInstanceOf(Inventor.class);

state = new ExpressionState(new StandardEvaluationContext());
assertThat(state.getRootContextObject()).isEqualTo(TypedValue.NULL);


((StandardEvaluationContext) state.getEvaluationContext()).setRootObject(null);
assertThat(state.getRootContextObject().getValue()).isNull();
}

@Test
public void testActiveContextObject() {
ExpressionState state = getState();
void activeContextObject() {
assertThat(state.getActiveContextObject().getValue()).isEqualTo(state.getRootContextObject().getValue());

assertThatIllegalStateException().isThrownBy(
state::popActiveContextObject);
assertThatIllegalStateException().isThrownBy(state::popActiveContextObject);

state.pushActiveContextObject(new TypedValue(34));
assertThat(state.getActiveContextObject().getValue()).isEqualTo(34);
Expand All @@ -162,8 +158,7 @@ public void testActiveContextObject() {
}

@Test
public void testPopulatedNestedScopes() {
ExpressionState state = getState();
void populatedNestedScopes() {
assertThat(state.lookupLocalVariable("foo")).isNull();

state.enterScope("foo",34);
Expand All @@ -181,27 +176,22 @@ public void testPopulatedNestedScopes() {
}

@Test
public void testRootObjectConstructor() {
EvaluationContext ctx = getContext();
void rootObjectConstructor() {
EvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
// TypedValue root = ctx.getRootObject();
// supplied should override root on context
ExpressionState state = new ExpressionState(ctx,new TypedValue("i am a string"));
ExpressionState state = new ExpressionState(ctx, new TypedValue("i am a string"));
TypedValue stateRoot = state.getRootContextObject();
assertThat(stateRoot.getTypeDescriptor().getType()).isEqualTo(String.class);
assertThat(stateRoot.getValue()).isEqualTo("i am a string");
}

@Test
public void testPopulatedNestedScopesMap() {
ExpressionState state = getState();
void populatedNestedScopesMap() {
assertThat(state.lookupLocalVariable("foo")).isNull();
assertThat(state.lookupLocalVariable("goo")).isNull();

Map<String,Object> m = new HashMap<>();
m.put("foo", 34);
m.put("goo", "abc");

state.enterScope(m);
state.enterScope(Map.of("foo", 34, "goo", "abc"));
assertThat(state.lookupLocalVariable("foo")).isEqualTo(34);
assertThat(state.lookupLocalVariable("goo")).isEqualTo("abc");

Expand All @@ -217,61 +207,42 @@ public void testPopulatedNestedScopesMap() {
}

@Test
public void testOperators() {
ExpressionState state = getState();
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() ->
state.operate(Operation.ADD,1,2))
void operators() {
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> state.operate(Operation.ADD,1,2))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES));

assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() ->
state.operate(Operation.ADD,null,null))
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> state.operate(Operation.ADD,null,null))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES));
}

@Test
public void testComparator() {
ExpressionState state = getState();
void comparator() {
assertThat(state.getTypeComparator()).isEqualTo(state.getEvaluationContext().getTypeComparator());
}

@Test
public void testTypeLocator() throws EvaluationException {
ExpressionState state = getState();
void typeLocator() throws EvaluationException {
assertThat(state.getEvaluationContext().getTypeLocator()).isNotNull();
assertThat(state.findType("java.lang.Integer")).isEqualTo(Integer.class);
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() ->
state.findType("someMadeUpName"))
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> state.findType("someMadeUpName"))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(SpelMessage.TYPE_NOT_FOUND));

}

@Test
public void testTypeConversion() throws EvaluationException {
ExpressionState state = getState();
void typeConversion() throws EvaluationException {
String s = (String) state.convertValue(34, TypeDescriptor.valueOf(String.class));
assertThat(s).isEqualTo("34");

s = (String)state.convertValue(new TypedValue(34), TypeDescriptor.valueOf(String.class));
s = (String) state.convertValue(new TypedValue(34), TypeDescriptor.valueOf(String.class));
assertThat(s).isEqualTo("34");
}

@Test
public void testPropertyAccessors() {
ExpressionState state = getState();
void propertyAccessors() {
assertThat(state.getPropertyAccessors()).isEqualTo(state.getEvaluationContext().getPropertyAccessors());
}

/**
* @return a new ExpressionState
*/
private ExpressionState getState() {
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
ExpressionState state = new ExpressionState(context);
return state;
}

private EvaluationContext getContext() {
return TestScenarioCreator.getTestEvaluationContext();
}

}

0 comments on commit dbf6f7d

Please sign in to comment.