diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index fbf7e80..5f4794e 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -28,7 +28,7 @@ jobs: - run: | ant clean dist cd dist; zip -r ../funz-client.zip ./*; cd .. - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: path: dist - uses: softprops/action-gh-release@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4f41f9b..94a3e60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -76,7 +76,7 @@ jobs: continue-on-error: true timeout-minutes: 100 - if: steps.anttest.outcome != 'success' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: artifacts-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.Rserver }}-unit path: | diff --git a/.github/workflows/use.yml b/.github/workflows/use.yml index 6d39420..504dfb7 100644 --- a/.github/workflows/use.yml +++ b/.github/workflows/use.yml @@ -70,7 +70,7 @@ jobs: continue-on-error: true timeout-minutes: 60 - if: steps.anttest.outcome != 'success' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: artifacts-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.Rserver }}-Main path: | @@ -203,7 +203,7 @@ jobs: continue-on-error: true timeout-minutes: 60 - if: steps.anttest.outcome != 'success' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: artifacts-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.Rserver }}-${{ matrix.CLI }} path: | diff --git a/src/main/java/org/funz/run/CalculatorsPool.java b/src/main/java/org/funz/run/CalculatorsPool.java index ba6d182..0e88198 100644 --- a/src/main/java/org/funz/run/CalculatorsPool.java +++ b/src/main/java/org/funz/run/CalculatorsPool.java @@ -10,10 +10,8 @@ import java.net.MulticastSocket; import java.net.SocketException; import java.net.SocketTimeoutException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +import java.util.*; + import org.funz.api.Funz_v1; import static org.funz.Protocol.PING_PERIOD; import org.funz.conf.Configuration; @@ -23,7 +21,6 @@ import org.funz.run.Computer.ComputerGuard; import org.funz.run.Computer.ComputerStatusListener; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.Collections; /** * @@ -350,7 +347,7 @@ public void update(DatagramSocket s) throws IOException { s.receive(p); // blocking as long as a packet not received / or SoTimeout exceeded } catch (SocketTimeoutException t) { force_close(s); - if (!shutdown) s = getSocket(_port); // Do not rebuild socket if shutdown + if (!shutdown) UDP_socket = getSocket(_port); // Do not rebuild socket if shutdown return; } catch (Exception t) { Log.err(t,2); diff --git a/src/main/java/org/funz/script/ParseExpression.java b/src/main/java/org/funz/script/ParseExpression.java index 6835f83..ef47d92 100644 --- a/src/main/java/org/funz/script/ParseExpression.java +++ b/src/main/java/org/funz/script/ParseExpression.java @@ -13,34 +13,48 @@ public class ParseExpression { - public static List StaticMethods = new LinkedList(); - public final static String PIPE = ">>"; + private static final List STATIC_METHODS = new LinkedList<>(); + private final static String PIPE = ">>"; public final static String FILES = "files"; + /** + * Initializes the engine by populating the list of static methods from the org.funz.util.Parser class. (see funz-core) + */ static void initEngine() { Method[] methods = Parser.class.getMethods(); for (Method method : methods) { - if (!StaticMethods.contains(method.getName())) { - StaticMethods.add(method.getName()); + if (!STATIC_METHODS.contains(method.getName())) { + STATIC_METHODS.add(method.getName()); } } } + /** + * Evaluates a static method on the given object with the specified arguments. + * + * @param o The object on which the method is invoked. + * @param staticMethod The name of the static method to invoke. + * @param args The arguments to pass to the method. + * @return The result of the method invocation. + * @throws Exception If the method cannot be invoked or does not exist. + */ public static Object Eval(Object o, String staticMethod, Object... args) throws Exception { -// System.err.println("---------------------> Eval " + staticMethod + " ... " + Arrays.asList(args)); if (o == null) { - Log.logMessage("[ParseExpression.Call]", SeverityLevel.WARNING, true, "Calling " + staticMethod + " on args=" + Arrays.asList(args) + " for null object."); + Log.logMessage("[ParseExpression.Call]", SeverityLevel.ERROR, true, "Calling " + staticMethod + " on args=" + Arrays.asList(args) + " for null object."); + return null; } if (staticMethod == null) { - Log.logMessage("[ParseExpression.Call]", SeverityLevel.WARNING, true, "Calling void method on args=" + Arrays.asList(args) + " for " + o); + Log.logMessage("[ParseExpression.Call]", SeverityLevel.ERROR, true, "Calling void method on args=" + Arrays.asList(args) + " for " + o); + return null; } staticMethod = staticMethod.trim(); if (args == null || args.length == 0) { - Log.logMessage("[ParseExpression.Call]", SeverityLevel.WARNING, true, "Calling " + staticMethod + " on void args for " + o); + Log.logMessage("[ParseExpression.Call]", SeverityLevel.ERROR, true, "Calling " + staticMethod + " on void args for " + o); + return null; } - Class[] argsclass = new Class[args.length]; + Class[] argsclass = new Class[args.length]; for (int i = 0; i < argsclass.length; i++) { - Class noprim = args[i].getClass(); + Class noprim = args[i].getClass(); if (noprim == Double.class) { argsclass[i] = double.class; } else if (noprim == Integer.class) { @@ -53,42 +67,69 @@ public static Object Eval(Object o, String staticMethod, Object... args) throws argsclass[i] = noprim; } } - Method m = null; + Method m = getMethod(o, staticMethod, argsclass); + return m.invoke(o, args); + } + + /** + * Retrieves a method from the specified object or class based on the method name and argument types. + * + * @param o The object or class instance on which the method is to be invoked. + * @param staticMethod The name of the method to retrieve. If it contains a dot (e.g., "ClassName.methodName"), + * it is treated as a static method of the specified class. + * @param argsclass An array of argument types that the method accepts. + * @return The Method object representing the specified method. + * @throws ClassNotFoundException If the class specified in the static method name cannot be found. + * @throws NoSuchMethodException If the method with the specified name and argument types cannot be found. + */ + private static Method getMethod(Object o, String staticMethod, Class[] argsclass) throws ClassNotFoundException, NoSuchMethodException { + Method m; if (staticMethod.contains(".")) { // Integer.parseInt String pack = ""; + // If the method starts with an uppercase letter, it is a static method of the java.lang package. like Integer.parseInt if (Character.isUpperCase(staticMethod.charAt(0))) { pack = "java.lang."; } - Class classs = Class.forName(pack + staticMethod.substring(0, staticMethod.indexOf("."))); - m = classs.getMethod(staticMethod.substring(staticMethod.indexOf(".") + 1), argsclass); + Class aClass = Class.forName(pack + staticMethod.substring(0, staticMethod.indexOf("."))); + m = aClass.getMethod(staticMethod.substring(staticMethod.indexOf(".") + 1), argsclass); } else { m = o.getClass().getMethod(staticMethod.trim(), argsclass); } - Object out = m.invoke(o, args); -// System.err.println("-----------------------------------------------------> " + out); - return out; + return m; } - static boolean isBraced(String s) { + /** + * Checks if the given string is braced or represents a valid algebraic expression. + * + * @param expr The string expression to check. + * @return True if the string is braced or valid, false otherwise. + */ + static boolean isBraced(String expr) { try { - Double.parseDouble(s); + Double.parseDouble(expr); return true; } catch (NumberFormatException e) { - return s.trim().matches("([\\!\\-]*[a-zA-Z0-9\\.]*)\\((.*)\\)");// startsWith("(") && s.endsWith(")"); + return expr.trim().matches("([!\\-]*[a-zA-Z0-9.]*)\\((.*)\\)"); } } + /** + * Evaluates an algebraic expression on the given object. + * + * @param o The object to evaluate the expression on. + * @param expr The algebraic expression to evaluate. + * @return The result of the evaluation. + * @throws Exception If the expression cannot be evaluated. + */ public static Object CallAlgebra(Object o, String expr) throws Exception { -// System.err.println("> CallAlgebra " + expr); try { - Double d = Double.parseDouble(expr.toString()); - return d; - } catch (NumberFormatException e) { + return Double.parseDouble(expr); + } catch (NumberFormatException ignored) { } - if (expr.toString().trim().equals("true")) { + if (expr.trim().equals("true")) { return true; } - if (expr.toString().trim().equals("false")) {// pffff... + if (expr.trim().equals("false")) { return false; } @@ -158,6 +199,22 @@ public static Object CallAlgebra(Object o, String expr) throws Exception { } else { throw new Exception("Bracketing algebra operations is required: (..)" + c + "(...) in expression: "+expr); } + } else if (c == '>') { + String left = current_arg.toString(); + String right = expr.substring(i + 1); + if (isBraced(left) && isBraced(right)) { + return (Double) CallAlgebra(o, left) > (Double) CallAlgebra(o, right); + } else { + //throw new Exception("Bracketing algebra operations is required: (..)" + c + "(...) in expression: "+expr); + } + } else if (c == '<') { + String left = current_arg.toString(); + String right = expr.substring(i + 1); + if (isBraced(left) && isBraced(right)) { + return (Double) CallAlgebra(o, left) < (Double) CallAlgebra(o, right); + } else { + //throw new Exception("Bracketing algebra operations is required: (..)" + c + "(...) in expression: "+expr); + } } } current_arg.append(c); @@ -188,7 +245,7 @@ public static Object CallAlgebra(Object o, String expr) throws Exception { if (expr.contains("(")) { Object ret = CallMethod(o, expr); - if (ret != null && ret.toString().equals(expr.toString())) { + if (ret != null && ret.toString().equals(expr)) { throw new Exception("Cannot evaluate expression " + expr); //to avoid infinite loop between CallAlgebra & CallMethod } else { return ret; @@ -199,23 +256,29 @@ public static Object CallAlgebra(Object o, String expr) throws Exception { } } + /** + * Evaluates a method call expression on the given object. + * + * @param o The object to evaluate the method call on. + * @param expr The method call expression to evaluate. + * @return The result of the method call. + * @throws Exception If the method call cannot be evaluated. + */ public static Object CallMethod(Object o, String expr) throws Exception { -// System.err.println("> CallMethod " + expr); try { - Double d = Double.parseDouble(expr); - return d; - } catch (NumberFormatException e) { + return Double.parseDouble(expr); + } catch (NumberFormatException ignored) { } if (expr.trim().equals("true")) { return true; } - if (expr.trim().equals("false")) {// pffff... + if (expr.trim().equals("false")) { return false; } if (!expr.contains("(")) { Object a = CallAlgebra(o, expr); - if (a != null && a.toString().equals(expr.toString())) { + if (a != null && a.toString().equals(expr)) { Log.err(new Exception("Cannot evaluate method " + expr), 1); //to avoid infinite loop between CallAlgebra & CallMethod } return a; @@ -223,9 +286,9 @@ public static Object CallMethod(Object o, String expr) throws Exception { String method = expr.substring(0, expr.indexOf('(')); String head = ""; - if (method.length() > 0) { + if (!method.isEmpty()) { int h = method.length() - 1; - while (h > 0 && (Character.isLetterOrDigit(method.charAt(h)) || method.charAt(h) == '.')) { + while (h > 0 && (Character.isLetterOrDigit(method.charAt(h)) || method.charAt(h) == '.' || method.charAt(h) == '_')) { h--; } head = h > 0 ? method.substring(0, h + 1) : ""; @@ -234,10 +297,52 @@ public static Object CallMethod(Object o, String expr) throws Exception { String args_string = expr.substring(expr.indexOf('(') + 1, expr.lastIndexOf(')')); String tail = expr.lastIndexOf(')') == expr.length() - 1 ? "" : expr.substring(expr.lastIndexOf(')') + 1); -// System.err.println("method " + method); -// System.err.println("head " + head); -// System.err.println("tail " + tail); - List args_string_list = new LinkedList(); + List args_string_list = getArgsStringList(args_string); + String[] args_string_array = args_string_list.toArray(new String[0]); + Object[] args = new Object[args_string_array.length]; + for (int i = 0; i < args.length; i++) { + String arg_string = args_string_array[i].trim(); + if (arg_string.startsWith("\"") && arg_string.endsWith("\"")) { + args[i] = arg_string.substring(1, arg_string.length() - 1).replace("\\\"","\""); + continue; + } + if (arg_string.startsWith("'") && arg_string.endsWith("'") && arg_string.length() == 3) { + args[i] = ""+arg_string.charAt(1); + continue; + } + try { + int in = Integer.parseInt(arg_string); + args[i] = in; + continue; + } catch (NumberFormatException ignored) { + } + try { + double d = Double.parseDouble(arg_string); + args[i] = d; + continue; + } catch (NumberFormatException ignored) { + } + args[i] = CallAlgebra(o, arg_string.trim()); + } + if (method.isEmpty() && args.length == 1) {//not a function call, just a bracket eval eg. (1+1)*3 + return CallAlgebra(o, head + args[0].toString() + tail); + } else { + if (head.isEmpty() && tail.isEmpty()) { + return Eval(o, method, args); + } else { + return CallAlgebra(o, head + Eval(o, method, args) + tail); + } + } + } + + /** + * Parses a string of arguments into a list of individual argument strings. + * + * @param args_string The string containing the arguments. + * @return A list of argument strings. + */ + private static List getArgsStringList(String args_string) { + List args_string_list = new LinkedList<>(); int openBraces = 0; boolean escaped = false; boolean simpleQuoted = false; @@ -248,95 +353,56 @@ public static Object CallMethod(Object o, String expr) throws Exception { if (c == ',' && openBraces == 0 && !simpleQuoted && !doubleQuoted) { args_string_list.add(current_arg.toString()); current_arg = new StringBuilder(); -// System.err.println(">>> " + args_string_list); continue; } -// System.err.println(current_arg); current_arg.append(c); - //System.err.println(StringUtils.repeat(" ",i)+c); if (c == '\\') { escaped = true; -// System.err.println(StringUtils.repeat(" ", i + 1) + "escaped = T"); } else { if (escaped) { escaped = false; -// System.err.println(">" + StringUtils.repeat(" ", i) + "escaped = F"); } else { if (c == '\'') { -// System.err.print(">" + StringUtils.repeat(" ", i) + "simpleQuoted = " + simpleQuoted); if (!doubleQuoted) { simpleQuoted = !simpleQuoted; } -// System.err.println(" -> " + simpleQuoted); } else if (c == '\"') { -// System.err.print(">" + StringUtils.repeat(" ", i) + "doubleQuoted = " + doubleQuoted); if (!simpleQuoted) { doubleQuoted = !doubleQuoted; } -// System.err.println(" -> " + doubleQuoted); } else if (!simpleQuoted && !doubleQuoted) { if (c == '(') { openBraces++; -// System.err.println(">" + StringUtils.repeat(" ", i) + "openBraces = " + openBraces); } else if (c == ')') { openBraces--; -// System.err.println(">" + StringUtils.repeat(" ", i) + "openBraces = " + openBraces); } } } } } args_string_list.add(current_arg.toString()); - String[] args_string_array = args_string_list.toArray(new String[args_string_list.size()]); - Object[] args = new Object[args_string_array.length]; - for (int i = 0; i < args.length; i++) { - String arg_string = args_string_array[i].trim(); - if (arg_string.startsWith("\"") && arg_string.endsWith("\"")) { - args[i] = arg_string.substring(1, arg_string.length() - 1).replace("\\\"","\""); - continue; - } - if (arg_string.startsWith("'") && arg_string.endsWith("'") && arg_string.length() == 3) { - args[i] = ""+arg_string.charAt(1); - continue; - } - try { - int in = Integer.parseInt(arg_string); - args[i] = in; - continue; - } catch (NumberFormatException e) { - } - try { - double d = Double.parseDouble(arg_string); - args[i] = d; - continue; - } catch (NumberFormatException e) { - } - args[i] = CallAlgebra(o, arg_string.trim()); - } - if (method.length() == 0 && args.length == 1) {//not a function call, just a bracket eval eg. (1+1)*3 -// System.err.println("-------------------------> CallAlgebra " + head + args[0].toString() + tail); - return CallAlgebra(o, head + args[0].toString() + tail); - } else { -// System.err.println("-------------------------> CallAlgebra/Eval h=" + head + " Call(o, method=" + method + ",args=<<" + Arrays.asList(args) + ">>) t=" + tail); - if (head.length() == 0 && tail.length() == 0) { - return Eval(o, method, args); - } else { - return CallAlgebra(o, head + Eval(o, method, args) + tail); - } - } + return args_string_list; } - public static List getSyntax() { - LinkedList list = new LinkedList(); - list.addAll(StaticMethods); - return list; + /** + * Retrieves the list of syntax elements (static methods) available for parsing. + * + * @return A list of syntax elements. + */ + public static List getSyntax() { + return new LinkedList<>(STATIC_METHODS); } + /** + * Converts a user-defined expression into a generalized expression format. + * + * @param userExpression The user-defined expression. + * @return The generalized expression. + */ static String importExpression(String userExpression) { String gexpr = userExpression; while (gexpr.contains(PIPE)) { - //System.out.println(" " + gexpr); int i = gexpr.indexOf(PIPE); int j = gexpr.indexOf("(", i + PIPE.length()); if (gexpr.substring(j + 1).trim().startsWith(")")) {//no more arg @@ -348,38 +414,56 @@ static String importExpression(String userExpression) { return gexpr; } + /** + * Exports an object, simplifying it if it is a list with a single element. + * + * @param go The object to export. + * @return The simplified or original object. + */ static Object exportObject(Object go) { - if (go instanceof List) { - List golist = (List) go; + if (go instanceof List) { + List golist = (List) go; if (golist.size() == 1) { return exportObject(golist.get(0)); } else { - return golist;//ASCII.cat("\n", golist); - //return ASCII.cat("\n", golist); + return golist; } } - return go;//.toString(); + return go; } - public static Object eval(Object of, Map outputNamesValues) { - assert of instanceof String : "Problem trying to eval " + of.toString() + " : not a String"; - return eval((String) of, outputNamesValues); + /** + * Evaluates an expression using the provided parameters. + * + * @param expression The expression to evaluate. + * @param outputNamesValues A map expression parameter names and their values. + * @return The result expression the evaluation. + */ + public static Object eval(Object expression, Map outputNamesValues) { + assert expression instanceof String : "Problem trying to eval " + expression.toString() + " : not a String"; + return eval((String) expression, outputNamesValues); } /** - * apply the function to get the result + * Evaluates a function or expression using the provided parameters. * - * @param outputValues values of initial outputs + * @param expression The function or expression to evaluate. + * @param params A map of parameter names and their values. + * @return The result of the evaluation. */ - public synchronized static Object eval(String f, Map params) { + public synchronized static Object eval(String expression, Map params) { Object out = null; - List rfiles = new LinkedList<>(); + List rFiles = new LinkedList<>(); try { - Log.logMessage("ParseExpression", SeverityLevel.INFO, false, "eval(" + f + "," + (params != null ? params.toString() : "null") + ")"); + Log.logMessage("ParseExpression", SeverityLevel.INFO, false, "eval(" + expression + "," + (params != null ? params.toString() : "null") + ")"); - if (params != null && params.containsKey(f)) { - return params.get(f); + if(params == null) { + Log.logMessage("ParseExpression", SeverityLevel.ERROR, false, "params is null"); + return null; + } + if (params.containsKey(expression)) { + return params.get(expression); } File[] files = null; if (!(params.get(FILES) instanceof File[])) { @@ -401,10 +485,10 @@ public synchronized static Object eval(String f, Map params) { if (files != null) { for (File file : files) { if (file.isFile()) { - rfiles.add(file); + rFiles.add(file); } else { try { - Disk.listRecursiveFiles(file, rfiles); + Disk.listRecursiveFiles(file, rFiles); } catch (Exception e) { Log.logException(true, e); } @@ -412,16 +496,15 @@ public synchronized static Object eval(String f, Map params) { } } - Parser o = new Parser(rfiles.toArray(new File[rfiles.size()])); - if (f.startsWith("`") && f.endsWith("`")) { - f = f.substring(1, f.length() - 1); + Parser o = new Parser(rFiles.toArray(new File[0])); + if (expression.startsWith("`") && expression.endsWith("`")) { + expression = expression.substring(1, expression.length() - 1); } - String ie = importExpression(f); + String ie = importExpression(expression); out = exportObject(CallAlgebra(o, ie)); Log.logMessage("ParseExpression", SeverityLevel.INFO, false, " >> " + out); } catch (Exception e) { - Log.logException(false, new Exception(e.getClass()+": Failed to evaluate expression " + f + " on files " + rfiles + "\n" + e.getMessage())); - if (Log.level>=10) e.printStackTrace(); + Log.logException(false, new Exception(e.getClass()+": Failed to evaluate expression " + expression + " on files " + rFiles + "\n" + e.getMessage())); } return out; } diff --git a/src/test/java/org/funz/script/ParseExpressionTest.java b/src/test/java/org/funz/script/ParseExpressionTest.java index 71b7448..b01908f 100644 --- a/src/test/java/org/funz/script/ParseExpressionTest.java +++ b/src/test/java/org/funz/script/ParseExpressionTest.java @@ -2,9 +2,9 @@ import java.io.File; import java.io.FilenameFilter; -import java.util.Calendar; -import java.util.HashMap; -import java.util.LinkedList; +import java.net.URL; +import java.util.*; + import org.funz.util.Data; import org.funz.util.Format; import static org.funz.util.Format.repeat; @@ -14,7 +14,7 @@ public class ParseExpressionTest { - public static void main(String args[]) { + public static void main(String[] args) { org.junit.runner.JUnitCore.main(ParseExpressionTest.class.getName()); } @@ -26,19 +26,16 @@ public void testParseExpression() throws Exception { LinkedList expressions; LinkedList results; - params = new HashMap(); + params = new HashMap<>(); params.put(ParseExpression.FILES, new File("./src/test/samples/").listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return !name.startsWith("."); } })); - /*for (File f : (File[]) params.get(JavaParseExpression.FILES)) { - System.out.println(f.getName()); - }*/ - expressions = new LinkedList(); - results = new LinkedList(); + expressions = new LinkedList<>(); + results = new LinkedList<>(); expressions.add("CSV(\"toto.csv\",\",\")>>asString()"); results.add("{a=[1.0,2.0,3.0],b=[4.0,5.0,6.0],c=[7.0,8.0,9.0]}"); @@ -147,12 +144,10 @@ public void testCall() throws Exception { LinkedList expressions; LinkedList results; - Parser p = new Parser(new File[0]); - expressions = new LinkedList(); - results = new LinkedList(); + Parser p = new Parser(); - expressions = new LinkedList(); - results = new LinkedList(); + expressions = new LinkedList<>(); + results = new LinkedList<>(); expressions.add("1+1"); results.add(2.0); @@ -182,7 +177,7 @@ public void testCall() throws Exception { Object res = results.get(i); long tic = Calendar.getInstance().getTimeInMillis(); - Object o = null; + Object o; try { o = ParseExpression.CallAlgebra(p, ex); System.err.println(o); @@ -287,6 +282,150 @@ public void testSerialLogic() { } + @Test + public void testConcatString() { + System.err.println("testStringConcat"); + testEvalEquality("concatString('1','1')", "11"); + testEvalInequality("concatString('1','1')", 2); + } + + @Test + public void testDoubleToInt() { + System.err.println("testDoubleToInt"); + testEvalEquality("doubleToInt(2.3)", 2); + testEvalEquality("doubleToInt(2.0)", 2); + testEvalEquality("doubleToInt(1.9)", 1); + testEvalInequality("doubleToInt(1.9)", 2); + } + + @Test + public void testBooleanComparison() { + System.err.println("testBooleanComparison"); + testEvalEquality("1 > 2", false); + testEvalEquality("1 < 2", true); + testEvalInequality("1 > 2", true); + testEvalEquality("asNumeric(\"1.2\")", 1.2); + testEvalEquality("asNumeric(\"1.2\") < 2", true); + testEvalEquality("asNumeric(\"1.2\") > asNumeric(\"1.2\")", false); + } + + @Test + public void testBooleanConversion() { + System.err.println("testBooleanConversion"); + testEvalEquality("asNumeric(1>2)", 0.0); + testEvalEquality("asNumeric(1<2)", 1.0); + testEvalInequality("asNumeric(1>2)", 1.0); + testEvalEquality("asNumeric(asNumeric(\"1.2\") > asNumeric(\"1.2\"))", 0.0); + } + + @Test + public void testBetween() { + System.err.println("testBetween"); + testEvalEquality("between(\"1abc2\", \"1\", \"2\")", "abc"); + testEvalInequality("between(\"1abc2\", \"1\", \"2\")", "1abc2"); + testEvalEquality("between(\"1abc2\", \"1\", \"2\")", "a>bc"); + testEvalEquality("between(\"1a+bc2\", \"1\", \"2\")", "a+bc"); + testEvalEquality("between(\"1a-bc2\", \"1\", \"2\")", "a-bc"); + testEvalEquality("between(\"1a*bc2\", \"1\", \"2\")", "a*bc"); + testEvalEquality("between(\"1a/bc2\", \"1\", \"2\")", "a/bc"); + testEvalEquality("between(\"+1a/bc-2\", \"+1\", \"-2\")", "a/bc"); + testEvalEquality("between(\"<1a/bc>2\", \"<1\", \">2\")", "a/bc"); + testEvalEquality("between(1abc2, 1a, c2)", "b"); + testEvalEquality("between(\".10000000E+31 .20000000E+31 .30000000E+31 <\\mean>\", \"\", \" \")", ".10000000E+31"); + testEvalEquality("between(\".10000000E+31 .20000000E+31 .30000000E+31 <\\mean>\", \"\", \" \")", ".10000000E+31"); + } + + @Test + public void testReturnIf() { + System.err.println("returnIf"); + testEvalEquality("returnIf(1>2, \"a\", \"b\")", "b"); + testEvalEquality("returnIf(1<2, \"a\", \"b\")", "a"); + testEvalInequality("returnIf(1>2, \"a\", \"b\")", "a"); + testEvalEquality("returnIf(asNumeric(\"1.2\") > asNumeric(\"1.2\"), \"a\", \"b\")", "b"); + } + + /** + * Test if the evaluation of an expression is equals to the expected result + * + * @param expr expression to evaluate + * @param expected expected result + */ + private static void testEvalEquality(String expr, Object expected) { + testEvalEquality(expr, expected, null); + } + + /** + * Test if the evaluation of an expression is equals to the expected result + * + * @param expr expression to evaluate + * @param expected expected result + */ + private static void testEvalEquality(String expr, Object expected, File file) { + Map fileMap = Data.newMap("files", new File[]{file}); + Object evalRes = ParseExpression.eval(expr, fileMap); + assert expected.equals(evalRes) : "Result not matching when eval " + expr + ": [" + evalRes + "] != [" + expected + "] "; + } + + + @Test + public void testXpath() { + File xmlFile = loadTestXmlFile(); + assert Parser.XPath(xmlFile, "/calculation/keff/esti[@name=\"SOURCE-COLLISION\"]/mean").equals(".99580215 .99584567 .99587032 .99586262 ") : "XPath evaluation failed"; + } + + private static File loadTestXmlFile() { + // Load xpath-test.xml from resources + String testFileName = "xpath-test.xml"; + URL resource = ParseExpressionTest.class.getClassLoader().getResource(testFileName); + + File xmlFile; + if (resource != null) { + xmlFile = new File(resource.getFile()); + System.out.println("Found file: " + xmlFile.getAbsolutePath()); + } else { + System.out.println("File not found!"); + throw new RuntimeException("XML file not found: " + testFileName); + + } + return xmlFile; + } + + @Test + public void testExtractMinStdValues() { + File xmlFile = loadTestXmlFile(); + String expectedMean = ".19580215"; + String expectedStd = ".56892243E-03"; + List meanAndStdList = Parser.extractMinValues( + xmlFile, + "/calculation/keff/esti", + "mean", + "std"); + assert meanAndStdList.size() == 2 : "Expected 2 values, got: " + meanAndStdList.size(); + assert meanAndStdList.get(0).equals(expectedMean) : "Expected " + expectedMean +", got: " + meanAndStdList.get(0); + assert meanAndStdList.get(1).equals(expectedStd) : "Expected " + expectedStd + ", got: " + meanAndStdList.get(1); + + List expectResult = new ArrayList<>(); + expectResult.add(expectedMean); + expectResult.add(expectedStd); + + testEvalEquality("extractMinValues(\"" + xmlFile.getAbsolutePath() + "\", \"/calculation/keff/esti\", \"mean\", \"std\")", expectResult, xmlFile); + testEvalEquality("extractMinValues(\"" + xmlFile.getAbsolutePath() + "\", \"/calculation/keff/esti\", \"mean\", \"std\") >> get(1)", expectedMean, xmlFile); + testEvalEquality("extractMinValues(\"" + xmlFile.getAbsolutePath() + "\", \"/calculation/keff/esti\", \"mean\", \"std\") >> get(0)", expectedStd, xmlFile); + } + + /** + * Test the evaluation of an expression is not equals to the expected result + * + * @param expr expression to evaluate + * @param expected not expected result + */ + private static void testEvalInequality(String expr, Object expected) { + Object evalRes = ParseExpression.eval(expr, new HashMap<>()); + assert !expected.equals(evalRes) : "Result SHOULD NOT match when eval " + expr + ": [" + evalRes + "] == [" + expected + "] "; + + } + @Test public void testCallMethod() throws Exception { System.err.println("testCallMethod"); @@ -294,12 +433,10 @@ public void testCallMethod() throws Exception { LinkedList expressions; LinkedList results; - Parser p = new Parser(new File[0]); - expressions = new LinkedList(); - results = new LinkedList(); + Parser p = new Parser(); - expressions = new LinkedList(); - results = new LinkedList(); + expressions = new LinkedList<>(); + results = new LinkedList<>(); // test basic algebra expressions.add("1+1"); @@ -368,7 +505,7 @@ public void testCallMethod() throws Exception { Object res = results.get(i); long tic = Calendar.getInstance().getTimeInMillis(); - Object o = null; + Object o; try { o = ParseExpression.CallMethod(p, ex); System.err.println(o); @@ -382,7 +519,7 @@ public void testCallMethod() throws Exception { if (o == null && res != null) { throw new Exception("Parsing returned null !"); } else { - if (o != null || res != null) { + if (o != null) { String ostr = o.toString(); if (o instanceof double[]) { ostr = ArrayString.printDoubleArray((double[]) o); diff --git a/src/test/resources/xpath-test.xml b/src/test/resources/xpath-test.xml new file mode 100644 index 0000000..2232986 --- /dev/null +++ b/src/test/resources/xpath-test.xml @@ -0,0 +1,13 @@ + + + + + .99580215 .99584567 .99587032 .99586262 + .66892243E-03 .66841771E-03 .66887750E-03 + + + .19580215 .99584567 .99587032 .99586262 + .56892243E-03 .66841771E-03 .66887750E-03 + + + \ No newline at end of file diff --git a/src/test/test.iml b/src/test/test.iml new file mode 100644 index 0000000..f6f5fcb --- /dev/null +++ b/src/test/test.iml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file