blob: 6b9f31f1574f1b60ef1a11d3680cf930ddfece51 [file] [log] [blame]
/*
* Copyright 2011 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jexl3.internal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlException;
import org.apache.commons.jexl3.JexlFeatures;
import org.apache.commons.jexl3.JexlScript;
import org.apache.commons.jexl3.parser.ASTJexlScript;
import org.apache.commons.jexl3.parser.JexlNode;
/**
* Helper methods for validate sessions.
*/
public class Util {
/**
* Will force testing the debugger for each derived test class by
* recreating each expression from the JexlNode in the JexlEngine cache &
* testing them for equality with the origin.
* @throws Exception
*/
public static void debuggerCheck(final JexlEngine ijexl) throws Exception {
final Engine jexl = (Engine) ijexl;
// without a cache, nothing to check
if (jexl == null || jexl.cache == null) {
return;
}
final Engine jdbg = new Engine();
jdbg.parser.allowRegisters(true);
final Debugger dbg = new Debugger();
// iterate over all expression in
for (final Map.Entry<Source, ASTJexlScript> entry : jexl.cache.entries()) {
final JexlNode node = entry.getValue();
// recreate expr string from AST
dbg.debug(node);
final String expressiondbg = dbg.toString();
final JexlFeatures features = entry.getKey().getFeatures();
// recreate expr from string
try {
final Script exprdbg = jdbg.createScript(features, null, expressiondbg, null);
// make arg cause become the root cause
JexlNode root = exprdbg.script;
while (root.jjtGetParent() != null) {
root = root.jjtGetParent();
}
// test equality
final String reason = checkEquals(root, node);
if (reason != null) {
throw new RuntimeException("check equal failed: "
+ expressiondbg
+ " /**** " + reason + " **** */ "
+ entry.getKey());
}
} catch (final JexlException xjexl) {
throw new RuntimeException("check parse failed: "
+ expressiondbg
+ " /*********/ "
+ entry.getKey(), xjexl);
}
}
}
/**
* Creates a list of all descendants of a script including itself.
* @param node the script to flatten
* @return the descendants-and-self list
*/
protected static ArrayList<JexlNode> flatten(final JexlNode node) {
final ArrayList<JexlNode> list = new ArrayList<JexlNode>();
flatten(list, node);
return list;
}
/**
* Recursively adds all children of a script to the list of descendants.
* @param list the list of descendants to add to
* @param node the script & descendants to add
*/
private static void flatten(final List<JexlNode> list, final JexlNode node) {
final int nc = node.jjtGetNumChildren();
list.add(node);
for (int c = 0; c < nc; ++c) {
flatten(list, node.jjtGetChild(c));
}
}
/**
* Checks the equality of 2 nodes by comparing all their descendants.
* Descendants must have the same class and same image if non null.
* @param lhs the left script
* @param rhs the right script
* @return null if true, a reason otherwise
*/
private static String checkEquals(JexlNode lhs, JexlNode rhs) {
if (lhs != rhs) {
final ArrayList<JexlNode> lhsl = flatten(lhs);
final ArrayList<JexlNode> rhsl = flatten(rhs);
if (lhsl.size() != rhsl.size()) {
return "size: " + lhsl.size() + " != " + rhsl.size();
}
for (int n = 0; n < lhsl.size(); ++n) {
lhs = lhsl.get(n);
rhs = rhsl.get(n);
if (lhs.getClass() != rhs.getClass()) {
return "class: " + lhs.getClass() + " != " + rhs.getClass();
}
final String lhss = lhs.toString();
final String rhss = rhs.toString();
if ((lhss == null && rhss != null)
|| (lhss != null && rhss == null)) {
return "image: " + lhss + " != " + rhss;
}
if (lhss != null && !lhss.equals(rhss)) {
return "image: " + lhss + " != " + rhss;
}
}
}
return null;
}
/**
* A helper class to help validate AST problems.
* @param e the script
* @return an indented version of the AST
*/
protected static String flattenedStr(final JexlScript e) {
return "";//e.getText() + "\n" + flattenedStr(((Script)e).script);
}
private static String indent(JexlNode node) {
final StringBuilder strb = new StringBuilder();
while (node != null) {
strb.append(" ");
node = node.jjtGetParent();
}
return strb.toString();
}
private String flattenedStr(final JexlNode node) {
final ArrayList<JexlNode> flattened = flatten(node);
final StringBuilder strb = new StringBuilder();
for (final JexlNode flat : flattened) {
strb.append(indent(flat));
strb.append(flat.getClass().getSimpleName());
final String sflat = flat.toString();
if (sflat != null) {
strb.append(" = ");
strb.append(sflat);
}
strb.append("\n");
}
return strb.toString();
}
}