Moving the @Compare infrastructure into separate, reusable module launcher
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 17 Dec 2012 17:45:08 +0100
branchlauncher
changeset 346b671ac44bc55
parent 344 4adbde04e899
child 347 6f964a88e6c5
Moving the @Compare infrastructure into separate, reusable module
pom.xml
vm/src/test/java/org/apidesign/vm4brwsr/Compare.java
vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java
vm/src/test/java/org/apidesign/vm4brwsr/tck/CompareHashTest.java
vm/src/test/java/org/apidesign/vm4brwsr/tck/CompareStringsTest.java
vmtest/pom.xml
vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java
vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java
vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java
vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java
     1.1 --- a/pom.xml	Mon Dec 17 12:21:05 2012 +0100
     1.2 +++ b/pom.xml	Mon Dec 17 17:45:08 2012 +0100
     1.3 @@ -15,6 +15,7 @@
     1.4      <module>javap</module>
     1.5      <module>benchmarks</module>
     1.6      <module>launcher</module>
     1.7 +    <module>vmtest</module>
     1.8    </modules>
     1.9    <licenses>
    1.10        <license>
    1.11 @@ -109,5 +110,4 @@
    1.12    <properties>
    1.13        <license>COPYING</license>
    1.14    </properties>
    1.15 -</project>
    1.16 -
    1.17 +</project>
    1.18 \ No newline at end of file
     2.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/Compare.java	Mon Dec 17 12:21:05 2012 +0100
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,36 +0,0 @@
     2.4 -/**
     2.5 - * Back 2 Browser Bytecode Translator
     2.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.7 - *
     2.8 - * This program is free software: you can redistribute it and/or modify
     2.9 - * it under the terms of the GNU General Public License as published by
    2.10 - * the Free Software Foundation, version 2 of the License.
    2.11 - *
    2.12 - * This program is distributed in the hope that it will be useful,
    2.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 - * GNU General Public License for more details.
    2.16 - *
    2.17 - * You should have received a copy of the GNU General Public License
    2.18 - * along with this program. Look for COPYING file in the top folder.
    2.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    2.20 - */
    2.21 -package org.apidesign.vm4brwsr;
    2.22 -
    2.23 -import java.lang.annotation.ElementType;
    2.24 -import java.lang.annotation.Retention;
    2.25 -import java.lang.annotation.RetentionPolicy;
    2.26 -import java.lang.annotation.Target;
    2.27 -
    2.28 -/** Can be applied on a method that yields a return value. 
    2.29 - * Together with {@link VMCompare#create} it can be used to write
    2.30 - * methods which are executed in real as well as JavaScript VMs and
    2.31 - * their results are compared.
    2.32 - *
    2.33 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.34 - */
    2.35 -@Retention(RetentionPolicy.RUNTIME)
    2.36 -@Target(ElementType.METHOD)
    2.37 -public @interface Compare {
    2.38 -    
    2.39 -}
     3.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java	Mon Dec 17 12:21:05 2012 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,197 +0,0 @@
     3.4 -/**
     3.5 - * Back 2 Browser Bytecode Translator
     3.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     3.7 - *
     3.8 - * This program is free software: you can redistribute it and/or modify
     3.9 - * it under the terms of the GNU General Public License as published by
    3.10 - * the Free Software Foundation, version 2 of the License.
    3.11 - *
    3.12 - * This program is distributed in the hope that it will be useful,
    3.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 - * GNU General Public License for more details.
    3.16 - *
    3.17 - * You should have received a copy of the GNU General Public License
    3.18 - * along with this program. Look for COPYING file in the top folder.
    3.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    3.20 - */
    3.21 -package org.apidesign.vm4brwsr;
    3.22 -
    3.23 -import java.lang.reflect.Method;
    3.24 -import java.util.Map;
    3.25 -import java.util.WeakHashMap;
    3.26 -import javax.script.Invocable;
    3.27 -import javax.script.ScriptContext;
    3.28 -import javax.script.ScriptEngine;
    3.29 -import javax.script.ScriptEngineManager;
    3.30 -import org.testng.Assert;
    3.31 -import org.testng.ITest;
    3.32 -import org.testng.annotations.Factory;
    3.33 -import org.testng.annotations.Test;
    3.34 -
    3.35 -/** A TestNG {@link Factory} that seeks for {@link Compare} annotations
    3.36 - * in provided class and builds set of tests that compare the computations
    3.37 - * in real as well as JavaScript virtual machines. Use as:<pre>
    3.38 - * {@code @}{@link Factory} public static create() {
    3.39 - *   return @{link CompareVMs}.{@link #create(YourClass.class);
    3.40 - * }</pre>
    3.41 - *
    3.42 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.43 - */
    3.44 -public final class CompareVMs implements ITest {
    3.45 -    private final Run first, second;
    3.46 -    private final Method m;
    3.47 -    
    3.48 -    private CompareVMs(Method m, Run first, Run second) {
    3.49 -        this.first = first;
    3.50 -        this.second = second;
    3.51 -        this.m = m;
    3.52 -    }
    3.53 -
    3.54 -    public static Object[] create(Class<?> clazz) {
    3.55 -        Method[] arr = clazz.getMethods();
    3.56 -        Object[] ret = new Object[3 * arr.length];
    3.57 -        int cnt = 0;
    3.58 -        for (Method m : arr) {
    3.59 -            Compare c = m.getAnnotation(Compare.class);
    3.60 -            if (c == null) {
    3.61 -                continue;
    3.62 -            }
    3.63 -            final Run real = new Run(m, false);
    3.64 -            final Run js = new Run(m, true);
    3.65 -            ret[cnt++] = real;
    3.66 -            ret[cnt++] = js;
    3.67 -            ret[cnt++] = new CompareVMs(m, real, js);
    3.68 -        }
    3.69 -        Object[] r = new Object[cnt];
    3.70 -        for (int i = 0; i < cnt; i++) {
    3.71 -            r[i] = ret[i];
    3.72 -        }
    3.73 -        return r;
    3.74 -    }
    3.75 -    
    3.76 -    @Test(dependsOnGroups = "run") public void compareResults() throws Throwable {
    3.77 -        Object v1 = first.value;
    3.78 -        Object v2 = second.value;
    3.79 -        if (v1 instanceof Number) {
    3.80 -            v1 = ((Number)v1).doubleValue();
    3.81 -        }
    3.82 -        Assert.assertEquals(v2, v1, "Comparing results");
    3.83 -    }
    3.84 -    
    3.85 -    @Override
    3.86 -    public String getTestName() {
    3.87 -        return m.getName() + "[Compare]";
    3.88 -    }
    3.89 -    
    3.90 -    public static final class Run implements ITest {
    3.91 -        private final Method m;
    3.92 -        private final boolean js;
    3.93 -        Object value;
    3.94 -        private Invocable code;
    3.95 -        private CharSequence codeSeq;
    3.96 -        private static final Map<Class,Object[]> compiled = new WeakHashMap<Class,Object[]>();
    3.97 -
    3.98 -        private Run(Method m, boolean js) {
    3.99 -            this.m = m;
   3.100 -            this.js = js;
   3.101 -        }
   3.102 -
   3.103 -        private void compileTheCode(Class<?> clazz) throws Exception {
   3.104 -            final Object[] data = compiled.get(clazz);
   3.105 -            if (data != null) {
   3.106 -                code = (Invocable) data[0];
   3.107 -                codeSeq = (CharSequence) data[1];
   3.108 -                return;
   3.109 -            }
   3.110 -            StringBuilder sb = new StringBuilder();
   3.111 -            Bck2Brwsr.generate(sb, CompareVMs.class.getClassLoader());
   3.112 -
   3.113 -            ScriptEngineManager sem = new ScriptEngineManager();
   3.114 -            ScriptEngine js = sem.getEngineByExtension("js");
   3.115 -            js.getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
   3.116 -            
   3.117 -            sb.append("\nfunction initVM() {"
   3.118 -                + "\n  return bck2brwsr("
   3.119 -                + "\n    function(name) { return loader.get(name);}"
   3.120 -                + "\n  );"
   3.121 -                + "\n};");
   3.122 -
   3.123 -            Object res = js.eval(sb.toString());
   3.124 -            Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
   3.125 -            code = (Invocable) js;
   3.126 -            codeSeq = sb;
   3.127 -            compiled.put(clazz, new Object[] { code, codeSeq });
   3.128 -        }
   3.129 -
   3.130 -        @Test(groups = "run") public void executeCode() throws Throwable {
   3.131 -            if (js) {
   3.132 -                try {
   3.133 -                    compileTheCode(m.getDeclaringClass());
   3.134 -                    Object vm = code.invokeFunction("initVM");
   3.135 -                    Object inst = code.invokeMethod(vm, "loadClass", m.getDeclaringClass().getName());
   3.136 -                    value = code.invokeMethod(inst, m.getName() + "__" + computeSignature(m));
   3.137 -                } catch (Exception ex) {
   3.138 -                    throw new AssertionError(StaticMethodTest.dumpJS(codeSeq)).initCause(ex);
   3.139 -                }
   3.140 -            } else {
   3.141 -                value = m.invoke(m.getDeclaringClass().newInstance());
   3.142 -            }
   3.143 -        }
   3.144 -        @Override
   3.145 -        public String getTestName() {
   3.146 -            return m.getName() + (js ? "[JavaScript]" : "[Java]");
   3.147 -        }
   3.148 -        
   3.149 -        private static String computeSignature(Method m) {
   3.150 -            StringBuilder sb = new StringBuilder();
   3.151 -            appendType(sb, m.getReturnType());
   3.152 -            for (Class<?> c : m.getParameterTypes()) {
   3.153 -                appendType(sb, c);
   3.154 -            }
   3.155 -            return sb.toString();
   3.156 -        }
   3.157 -        
   3.158 -        private static void appendType(StringBuilder sb, Class<?> t) {
   3.159 -            if (t == null) {
   3.160 -                sb.append('V');
   3.161 -                return;
   3.162 -            }
   3.163 -            if (t.isPrimitive()) {
   3.164 -                int ch = -1;
   3.165 -                if (t == int.class) {
   3.166 -                    ch = 'I';
   3.167 -                }
   3.168 -                if (t == short.class) {
   3.169 -                    ch = 'S';
   3.170 -                }
   3.171 -                if (t == byte.class) {
   3.172 -                    ch = 'B';
   3.173 -                }
   3.174 -                if (t == boolean.class) {
   3.175 -                    ch = 'Z';
   3.176 -                }
   3.177 -                if (t == long.class) {
   3.178 -                    ch = 'J';
   3.179 -                }
   3.180 -                if (t == float.class) {
   3.181 -                    ch = 'F';
   3.182 -                }
   3.183 -                if (t == double.class) {
   3.184 -                    ch = 'D';
   3.185 -                }
   3.186 -                assert ch != -1 : "Unknown primitive type " + t;
   3.187 -                sb.append((char)ch);
   3.188 -                return;
   3.189 -            }
   3.190 -            if (t.isArray()) {
   3.191 -                sb.append("_3");
   3.192 -                appendType(sb, t.getComponentType());
   3.193 -                return;
   3.194 -            }
   3.195 -            sb.append('L');
   3.196 -            sb.append(t.getName().replace('.', '_'));
   3.197 -            sb.append("_2");
   3.198 -        }
   3.199 -    }
   3.200 -}
     4.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/tck/CompareHashTest.java	Mon Dec 17 12:21:05 2012 +0100
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,42 +0,0 @@
     4.4 -/**
     4.5 - * Back 2 Browser Bytecode Translator
     4.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4.7 - *
     4.8 - * This program is free software: you can redistribute it and/or modify
     4.9 - * it under the terms of the GNU General Public License as published by
    4.10 - * the Free Software Foundation, version 2 of the License.
    4.11 - *
    4.12 - * This program is distributed in the hope that it will be useful,
    4.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.15 - * GNU General Public License for more details.
    4.16 - *
    4.17 - * You should have received a copy of the GNU General Public License
    4.18 - * along with this program. Look for COPYING file in the top folder.
    4.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    4.20 - */
    4.21 -package org.apidesign.vm4brwsr.tck;
    4.22 -
    4.23 -import org.apidesign.vm4brwsr.Compare;
    4.24 -import org.apidesign.vm4brwsr.CompareVMs;
    4.25 -import org.testng.annotations.Factory;
    4.26 -
    4.27 -/**
    4.28 - *
    4.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    4.30 - */
    4.31 -public class CompareHashTest {
    4.32 -    @Compare public int hashOfString() {
    4.33 -        return "Ahoj".hashCode();
    4.34 -    }
    4.35 -    
    4.36 -    @Compare public int hashRemainsYieldsZero() {
    4.37 -        Object o = new Object();
    4.38 -        return o.hashCode() - o.hashCode();
    4.39 -    }
    4.40 -    
    4.41 -    @Factory
    4.42 -    public static Object[] create() {
    4.43 -        return CompareVMs.create(CompareHashTest.class);
    4.44 -    }
    4.45 -}
     5.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/tck/CompareStringsTest.java	Mon Dec 17 12:21:05 2012 +0100
     5.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.3 @@ -1,110 +0,0 @@
     5.4 -/**
     5.5 - * Back 2 Browser Bytecode Translator
     5.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5.7 - *
     5.8 - * This program is free software: you can redistribute it and/or modify
     5.9 - * it under the terms of the GNU General Public License as published by
    5.10 - * the Free Software Foundation, version 2 of the License.
    5.11 - *
    5.12 - * This program is distributed in the hope that it will be useful,
    5.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    5.15 - * GNU General Public License for more details.
    5.16 - *
    5.17 - * You should have received a copy of the GNU General Public License
    5.18 - * along with this program. Look for COPYING file in the top folder.
    5.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    5.20 - */
    5.21 -package org.apidesign.vm4brwsr.tck;
    5.22 -
    5.23 -import java.net.MalformedURLException;
    5.24 -import java.net.URL;
    5.25 -import org.apidesign.vm4brwsr.Compare;
    5.26 -import org.apidesign.vm4brwsr.CompareVMs;
    5.27 -import org.testng.annotations.Factory;
    5.28 -
    5.29 -/**
    5.30 - *
    5.31 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.32 - */
    5.33 -public class CompareStringsTest {
    5.34 -    @Compare public static Object compareURLs() throws MalformedURLException {
    5.35 -        return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
    5.36 -    }
    5.37 -    
    5.38 -    @Compare public String deleteLastTwoCharacters() {
    5.39 -        StringBuilder sb = new StringBuilder();
    5.40 -        sb.append("453.0");
    5.41 -        if (sb.toString().endsWith(".0")) {
    5.42 -            final int l = sb.length();
    5.43 -            sb.delete(l - 2, l);
    5.44 -        }
    5.45 -        return sb.toString().toString();
    5.46 -    }
    5.47 -    
    5.48 -    @Compare public String nameOfStringClass() throws Exception {
    5.49 -        return Class.forName("java.lang.String").getName();
    5.50 -    }
    5.51 -    @Compare public String nameOfArrayClass() throws Exception {
    5.52 -        return Class.forName("org.apidesign.vm4brwsr.Array").getName();
    5.53 -    }
    5.54 -    
    5.55 -    @Compare public String lowerHello() {
    5.56 -        return "HeLlO".toLowerCase();
    5.57 -    }
    5.58 -    
    5.59 -    @Compare public String lowerA() {
    5.60 -        return String.valueOf(Character.toLowerCase('A')).toString();
    5.61 -    }
    5.62 -    @Compare public String upperHello() {
    5.63 -        return "hello".toUpperCase();
    5.64 -    }
    5.65 -    
    5.66 -    @Compare public String upperA() {
    5.67 -        return String.valueOf(Character.toUpperCase('a')).toString();
    5.68 -    }
    5.69 -    
    5.70 -    @Compare public boolean matchRegExp() throws Exception {
    5.71 -        return "58038503".matches("\\d*");
    5.72 -    }
    5.73 -
    5.74 -    @Compare public boolean doesNotMatchRegExp() throws Exception {
    5.75 -        return "58038503GH".matches("\\d*");
    5.76 -    }
    5.77 -
    5.78 -    @Compare public boolean doesNotMatchRegExpFully() throws Exception {
    5.79 -        return "Hello".matches("Hell");
    5.80 -    }
    5.81 -    
    5.82 -    @Compare public String variousCharacterTests() throws Exception {
    5.83 -        StringBuilder sb = new StringBuilder();
    5.84 -        
    5.85 -        sb.append(Character.isUpperCase('a'));
    5.86 -        sb.append(Character.isUpperCase('A'));
    5.87 -        sb.append(Character.isLowerCase('a'));
    5.88 -        sb.append(Character.isLowerCase('A'));
    5.89 -        
    5.90 -        sb.append(Character.isLetter('A'));
    5.91 -        sb.append(Character.isLetterOrDigit('9'));
    5.92 -        sb.append(Character.isLetterOrDigit('A'));
    5.93 -        sb.append(Character.isLetter('0'));
    5.94 -        
    5.95 -        return sb.toString().toString();
    5.96 -    }
    5.97 -        
    5.98 -    @Compare
    5.99 -    public String nullFieldInitialized() {
   5.100 -        NullField nf = new NullField();
   5.101 -        return ("" + nf.name).toString();
   5.102 -    }
   5.103 -
   5.104 -    @Factory
   5.105 -    public static Object[] create() {
   5.106 -        return CompareVMs.create(CompareStringsTest.class);
   5.107 -    }
   5.108 -
   5.109 -    private static final class NullField {
   5.110 -
   5.111 -        String name;
   5.112 -    }
   5.113 -}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/vmtest/pom.xml	Mon Dec 17 17:45:08 2012 +0100
     6.3 @@ -0,0 +1,56 @@
     6.4 +<?xml version="1.0"?>
     6.5 +<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
     6.6 +    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
     6.7 +  <modelVersion>4.0.0</modelVersion>
     6.8 +  <parent>
     6.9 +    <groupId>org.apidesign</groupId>
    6.10 +    <artifactId>bck2brwsr</artifactId>
    6.11 +    <version>0.3-SNAPSHOT</version>
    6.12 +  </parent>
    6.13 +  <groupId>org.apidesign.bck2brwsr</groupId>
    6.14 +  <artifactId>vmtest</artifactId>
    6.15 +  <version>0.3-SNAPSHOT</version>
    6.16 +  
    6.17 +  <name>VM Testing APIs</name>
    6.18 +  <url>http://bck2brwsr.apidesign.org</url>
    6.19 +    <build>
    6.20 +        <plugins>
    6.21 +            <plugin>
    6.22 +                <groupId>org.apache.maven.plugins</groupId>
    6.23 +                <artifactId>maven-compiler-plugin</artifactId>
    6.24 +                <version>2.3.2</version>
    6.25 +                <configuration>
    6.26 +                    <source>1.7</source>
    6.27 +                    <target>1.7</target>
    6.28 +                </configuration>
    6.29 +            </plugin>
    6.30 +        </plugins>
    6.31 +    </build>
    6.32 +    <properties>
    6.33 +    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    6.34 +  </properties>
    6.35 +  <dependencies>
    6.36 +    <dependency>
    6.37 +      <groupId>org.testng</groupId>
    6.38 +      <artifactId>testng</artifactId>
    6.39 +      <scope>compile</scope>
    6.40 +      <exclusions>
    6.41 +        <exclusion>
    6.42 +          <artifactId>junit</artifactId>
    6.43 +          <groupId>junit</groupId>
    6.44 +        </exclusion>
    6.45 +      </exclusions>
    6.46 +    </dependency>
    6.47 +    <dependency>
    6.48 +      <groupId>${project.groupId}</groupId>
    6.49 +      <artifactId>vm4brwsr</artifactId>
    6.50 +      <version>0.3-SNAPSHOT</version>
    6.51 +      <type>jar</type>
    6.52 +    </dependency>
    6.53 +    <dependency>
    6.54 +      <groupId>${project.groupId}</groupId>
    6.55 +      <artifactId>emul</artifactId>
    6.56 +      <version>0.3-SNAPSHOT</version>
    6.57 +    </dependency>
    6.58 +  </dependencies>
    6.59 +</project>
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/Compare.java	Mon Dec 17 17:45:08 2012 +0100
     7.3 @@ -0,0 +1,36 @@
     7.4 +/**
     7.5 + * Back 2 Browser Bytecode Translator
     7.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     7.7 + *
     7.8 + * This program is free software: you can redistribute it and/or modify
     7.9 + * it under the terms of the GNU General Public License as published by
    7.10 + * the Free Software Foundation, version 2 of the License.
    7.11 + *
    7.12 + * This program is distributed in the hope that it will be useful,
    7.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    7.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    7.15 + * GNU General Public License for more details.
    7.16 + *
    7.17 + * You should have received a copy of the GNU General Public License
    7.18 + * along with this program. Look for COPYING file in the top folder.
    7.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    7.20 + */
    7.21 +package org.apidesign.bck2brwsr.vmtest;
    7.22 +
    7.23 +import java.lang.annotation.ElementType;
    7.24 +import java.lang.annotation.Retention;
    7.25 +import java.lang.annotation.RetentionPolicy;
    7.26 +import java.lang.annotation.Target;
    7.27 +
    7.28 +/** Can be applied on a method that yields a return value. 
    7.29 + * Together with {@link VMTest#create} it can be used to write
    7.30 + * methods which are executed in real as well as JavaScript VMs and
    7.31 + * their results are compared.
    7.32 + *
    7.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    7.34 + */
    7.35 +@Retention(RetentionPolicy.RUNTIME)
    7.36 +@Target(ElementType.METHOD)
    7.37 +public @interface Compare {
    7.38 +    
    7.39 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java	Mon Dec 17 17:45:08 2012 +0100
     8.3 @@ -0,0 +1,254 @@
     8.4 +/**
     8.5 + * Back 2 Browser Bytecode Translator
     8.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     8.7 + *
     8.8 + * This program is free software: you can redistribute it and/or modify
     8.9 + * it under the terms of the GNU General Public License as published by
    8.10 + * the Free Software Foundation, version 2 of the License.
    8.11 + *
    8.12 + * This program is distributed in the hope that it will be useful,
    8.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    8.15 + * GNU General Public License for more details.
    8.16 + *
    8.17 + * You should have received a copy of the GNU General Public License
    8.18 + * along with this program. Look for COPYING file in the top folder.
    8.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    8.20 + */
    8.21 +package org.apidesign.bck2brwsr.vmtest;
    8.22 +
    8.23 +import java.io.File;
    8.24 +import java.io.FileWriter;
    8.25 +import java.io.IOException;
    8.26 +import java.io.InputStream;
    8.27 +import java.lang.reflect.Method;
    8.28 +import java.net.URL;
    8.29 +import java.util.Enumeration;
    8.30 +import java.util.Map;
    8.31 +import java.util.WeakHashMap;
    8.32 +import javax.script.Invocable;
    8.33 +import javax.script.ScriptEngine;
    8.34 +import javax.script.ScriptEngineManager;
    8.35 +import org.apidesign.vm4brwsr.Bck2Brwsr;
    8.36 +import org.testng.Assert;
    8.37 +import org.testng.ITest;
    8.38 +import org.testng.annotations.Factory;
    8.39 +import org.testng.annotations.Test;
    8.40 +
    8.41 +/** A TestNG {@link Factory} that seeks for {@link Compare} annotations
    8.42 + * in provided class and builds set of tests that compare the computations
    8.43 + * in real as well as JavaScript virtual machines. Use as:<pre>
    8.44 + * {@code @}{@link Factory} public static create() {
    8.45 + *   return @{link VMTest}.{@link #create(YourClass.class);
    8.46 + * }</pre>
    8.47 + *
    8.48 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    8.49 + */
    8.50 +public final class VMTest implements ITest {
    8.51 +    private final Run first, second;
    8.52 +    private final Method m;
    8.53 +    
    8.54 +    private VMTest(Method m, Run first, Run second) {
    8.55 +        this.first = first;
    8.56 +        this.second = second;
    8.57 +        this.m = m;
    8.58 +    }
    8.59 +
    8.60 +    /** Inspects <code>clazz</code> and for each {@lik Compare} method creates
    8.61 +     * instances of tests. Each insteance runs the test in different virtual
    8.62 +     * machine and at the end they compare the results.
    8.63 +     * 
    8.64 +     * @param clazz the class to inspect
    8.65 +     * @return the set of created tests
    8.66 +     */
    8.67 +    public static Object[] create(Class<?> clazz) {
    8.68 +        Method[] arr = clazz.getMethods();
    8.69 +        Object[] ret = new Object[3 * arr.length];
    8.70 +        int cnt = 0;
    8.71 +        for (Method m : arr) {
    8.72 +            Compare c = m.getAnnotation(Compare.class);
    8.73 +            if (c == null) {
    8.74 +                continue;
    8.75 +            }
    8.76 +            final Run real = new Run(m, false);
    8.77 +            final Run js = new Run(m, true);
    8.78 +            ret[cnt++] = real;
    8.79 +            ret[cnt++] = js;
    8.80 +            ret[cnt++] = new VMTest(m, real, js);
    8.81 +        }
    8.82 +        Object[] r = new Object[cnt];
    8.83 +        for (int i = 0; i < cnt; i++) {
    8.84 +            r[i] = ret[i];
    8.85 +        }
    8.86 +        return r;
    8.87 +    }
    8.88 +
    8.89 +    /** Test that compares the previous results.
    8.90 +     * @throws Throwable 
    8.91 +     */
    8.92 +    @Test(dependsOnGroups = "run") public void compareResults() throws Throwable {
    8.93 +        Object v1 = first.value;
    8.94 +        Object v2 = second.value;
    8.95 +        if (v1 instanceof Number) {
    8.96 +            v1 = ((Number)v1).doubleValue();
    8.97 +        }
    8.98 +        Assert.assertEquals(v2, v1, "Comparing results");
    8.99 +    }
   8.100 +    
   8.101 +    /** Test name.
   8.102 +     * @return name of the tested method followed by a suffix
   8.103 +     */
   8.104 +    @Override
   8.105 +    public String getTestName() {
   8.106 +        return m.getName() + "[Compare]";
   8.107 +    }
   8.108 +
   8.109 +    /** Helper method that inspects the classpath and loads given resource
   8.110 +     * (usually a class file). Used while running tests in Rhino.
   8.111 +     * 
   8.112 +     * @param name resource name to find
   8.113 +     * @return the array of bytes in the given resource
   8.114 +     * @throws IOException I/O in case something goes wrong
   8.115 +     */
   8.116 +    public static byte[] read(String name) throws IOException {
   8.117 +        URL u = null;
   8.118 +        Enumeration<URL> en = VMTest.class.getClassLoader().getResources(name);
   8.119 +        while (en.hasMoreElements()) {
   8.120 +            u = en.nextElement();
   8.121 +        }
   8.122 +        if (u == null) {
   8.123 +            throw new IOException("Can't find " + name);
   8.124 +        }
   8.125 +        try (InputStream is = u.openStream()) {
   8.126 +            byte[] arr;
   8.127 +            arr = new byte[is.available()];
   8.128 +            int offset = 0;
   8.129 +            while (offset < arr.length) {
   8.130 +                int len = is.read(arr, offset, arr.length - offset);
   8.131 +                if (len == -1) {
   8.132 +                    throw new IOException("Can't read " + name);
   8.133 +                }
   8.134 +                offset += len;
   8.135 +            }
   8.136 +            return arr;
   8.137 +        }
   8.138 +    }
   8.139 +   
   8.140 +    public static final class Run implements ITest {
   8.141 +        private final Method m;
   8.142 +        private final boolean js;
   8.143 +        Object value;
   8.144 +        private Invocable code;
   8.145 +        private CharSequence codeSeq;
   8.146 +        private static final Map<Class,Object[]> compiled = new WeakHashMap<Class,Object[]>();
   8.147 +
   8.148 +        private Run(Method m, boolean js) {
   8.149 +            this.m = m;
   8.150 +            this.js = js;
   8.151 +        }
   8.152 +
   8.153 +        private void compileTheCode(Class<?> clazz) throws Exception {
   8.154 +            final Object[] data = compiled.get(clazz);
   8.155 +            if (data != null) {
   8.156 +                code = (Invocable) data[0];
   8.157 +                codeSeq = (CharSequence) data[1];
   8.158 +                return;
   8.159 +            }
   8.160 +            StringBuilder sb = new StringBuilder();
   8.161 +            Bck2Brwsr.generate(sb, VMTest.class.getClassLoader());
   8.162 +
   8.163 +            ScriptEngineManager sem = new ScriptEngineManager();
   8.164 +            ScriptEngine js = sem.getEngineByExtension("js");
   8.165 +            
   8.166 +            sb.append("\nfunction initVM() {"
   8.167 +                + "\n  return bck2brwsr("
   8.168 +                + "\n    function(name) { return org.apidesign.bck2brwsr.vmtest.VMTest.read(name);}"
   8.169 +                + "\n  );"
   8.170 +                + "\n};");
   8.171 +
   8.172 +            Object res = js.eval(sb.toString());
   8.173 +            Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
   8.174 +            code = (Invocable) js;
   8.175 +            codeSeq = sb;
   8.176 +            compiled.put(clazz, new Object[] { code, codeSeq });
   8.177 +        }
   8.178 +
   8.179 +        @Test(groups = "run") public void executeCode() throws Throwable {
   8.180 +            if (js) {
   8.181 +                try {
   8.182 +                    compileTheCode(m.getDeclaringClass());
   8.183 +                    Object vm = code.invokeFunction("initVM");
   8.184 +                    Object inst = code.invokeMethod(vm, "loadClass", m.getDeclaringClass().getName());
   8.185 +                    value = code.invokeMethod(inst, m.getName() + "__" + computeSignature(m));
   8.186 +                } catch (Exception ex) {
   8.187 +                    throw new AssertionError(dumpJS(codeSeq)).initCause(ex);
   8.188 +                }
   8.189 +            } else {
   8.190 +                value = m.invoke(m.getDeclaringClass().newInstance());
   8.191 +            }
   8.192 +        }
   8.193 +        @Override
   8.194 +        public String getTestName() {
   8.195 +            return m.getName() + (js ? "[JavaScript]" : "[Java]");
   8.196 +        }
   8.197 +        
   8.198 +        private static String computeSignature(Method m) {
   8.199 +            StringBuilder sb = new StringBuilder();
   8.200 +            appendType(sb, m.getReturnType());
   8.201 +            for (Class<?> c : m.getParameterTypes()) {
   8.202 +                appendType(sb, c);
   8.203 +            }
   8.204 +            return sb.toString();
   8.205 +        }
   8.206 +        
   8.207 +        private static void appendType(StringBuilder sb, Class<?> t) {
   8.208 +            if (t == null) {
   8.209 +                sb.append('V');
   8.210 +                return;
   8.211 +            }
   8.212 +            if (t.isPrimitive()) {
   8.213 +                int ch = -1;
   8.214 +                if (t == int.class) {
   8.215 +                    ch = 'I';
   8.216 +                }
   8.217 +                if (t == short.class) {
   8.218 +                    ch = 'S';
   8.219 +                }
   8.220 +                if (t == byte.class) {
   8.221 +                    ch = 'B';
   8.222 +                }
   8.223 +                if (t == boolean.class) {
   8.224 +                    ch = 'Z';
   8.225 +                }
   8.226 +                if (t == long.class) {
   8.227 +                    ch = 'J';
   8.228 +                }
   8.229 +                if (t == float.class) {
   8.230 +                    ch = 'F';
   8.231 +                }
   8.232 +                if (t == double.class) {
   8.233 +                    ch = 'D';
   8.234 +                }
   8.235 +                assert ch != -1 : "Unknown primitive type " + t;
   8.236 +                sb.append((char)ch);
   8.237 +                return;
   8.238 +            }
   8.239 +            if (t.isArray()) {
   8.240 +                sb.append("_3");
   8.241 +                appendType(sb, t.getComponentType());
   8.242 +                return;
   8.243 +            }
   8.244 +            sb.append('L');
   8.245 +            sb.append(t.getName().replace('.', '_'));
   8.246 +            sb.append("_2");
   8.247 +        }
   8.248 +    }
   8.249 +    
   8.250 +    static StringBuilder dumpJS(CharSequence sb) throws IOException {
   8.251 +        File f = File.createTempFile("execution", ".js");
   8.252 +        FileWriter w = new FileWriter(f);
   8.253 +        w.append(sb);
   8.254 +        w.close();
   8.255 +        return new StringBuilder(f.getPath());
   8.256 +    }
   8.257 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java	Mon Dec 17 17:45:08 2012 +0100
     9.3 @@ -0,0 +1,42 @@
     9.4 +/**
     9.5 + * Back 2 Browser Bytecode Translator
     9.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     9.7 + *
     9.8 + * This program is free software: you can redistribute it and/or modify
     9.9 + * it under the terms of the GNU General Public License as published by
    9.10 + * the Free Software Foundation, version 2 of the License.
    9.11 + *
    9.12 + * This program is distributed in the hope that it will be useful,
    9.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    9.15 + * GNU General Public License for more details.
    9.16 + *
    9.17 + * You should have received a copy of the GNU General Public License
    9.18 + * along with this program. Look for COPYING file in the top folder.
    9.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    9.20 + */
    9.21 +package org.apidesign.bck2brwsr.tck;
    9.22 +
    9.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
    9.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
    9.25 +import org.testng.annotations.Factory;
    9.26 +
    9.27 +/**
    9.28 + *
    9.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    9.30 + */
    9.31 +public class CompareHashTest {
    9.32 +    @Compare public int hashOfString() {
    9.33 +        return "Ahoj".hashCode();
    9.34 +    }
    9.35 +    
    9.36 +    @Compare public int hashRemainsYieldsZero() {
    9.37 +        Object o = new Object();
    9.38 +        return o.hashCode() - o.hashCode();
    9.39 +    }
    9.40 +    
    9.41 +    @Factory
    9.42 +    public static Object[] create() {
    9.43 +        return VMTest.create(CompareHashTest.class);
    9.44 +    }
    9.45 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java	Mon Dec 17 17:45:08 2012 +0100
    10.3 @@ -0,0 +1,110 @@
    10.4 +/**
    10.5 + * Back 2 Browser Bytecode Translator
    10.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    10.7 + *
    10.8 + * This program is free software: you can redistribute it and/or modify
    10.9 + * it under the terms of the GNU General Public License as published by
   10.10 + * the Free Software Foundation, version 2 of the License.
   10.11 + *
   10.12 + * This program is distributed in the hope that it will be useful,
   10.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10.15 + * GNU General Public License for more details.
   10.16 + *
   10.17 + * You should have received a copy of the GNU General Public License
   10.18 + * along with this program. Look for COPYING file in the top folder.
   10.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
   10.20 + */
   10.21 +package org.apidesign.bck2brwsr.tck;
   10.22 +
   10.23 +import java.net.MalformedURLException;
   10.24 +import java.net.URL;
   10.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
   10.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
   10.27 +import org.testng.annotations.Factory;
   10.28 +
   10.29 +/**
   10.30 + *
   10.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
   10.32 + */
   10.33 +public class CompareStringsTest {
   10.34 +    @Compare public static Object compareURLs() throws MalformedURLException {
   10.35 +        return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
   10.36 +    }
   10.37 +    
   10.38 +    @Compare public String deleteLastTwoCharacters() {
   10.39 +        StringBuilder sb = new StringBuilder();
   10.40 +        sb.append("453.0");
   10.41 +        if (sb.toString().endsWith(".0")) {
   10.42 +            final int l = sb.length();
   10.43 +            sb.delete(l - 2, l);
   10.44 +        }
   10.45 +        return sb.toString().toString();
   10.46 +    }
   10.47 +    
   10.48 +    @Compare public String nameOfStringClass() throws Exception {
   10.49 +        return Class.forName("java.lang.String").getName();
   10.50 +    }
   10.51 +    @Compare public String nameOfArrayClass() throws Exception {
   10.52 +        return Class.forName("org.apidesign.bck2brwsr.tck.CompareHashTest").getName();
   10.53 +    }
   10.54 +    
   10.55 +    @Compare public String lowerHello() {
   10.56 +        return "HeLlO".toLowerCase();
   10.57 +    }
   10.58 +    
   10.59 +    @Compare public String lowerA() {
   10.60 +        return String.valueOf(Character.toLowerCase('A')).toString();
   10.61 +    }
   10.62 +    @Compare public String upperHello() {
   10.63 +        return "hello".toUpperCase();
   10.64 +    }
   10.65 +    
   10.66 +    @Compare public String upperA() {
   10.67 +        return String.valueOf(Character.toUpperCase('a')).toString();
   10.68 +    }
   10.69 +    
   10.70 +    @Compare public boolean matchRegExp() throws Exception {
   10.71 +        return "58038503".matches("\\d*");
   10.72 +    }
   10.73 +
   10.74 +    @Compare public boolean doesNotMatchRegExp() throws Exception {
   10.75 +        return "58038503GH".matches("\\d*");
   10.76 +    }
   10.77 +
   10.78 +    @Compare public boolean doesNotMatchRegExpFully() throws Exception {
   10.79 +        return "Hello".matches("Hell");
   10.80 +    }
   10.81 +    
   10.82 +    @Compare public String variousCharacterTests() throws Exception {
   10.83 +        StringBuilder sb = new StringBuilder();
   10.84 +        
   10.85 +        sb.append(Character.isUpperCase('a'));
   10.86 +        sb.append(Character.isUpperCase('A'));
   10.87 +        sb.append(Character.isLowerCase('a'));
   10.88 +        sb.append(Character.isLowerCase('A'));
   10.89 +        
   10.90 +        sb.append(Character.isLetter('A'));
   10.91 +        sb.append(Character.isLetterOrDigit('9'));
   10.92 +        sb.append(Character.isLetterOrDigit('A'));
   10.93 +        sb.append(Character.isLetter('0'));
   10.94 +        
   10.95 +        return sb.toString().toString();
   10.96 +    }
   10.97 +        
   10.98 +    @Compare
   10.99 +    public String nullFieldInitialized() {
  10.100 +        NullField nf = new NullField();
  10.101 +        return ("" + nf.name).toString();
  10.102 +    }
  10.103 +
  10.104 +    @Factory
  10.105 +    public static Object[] create() {
  10.106 +        return VMTest.create(CompareStringsTest.class);
  10.107 +    }
  10.108 +
  10.109 +    private static final class NullField {
  10.110 +
  10.111 +        String name;
  10.112 +    }
  10.113 +}