vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 07 Dec 2012 10:35:31 +0100
changeset 280 21c0cf272b05
parent 273 59b9f9f5364f
child 284 58bd38caf70d
child 296 fbf8eb98a8ef
permissions -rw-r--r--
Specify dependency between the test run and comparing the results
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.vm4brwsr;
    19 
    20 import java.lang.reflect.Method;
    21 import javax.script.Invocable;
    22 import javax.script.ScriptEngine;
    23 import javax.script.ScriptEngineManager;
    24 import org.testng.Assert;
    25 import org.testng.ITest;
    26 import org.testng.annotations.Factory;
    27 import org.testng.annotations.Test;
    28 
    29 /** A TestNG {@link Factory} that seeks for {@link Compare} annotations
    30  * in provided class and builds set of tests that compare the computations
    31  * in real as well as JavaScript virtual machines. Use as:<pre>
    32  * {@code @}{@link Factory} public static create() {
    33  *   return @{link CompareVMs}.{@link #create(YourClass.class);
    34  * }</pre>
    35  *
    36  * @author Jaroslav Tulach <jtulach@netbeans.org>
    37  */
    38 public final class CompareVMs implements ITest {
    39     private final Run first, second;
    40     private final Method m;
    41     
    42     private CompareVMs(Method m, Run first, Run second) {
    43         this.first = first;
    44         this.second = second;
    45         this.m = m;
    46     }
    47 
    48     public static Object[] create(Class<?> clazz) {
    49         Method[] arr = clazz.getMethods();
    50         Object[] ret = new Object[3 * arr.length];
    51         int cnt = 0;
    52         for (Method m : arr) {
    53             Compare c = m.getAnnotation(Compare.class);
    54             if (c == null) {
    55                 continue;
    56             }
    57             final Run real = new Run(m, false);
    58             final Run js = new Run(m, true);
    59             ret[cnt++] = real;
    60             ret[cnt++] = js;
    61             ret[cnt++] = new CompareVMs(m, real, js);
    62         }
    63         Object[] r = new Object[cnt];
    64         for (int i = 0; i < cnt; i++) {
    65             r[i] = ret[i];
    66         }
    67         return r;
    68     }
    69     
    70     @Test(dependsOnGroups = "run") public void compareResults() throws Throwable {
    71         Object v1 = first.value;
    72         Object v2 = second.value;
    73         if (v1 instanceof Number) {
    74             v1 = ((Number)v1).doubleValue();
    75         }
    76         Assert.assertEquals(v1, v2, "Comparing results");
    77     }
    78     
    79     @Override
    80     public String getTestName() {
    81         return m.getName() + "[Compare]";
    82     }
    83     
    84     public static final class Run implements ITest {
    85         private final Method m;
    86         private final boolean js;
    87         Object value;
    88         private static Invocable code;
    89         private static CharSequence codeSeq;
    90 
    91         private Run(Method m, boolean js) {
    92             this.m = m;
    93             this.js = js;
    94         }
    95 
    96         private static void compileTheCode(Class<?> clazz) throws Exception {
    97             if (code != null) {
    98                 return;
    99             }
   100             StringBuilder sb = new StringBuilder();
   101             class SkipMe extends GenJS {
   102 
   103                 public SkipMe(Appendable out) {
   104                     super(out);
   105                 }
   106 
   107                 @Override
   108                 protected boolean requireReference(String cn) {
   109                     if (cn.contains("CompareVMs")) {
   110                         return true;
   111                     }
   112                     return super.requireReference(cn);
   113                 }
   114             }
   115             SkipMe sm = new SkipMe(sb);
   116             sm.doCompile(CompareVMs.class.getClassLoader(), StringArray.asList(
   117                 clazz.getName().replace('.', '/')));
   118 
   119             ScriptEngineManager sem = new ScriptEngineManager();
   120             ScriptEngine js = sem.getEngineByExtension("js");
   121 
   122             Object res = js.eval(sb.toString());
   123             Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
   124             code = (Invocable) js;
   125             codeSeq = sb;
   126         }
   127 
   128         @Test(groups = "run") public void executeCode() throws Throwable {
   129             if (js) {
   130                 try {
   131                     compileTheCode(m.getDeclaringClass());
   132                     Object inst = code.invokeFunction(m.getDeclaringClass().getName().replace('.', '_'), false);
   133                     value = code.invokeMethod(inst, m.getName() + "__I");
   134                 } catch (Exception ex) {
   135                     throw new AssertionError(StaticMethodTest.dumpJS(codeSeq)).initCause(ex);
   136                 }
   137             } else {
   138                 value = m.invoke(m.getDeclaringClass().newInstance());
   139             }
   140         }
   141         @Override
   142         public String getTestName() {
   143             return m.getName() + (js ? "[JavaScript]" : "[Java]");
   144         }
   145     }
   146 }