vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 06 Dec 2012 21:54:40 +0100
branchlazyvm
changeset 275 6e8422eca1ed
parent 273 59b9f9f5364f
child 276 aeb9fe11cd60
permissions -rw-r--r--
Access the method via bck2brwsr
     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 Method m;
    40     private final boolean js;
    41     private final CompareVMs first, second;
    42     private Object value;
    43     private static Invocable code;
    44     private static CharSequence codeSeq;
    45     
    46     private CompareVMs(Method m, boolean js) {
    47         this.m = m;
    48         this.js = js;
    49         this.first = null;
    50         this.second = null;
    51     }
    52 
    53     private CompareVMs(Method m, CompareVMs first, CompareVMs second) {
    54         this.first = first;
    55         this.second = second;
    56         this.m = m;
    57         this.js = false;
    58     }
    59     
    60     private static void compileTheCode(Class<?> clazz) throws Exception {
    61         if (code != null) {
    62             return;
    63         }
    64         StringBuilder sb = new StringBuilder();
    65         class SkipMe extends GenJS {
    66             public SkipMe(Appendable out) {
    67                 super(out);
    68             }
    69 
    70             @Override
    71             protected boolean requireReference(String cn) {
    72                 if (cn.contains("CompareVMs")) {
    73                     return true;
    74                 }
    75                 return super.requireReference(cn);
    76             }
    77             
    78             
    79         }
    80         SkipMe sm = new SkipMe(sb);
    81         sm.doCompile(CompareVMs.class.getClassLoader(), StringArray.asList(
    82             clazz.getName().replace('.', '/')
    83         ));
    84         
    85         ScriptEngineManager sem = new ScriptEngineManager();
    86         ScriptEngine js = sem.getEngineByExtension("js");
    87         
    88         Object res = js.eval(sb.toString());
    89         Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
    90         code = (Invocable)js;
    91         codeSeq = sb;
    92     }
    93     
    94 
    95     public static Object[] create(Class<?> clazz) {
    96         Method[] arr = clazz.getMethods();
    97         Object[] ret = new Object[3 * arr.length];
    98         int cnt = 0;
    99         for (Method m : arr) {
   100             Compare c = m.getAnnotation(Compare.class);
   101             if (c == null) {
   102                 continue;
   103             }
   104             final CompareVMs real = new CompareVMs(m, false);
   105             final CompareVMs js = new CompareVMs(m, true);
   106             ret[cnt++] = real;
   107             ret[cnt++] = js;
   108             ret[cnt++] = new CompareVMs(m, real, js);
   109         }
   110         Object[] r = new Object[cnt];
   111         for (int i = 0; i < cnt; i++) {
   112             r[i] = ret[i];
   113         }
   114         return r;
   115     }
   116     
   117     @Test public void runTest() throws Throwable {
   118         if (first != null) {
   119             Object v1 = first.value;
   120             Object v2 = second.value;
   121             if (v1 instanceof Number) {
   122                 v1 = ((Number)v1).doubleValue();
   123             }
   124             Assert.assertEquals(v1, v2, "Comparing results");
   125         } else {
   126             if (js) {
   127                 try {
   128                     compileTheCode(m.getDeclaringClass());
   129                     Object vm = code.invokeFunction("bck2brwsr");
   130                     Object inst = code.invokeMethod(vm, "loadClass", m.getDeclaringClass().getName().replace('.', '_'));
   131                     value = code.invokeMethod(inst, m.getName() + "__I");
   132                 } catch (Exception ex) {
   133                     throw new AssertionError(StaticMethodTest.dumpJS(codeSeq)).initCause(ex);
   134                 }
   135             } else {
   136                 value = m.invoke(m.getDeclaringClass().newInstance());
   137             }
   138         }
   139     }
   140     
   141     @Override
   142     public String getTestName() {
   143         if (first != null) {
   144             return m.getName() + "[Compare]";
   145         }
   146         return m.getName() + (js ? "[JavaScript]" : "[Java]");
   147     }
   148 }