/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.el.mvel; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mule.runtime.core.util.ClassUtils.withContextClassLoader; import org.mule.mvel2.CompileException; import org.mule.mvel2.ParserConfiguration; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.core.el.context.AbstractELTestCase; import org.mule.tck.MuleTestUtils; import org.mule.tck.size.SmallTest; import java.io.Serializable; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; @SmallTest public class MVELExpressionExecutorTestCase extends AbstractELTestCase { public static final String SIMPLE_EXPRESSION = "'hi'"; protected MVELExpressionExecutor mvel; protected MVELExpressionLanguageContext context; public MVELExpressionExecutorTestCase(String mvelOptimizer) { super(mvelOptimizer); } @Before public void setupMVEL() throws InitialisationException { mvel = new MVELExpressionExecutor(new ParserConfiguration()); context = Mockito.mock(MVELExpressionLanguageContext.class); Mockito.when(context.isResolveable(Mockito.anyString())).thenReturn(false); } @Test public void evaluateReturnInt() { assertEquals(4, mvel.execute("2*2", null)); } @Test public void evaluateReturnString() { assertEquals("hi", mvel.execute("'hi'", null)); } @Test(expected = CompileException.class) public void evaluateInvalidExpression() { assertEquals(4, mvel.execute("2*'2", null)); } @Test(expected = CompileException.class) public void invalidExpression() { mvel.validate("a9-#'"); } @Test public void validExpression() { mvel.validate("var a = 2"); } @Test public void useContextClassLoader() throws ClassNotFoundException { withContextClassLoader(new MyClassClassLoader(), () -> { try { assertFalse((Boolean) mvel.execute("1 is org.MyClass", null)); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } }); } @Test public void safeMapPropertyAccessIsEnabled() { assertEquals(null, mvel.execute("['test1' : null].doesntExist", context)); } @Test public void safeMapNestedPropertyAccessIsEnabled() { assertEquals(null, mvel.execute("['test1' : null].test1", context)); } @Test public void safeBeanPropertyAccessIsEnabled() { assertNull(mvel.execute("new Object().doesntExist", context)); } @Test public void safeNestedBeanPropertyAccessIsEnabled() { assertNull(mvel.execute("new Object().?doesntExist.other", context)); } @Test(expected = RuntimeException.class) public void nestedMapAccessFailsCorrectly() { assertNull(mvel.execute("['test1' : null]['test2']['test2']", context)); } @Test(expected = RuntimeException.class) public void safeNestedBeanPropertyAccessMaintainsNullSafeBehavior() { assertNull(mvel.execute("new Object().doesntExist.other", context)); } @Test(expected = RuntimeException.class) public void safeNestedMapPropertyAccessMaintainsNullSafeBehavior() { assertNull(mvel.execute("['test1' : null].doesntExist.other", context)); } @Test(expected = RuntimeException.class) public void safePropertyDoesntMessNullSafeMode() { assertNull(mvel.execute("null.doesntExist", context)); } @Test(expected = RuntimeException.class) public void invalidMethodCallFails() { assertNull(mvel.execute("new Object().doesntExist()", context)); } @Test public void cachesCompiledExpressions() throws Exception { final Serializable compiledExpression1 = mvel.getCompiledExpression(SIMPLE_EXPRESSION); final Serializable compiledExpression2 = mvel.getCompiledExpression(SIMPLE_EXPRESSION); assertThat(compiledExpression1, is(compiledExpression2)); } @Test public void doesNotCachesCompiledExpressions() throws Exception { MuleTestUtils.testWithSystemProperty(MVELExpressionExecutor.DISABLE_MEL_EXPRESSION_CACHE, "", new MuleTestUtils.TestCallback() { @Override public void run() throws Exception { setupMVEL(); final Serializable compiledExpression1 = mvel.getCompiledExpression(SIMPLE_EXPRESSION); final Serializable compiledExpression2 = mvel.getCompiledExpression(SIMPLE_EXPRESSION); assertThat(compiledExpression1, is(not(compiledExpression2))); } }); } static class MyClassClassLoader extends ClassLoader { @Override protected Class<?> findClass(String className) throws ClassNotFoundException { if (className.equals("org.MyClass")) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "org/MyClass", null, "java/lang/Object", null); return defineClass(className, cw.toByteArray(), 0, cw.toByteArray().length); } else { return super.findClass(className); } } } }