package org.mvel2.tests.core;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import org.mvel2.DataConversion;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
import org.mvel2.compiler.CompiledExpression;
import org.mvel2.compiler.ExpressionCompiler;
import org.mvel2.debug.DebugTools;
import org.mvel2.integration.impl.MapVariableResolverFactory;
import org.mvel2.optimizers.dynamic.DynamicOptimizer;
import org.mvel2.tests.core.res.Base;
import org.mvel2.tests.core.res.DerivedClass;
import org.mvel2.tests.core.res.Foo;
import org.mvel2.tests.core.res.TestInterface;
import org.mvel2.util.StringAppender;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static java.lang.Integer.parseInt;
import static java.lang.String.valueOf;
import static java.lang.System.currentTimeMillis;
import static java.lang.System.getProperty;
import static org.mvel2.MVEL.compileExpression;
import static org.mvel2.MVEL.executeExpression;
import static org.mvel2.debug.DebugTools.decompile;
import static org.mvel2.optimizers.OptimizerFactory.setDefaultOptimizer;
public abstract class AbstractTest extends TestCase {
static {
// Modify the dynamic optimizer to ensure it always engages the JIT
DynamicOptimizer.tenuringThreshold = 1;
}
private boolean silentTests = Boolean.getBoolean("mvel.tests.silent");
public void testNothing() {
// to satify Eclipse and Surefire.
}
protected void setUp() throws Exception {
}
protected static Map createTestMap() {
Map map = new HashMap();
map.put("foo", new Foo());
map.put("a", null);
map.put("b", null);
map.put("c", "cat");
map.put("BWAH", "");
map.put("misc", new MiscTestClass());
map.put("pi", "3.14");
map.put("hour", 60);
map.put("zero", 0);
map.put("array", new String[]{"", "blip"});
map.put("order", new Order());
map.put("$id", 20);
map.put("five", 5);
map.put("testImpl",
new TestInterface() {
public String getName() {
return "FOOBAR!";
}
public boolean isFoo() {
return true;
}
});
map.put("derived", new DerivedClass());
map.put("ipaddr", "10.1.1.2");
map.put("dt1", new Date(currentTimeMillis() - 100000));
map.put("dt2", new Date(currentTimeMillis()));
return map;
}
protected void tearDown() throws Exception {
}
protected Object test(final String ex) {
Thread[] threads;
int threadCount;
if (Boolean.getBoolean("mvel.tests.quick")) {
threadCount = 1;
}
else if (getProperty("mvel.tests.threadcount") != null) {
threadCount = parseInt(getProperty("mvel.tests.threadcount"));
}
else {
threadCount = 5;
}
threads = new Thread[threadCount];
final Collection<Object> results = Collections.synchronizedCollection(new LinkedList<Object>());
final Collection<Throwable> exceptions = Collections.synchronizedCollection(new LinkedList<Throwable>());
long time = currentTimeMillis();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new TestRunner(results, exceptions, ex));
}
if (!silentTests) {
System.out.println("\n[test] begin test for:\n----------------------");
System.out.println(ex);
System.out.println("----------------------");
}
for (Thread thread1 : threads) {
if (threads.length > 1) {
System.out.println("Start Thread.");
thread1.setPriority(Thread.MIN_PRIORITY);
thread1.start();
}
else {
thread1.run();
}
}
if (threads.length > 1) {
boolean threadsRunning = true;
while (threadsRunning) {
threadsRunning = false;
for (Thread thread : threads) {
if (thread.isAlive()) {
System.out.println("Thread Alive.");
threadsRunning = true;
break;
}
}
try {
Thread.sleep(250);
}
catch (InterruptedException e) {
break;
}
}
}
System.out.println("All threads have stopped.");
System.out.println("Result Count: " + results.size());
// analyze results
if (!silentTests) {
System.out.println("[test] finished in: " + (currentTimeMillis() - time) + "ms (execution count: " + (threads.length * 8) + " [mixed modes])");
System.out.print("[test] analyzing results ... ");
}
Object last = null;
if (!exceptions.isEmpty()) {
Throwable firstException = exceptions.iterator().next();
String message = firstException.getMessage().replaceAll("\n", " ");
if (message.length() > 80) {
message = message.substring(0, 80 - 3) + "...";
}
throw new RuntimeException(exceptions.size() + " out of " + threadCount
+ " threads terminated due to exception: " + message,
firstException);
}
if (!results.isEmpty()) {
last = results.iterator().next();
if (last != null) {
for (Object o : results) {
if (o == null) {
throw new AssertionError("differing result in multi-thread test (first array has: " + valueOf(last) + "; second has: " + valueOf(o) + ")");
}
else if (!o.equals(last)) {
if (o.getClass().isArray()) {
// Object[] a1 = (Object[]) o;
// Object[] a2 = (Object[]) last;
//
// if (a1.length == a2.length) {
// for (int i = 0; i < a1.length; i++) {
// if (a1[i] == null && a2[i] == null) {
// continue;
// }
// else if (!a1[i].equals(a2[i])) {
// throw new AssertionError("differing result in multi-thread test (first array has: " + valueOf(last) + "; second has: " + valueOf(o) + ")");
// }
// }
// }
// else {
// throw new AssertionError("differing result in multi-thread test: array sizes differ.");
// }
}
else {
throw new AssertionError("differing result in multi-thread test (last was: " + valueOf(last) + "; current is: " + valueOf(o) + ")");
}
}
last = o;
}
}
}
if (!silentTests) {
System.out.println("good!");
}
return last;
}
protected static class TestRunner implements Runnable {
private final Collection<Object> results;
private final Collection<Throwable> exceptions;
private final String expression;
public TestRunner(Collection<Object> results, Collection<Throwable> exceptions, String expression) {
this.results = results;
this.exceptions = exceptions;
this.expression = expression;
}
public void run() {
try {
Object result = runSingleTest(expression);
results.add(result);
}
catch (Throwable e) {
exceptions.add(e);
System.out.println("thread terminating due to exception");
e.printStackTrace();
}
}
}
protected static Object runSingleTest(final String ex) {
return _test(ex);
}
protected static Object testCompiledSimple(String ex) {
return MVEL.executeExpression(MVEL.compileExpression(ex));
}
protected static Object testCompiledSimple(String ex, Map map) {
return MVEL.executeExpression(MVEL.compileExpression(ex), map);
}
protected static Object testCompiledSimple(String ex, Object base, Map map) {
return MVEL.executeExpression(MVEL.compileExpression(ex), base, map);
}
protected static Object _test(String ex) {
ExpressionCompiler compiler = new ExpressionCompiler(ex);
StringAppender failErrors = new StringAppender();
CompiledExpression compiled = compiler.compile();
Object first = null, second = null, third = null, fourth = null, fifth = null, sixth = null, seventh = null,
eighth = null;
System.out.println(DebugTools.decompile((Serializable) compiled));
if (!Boolean.getBoolean("mvel2.disable.jit")) {
setDefaultOptimizer("ASM");
try {
first = executeExpression(compiled, new Base(), createTestMap());
}
catch (Exception e) {
failErrors.append("\nFIRST TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
try {
second = executeExpression(compiled, new Base(), createTestMap());
}
catch (Exception e) {
failErrors.append("\nSECOND TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
}
try {
third = MVEL.eval(ex, new Base(), createTestMap());
}
catch (Exception e) {
failErrors.append("\nTHIRD TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
if (first != null && !first.getClass().isArray()) {
if (!first.equals(second)) {
System.out.println(failErrors.toString());
throw new AssertionError("Different result from test 1 and 2 (Compiled Re-Run / JIT) [first: "
+ valueOf(first) + "; second: " + valueOf(second) + "]");
}
if (!first.equals(third)) {
if (failErrors != null) System.out.println(failErrors.toString());
throw new AssertionError("Different result from test 1 and 3 (Compiled to Interpreted) [first: " +
valueOf(first) + " (" + (first != null ? first.getClass().getName() : null) + "); third: " + valueOf(third) + " (" + (third != null ? third.getClass().getName() : "null") + ")]");
}
}
setDefaultOptimizer("reflective");
Serializable compiled2 = compileExpression(ex);
try {
fourth = executeExpression(compiled2, new Base(), createTestMap());
}
catch (Exception e) {
if (failErrors == null) failErrors = new StringAppender();
failErrors.append("\nFOURTH TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
try {
fifth = executeExpression(compiled2, new Base(), createTestMap());
}
catch (Exception e) {
e.printStackTrace();
if (failErrors == null) failErrors = new StringAppender();
failErrors.append("\nFIFTH TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
if (fourth != null && !fourth.getClass().isArray()) {
if (!fourth.equals(fifth)) {
throw new AssertionError("Different result from test 4 and 5 (Compiled Re-Run X2) [fourth: "
+ valueOf(fourth) + "; fifth: " + valueOf(fifth) + "]");
}
}
ParserContext ctx = new ParserContext();
ctx.setSourceFile("unittest");
ctx.setDebugSymbols(true);
ExpressionCompiler debuggingCompiler = new ExpressionCompiler(ex, ctx);
// debuggingCompiler.setDebugSymbols(true);
CompiledExpression compiledD = debuggingCompiler.compile();
try {
sixth = executeExpression(compiledD, new Base(), createTestMap());
}
catch (Exception e) {
if (failErrors == null) failErrors = new StringAppender();
failErrors.append("\nSIXTH TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
if (sixth != null && !sixth.getClass().isArray()) {
if (!fifth.equals(sixth)) {
System.out.println("Payload 1 -- No Symbols: ");
System.out.println(decompile(compiled));
System.out.println();
System.out.println("Payload 2 -- With Symbols: ");
System.out.println(decompile(compiledD));
System.out.println();
throw new AssertionError("Different result from test 5 and 6 (Compiled to Compiled+DebuggingSymbols) [first: "
+ valueOf(fifth) + "; second: " + valueOf(sixth) + "]");
}
}
try {
seventh = executeExpression(compiledD, new Base(), createTestMap());
}
catch (Exception e) {
if (failErrors == null) failErrors = new StringAppender();
failErrors.append("\nSEVENTH TEST: { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
if (seventh != null && !seventh.getClass().isArray()) {
if (!seventh.equals(sixth)) {
throw new AssertionError("Different result from test 4 and 5 (Compiled Re-Run / Reflective) [first: "
+ valueOf(first) + "; second: " + valueOf(second) + "]");
}
}
try {
Serializable xx = serializationTest(compiledD);
eighth = executeExpression(xx, new Base(), new MapVariableResolverFactory(createTestMap()));
}
catch (Exception e) {
if (failErrors == null) failErrors = new StringAppender();
failErrors.append("\nEIGHTH TEST (Serializability): { " + ex + " }: EXCEPTION REPORT: \n\n");
CharArrayWriter writer = new CharArrayWriter();
e.printStackTrace(new PrintWriter(writer));
failErrors.append(writer.toCharArray());
}
if (eighth != null && !eighth.getClass().isArray()) {
if (!eighth.equals(seventh)) {
throw new AssertionError("Different result from test 7 and 8 (Compiled Re-Run / Reflective) [first: "
+ valueOf(first) + "; second: " + valueOf(second) + "]");
}
}
if (failErrors.length() > 0) {
System.out.println(decompile(compiledD));
throw new AssertionError("Detailed Failure Report:\n" + failErrors.toString());
}
return fourth;
}
protected static Serializable serializationTest(Serializable s) throws Exception {
File file = new File("./mvel_ser_test" + currentTimeMillis() + Math.round(Math.random() * 1000) + ".tmp");
InputStream inputStream = null;
ObjectInputStream objectIn = null;
try {
file.createNewFile();
file.deleteOnExit();
FileOutputStream fileStream = new FileOutputStream(file);
ObjectOutputStream objectOut = new ObjectOutputStream(new BufferedOutputStream(fileStream));
objectOut.writeObject(s);
objectOut.flush();
fileStream.flush();
fileStream.close();
inputStream = new BufferedInputStream(new FileInputStream(file));
objectIn = new ObjectInputStream(inputStream);
return (Serializable) objectIn.readObject();
}
finally {
if (inputStream != null) inputStream.close();
if (objectIn != null) objectIn.close();
// file.delete();
}
}
public static class MiscTestClass {
int exec = 0;
@SuppressWarnings({"unchecked", "UnnecessaryBoxing"})
public List toList(Object object1, String string, int integer, Map map, List list) {
exec++;
List l = new ArrayList();
l.add(object1);
l.add(string);
l.add(new Integer(integer));
l.add(map);
l.add(list);
return l;
}
public int getExec() {
return exec;
}
}
public static class Bean {
private Date myDate = new Date();
public Date getToday() {
return new Date();
}
public Date getNullDate() {
return null;
}
public String getNullString() {
return null;
}
public Date getMyDate() {
return myDate;
}
public void setMyDate(Date myDate) {
this.myDate = myDate;
}
}
public static class Context {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yy");
private Bean bean;
public Bean getBean() {
return bean;
}
public void setBean(Bean bean) {
this.bean = bean;
}
public String formatDate(Date date) {
return date == null ? null : dateFormat.format(date);
}
public String formatString(String str) {
return str == null ? "<NULL>" : str;
}
}
public static class Person {
private String name;
private int age;
private String likes;
private List<Foo> footributes;
private Map<String, Foo> maptributes;
private Map<Object, Foo> objectKeyMaptributes;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, String likes, int age) {
this.name = name;
this.likes = likes;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Foo> getFootributes() {
return footributes;
}
public void setFootributes(List<Foo> footributes) {
this.footributes = footributes;
}
public Map<String, Foo> getMaptributes() {
return maptributes;
}
public void setMaptributes(Map<String, Foo> maptributes) {
this.maptributes = maptributes;
}
public Map<Object, Foo> getObjectKeyMaptributes() {
return objectKeyMaptributes;
}
public void setObjectKeyMaptributes(Map<Object, Foo> objectKeyMaptributes) {
this.objectKeyMaptributes = objectKeyMaptributes;
}
public String toString() {
return "Person( name==" + name + " age==" + age + " likes==" + likes + " )";
}
}
public static class Address {
private String street;
public Address(String street) {
super();
this.street = street;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
public static class Drools {
public void insert(Object obj) {
}
}
public static class Model {
private List latestHeadlines;
public List getLatestHeadlines() {
return latestHeadlines;
}
public void setLatestHeadlines(List latestHeadlines) {
this.latestHeadlines = latestHeadlines;
}
}
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private List items = new ArrayList();
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
public void addItem(Item item) {
this.items.add(item);
}
public List getItems() {
return items;
}
}
public static class Item {
private String name;
public Item(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ClassA {
private Integer i;
private double d;
private String s;
public Date date;
private BigDecimal bigdec;
private BigInteger bigint;
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public BigDecimal getBigdec() {
return bigdec;
}
public void setBigdec(BigDecimal bigdec) {
this.bigdec = bigdec;
}
public BigInteger getBigint() {
return bigint;
}
public void setBigint(BigInteger bigint) {
this.bigint = bigint;
}
}
public class ClassB {
private Integer i;
private double d;
private String s;
public String date;
private BigDecimal bigdec;
private BigInteger bigint;
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public BigDecimal getBigdec() {
return bigdec;
}
public void setBigdec(BigDecimal bigdec) {
this.bigdec = bigdec;
}
public BigInteger getBigint() {
return bigint;
}
public void setBigint(BigInteger bigint) {
this.bigint = bigint;
}
}
public static class Order {
private int number = 20;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public static void assertNumEquals(Object obj, Object obj2) {
assertNumEquals(obj, obj2, true);
}
public static void assertNumEquals(Object obj, Object obj2, boolean permitRoundingVariance) {
if (obj == null || obj2 == null) throw new AssertionError("null value");
if (obj.getClass().equals(obj2.getClass())) {
if (obj instanceof Number) {
double compare = ((Number) obj).doubleValue() - ((Number) obj2).doubleValue();
if (!(compare <= 0.0001d && compare >= -0.0001d)) {
throw new AssertionFailedError("expected <" + String.valueOf(obj) + "> but was <" + String.valueOf(obj) + ">");
}
}
else {
assertEquals(obj, obj2);
}
}
else {
obj = DataConversion.convert(obj, obj2.getClass());
if (!obj.equals(obj2)) {
if (permitRoundingVariance) {
obj = DataConversion.convert(obj, Integer.class);
obj2 = DataConversion.convert(obj2, Integer.class);
assertEquals(obj, obj2);
}
else {
throw new AssertionFailedError("expected <" + String.valueOf(obj) + "> but was <" + String.valueOf(obj) + ">");
}
}
}
}
}