/* * xtc - The eXTensible Compiler * Copyright (C) 2007 IBM Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package xtc.lang.jeannie; import java.io.StringWriter; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import xtc.lang.JavaEntities; import xtc.lang.JavaUnitTests; import xtc.tree.GNode; import xtc.tree.Node; import xtc.tree.Printer; import xtc.type.Type; import xtc.util.Runtime; import xtc.util.SymbolTable; /** * JUnit tests for classes in package xtc.lang.jeannie. * * This class is a good place to quickly try a method on some simple * inputs. The test cases also document how to use certain API and * what it does. * * To run from the console, set your CLASSPATH to include * $JAVA_DEV_ROOT/classes and junit.jar, then run * * java -ea junit.textui.TestRunner xtc.lang.jeannie.UnitTests * * Or, to run from within eclipse, Run -> Run ... -> JUnit -> New, and * specify xtc.lang.jeannie.UnitTests. * * @author Martin Hirzel * @version $Revision: 1.35 $ */ public final class UnitTests extends TestCase { static final class JeannieAnalyzerTestError extends JavaUnitTests.IgnorableTest { private final String _expected; private final String _input; private final String _language; private final String _production; JeannieAnalyzerTestError(final boolean ignore, final String production, final String language, final String input, final String expected) { super(ignore); _expected = expected; _input = input; _language = language; _production = production; } public void runTestIgnorable() throws Exception { final Analyzer ana = new Analyzer(Utilities.newRuntime(), new SymbolTable(), _language); if (!"File".equals(_production) && !"CompilationUnit".equals(_production) && !"TranslationUnit".equals(_production)) JavaUnitTests.enterPackageFile(ana._table, "", "<input>"); UnitTests.jeannieAnalyzerTestError(_production, _language, _input, _expected, ana); } } static final class JeannieCodeGeneratorTest extends JavaUnitTests.IgnorableTest { private final String _cExpected; private final String _input; private final String _javaExpected; private final String _language; private final String _production; JeannieCodeGeneratorTest(final boolean ignore, final String production, final String language, final String input) { super(ignore); _cExpected = null; _input = input; _javaExpected = null; _language = language; _production = production; } JeannieCodeGeneratorTest(final boolean ignore, final String production, final String language, final String input, final String cExpected, final String javaExpected) { super(ignore); _cExpected = cExpected; _input = input; _javaExpected = javaExpected; _language = language; _production = production; } public void runTestIgnorable() throws Exception { final GNode ast = Utilities.jeannieStringToAst(_production, _language, _input); final Runtime runtime = Utilities.newRuntime(); final SymbolTable tab = new SymbolTable(); final Analyzer ana = new Analyzer(runtime, tab, _language); ana.dispatch(ast); final CodeGenerator codeGenerator = new CodeGenerator(runtime, tab); final CodeGenerator.Out out = (CodeGenerator.Out)codeGenerator.dispatch(ast); assertTrue(null == out._cExternalDeclarations && null == out._cMembers && null == out._javaMembers); final String cCode = Utilities.cAstToString(out._cNode); final String javaCode = Utilities.javaAstToString(out._javaNode); assrtEquals(_cExpected, cCode); assrtEquals(_javaExpected, javaCode); } } static class JeannieParserTest extends JavaUnitTests.IgnorableTest { private final String _expected; private final String _input; private final String _language; private final String _production; JeannieParserTest(final boolean ignore, final String production, final String language, final String input) { super(ignore); _expected = input; _input = input; _language = language; _production = production; } public void runTestIgnorable() throws Exception { UnitTests.jeannieParserTestRoundTrip(_production, _language, _input, _expected, false); UnitTests.jeannieParserTestRoundTrip(_production, _language, _input, _expected, true); } } static void assrtEquals(final String expected, final String actual) { if (null == expected) return; final String e = JavaUnitTests.contractSpace(expected); final String a = JavaUnitTests.contractSpace(actual); if (e.equals(a)) return; assertEquals(e, a); } static void jeannieAnalyzerTestError(final String production, final String language, final String input, final String expected, final Analyzer ana) throws Exception { final StringWriter stringWriter = new StringWriter(); ana._runtime.setErrConsole(new Printer(stringWriter)); final GNode ast = Utilities.jeannieStringToAst(production, language, input); ana.dispatch(ast); final String output = trimAnalyzerOutput(stringWriter.toString()); assrtEquals(expected, output); } static String trimAnalyzerOutput(String output) { output = JavaUnitTests.stripPrefix(output, "error:"); final int warningPos = output.indexOf("warning:"); if (-1 != warningPos) output = output.substring(warningPos); output = JavaUnitTests.stripSuffix(output, "\n"); output = output.trim(); return output; } static void jeannieParserTestRoundTrip(final String production, final String language, final String input, final String expected, final boolean simple) throws Exception { final String unescaped = JavaEntities.unicodeUnescape(input); final GNode ast = Utilities.jeannieStringToAst(production, language, unescaped, simple); final String result = Utilities.jeannieAstToString(ast, language); final String exp = JavaUnitTests.contractSpace(JavaEntities.unicodeUnescape(expected)); assrtEquals(exp, result); } private static TestSuite makeSuiteJeannieAnalyzerError() { final TestSuite s = new TestSuite(); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{double y; }class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{enum e{a,b}y; }class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{enum e{a,b}y; }class A{long x=`y;}", "warning: converting C type 'annotated(enum e)' to Java type 'long'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{float y;}class A{double x=`y;}", "warning: converting C type 'annotated(float)' to Java type 'double'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{float y;}class A{float x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{float y;}class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int i=0;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int i=\"s\";}", "initializer for 'i' makes integer from pointer without a cast")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int y;}class A{int x=`&y;}", "illegal C type 'annotated(pointer(int))' in Java expression")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int y;}class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int y;}class A{long x=`y;}", "warning: converting C type 'annotated(int)' to Java type 'long'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int y[5];}class A{int x=`y;}", "illegal C type 'annotated(array(int, 5))' in Java expression")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{int* y;}class A{int x=`y;}", "illegal C type 'annotated(pointer(int))' in Java expression")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{long double y;}class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{long long y;}class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{struct s{}y;}class A{int x=`y;}", "illegal C type 'annotated(struct s)' in Java expression")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef float jfloat; float y; }class A{float x=`y;}", "warning: converting C type 'annotated(float)' to Java type 'float'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef float jfloat; jfloat y; }class A{float x=`y;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;typedef char jbyte;typedef int jint;extern int printf(__const char*__restrict __format,...);}class Main{public static void main(String[]args){String js=\"abc\";`{jbyte*bs;_with(bs=`js){printf(\"%*s\\n\",bs,`js.length());}}}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;typedef int jintArray;}class A{native int[]f()`{jintArray a;return a;}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;typedef void* jstring;}class A{native void f()`{jstring s=_newJavaString(123);}}", "expected pointer to char, `byte, or `char")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;typedef void* jstring;}class A{native void f()`{jstring s=_newJavaString(\"hi\");}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;void f(JNIEnv*env){`{{System.out.println();}}}}class A{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;void f(JNIEnv*env){`{try{}catch(Error e){}}}}class A{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{int f(){int i;return `i;}}", "cannot use Java entity 'i' in C context")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{int f(){return env;}}", "cannot use C entity 'env' in Java context")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{int f(int i){return `i;}}", "cannot use Java entity 'i' in C context")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{int i;int f(){return `i;}}", "cannot use Java entity 'i' in C context")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{native void f()`{JNIEnv* e=env;}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{native void f(int env)`{}}", "formal parameter declaration of 'env' conflicts with implicit JNIEnv pointer")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int jint; int y; }class A{int x=`y;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int jint; jint i=0; typedef void* JNIEnv;} class A { int f(){return `i;} } ", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int jint; long y; }class A{long x=`y;}", "warning: converting C type 'annotated(long)' to Java type 'long'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef long jint; long y; }class A{int x=`y;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef unsigned char jboolean;jboolean b;}class A{boolean x=`b;} ", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef unsigned char jboolean;}class A{boolean x=`((jboolean)(2<3));} ", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef unsigned char jboolean;}class A{boolean x=`(2<3);} ", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void(*FP)(int);void g(FP fp){}void h(int i){}void f(){g(h);}}class A{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;typedef int jint;}class A{int f(){return `((jint)env);}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;}class A{native Exception f()`{return 123;}}", "return type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;}class A{native int f()`{return;}}", "'return' with no value, in method returning non-void")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;}class A{native void f()`{}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;}class A{void f(){if(true)`{int*p=0;}}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void* JNIEnv;}class A{void f(){if(true)`{int*p=3;}}}", "initializer for 'p' makes pointer from integer without a cast")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void*JNIEnv;typedef int jint;extern int printf(__const char* __restrict __format, ...);}class A{static native void f()`{jint a=0,b=0;b=`(1+`((jint)(a=1)));printf(\"%d,%d\\\\n\",a,b);}public static void main(String[]args){f();}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void*JNIEnv;typedef int jint;}class A{native int f()`{return (jint)1000;}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void*JNIEnv;typedef int jint;}class A{public static void main(String args[]){int a=0,b=0;b=`((jint)(1+`(a=1)));System.out.println(a+\",\"+b);}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void*JNIEnv;}class Main{native void f()`{int a[1]={3+5};}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef void*JNIEnv;}class Main{native void f()`{int a[1]={3};}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{union u{}y;}class A{int x=`y;}", "illegal C type 'annotated(union u)' in Java expression")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{unsigned y;}class A{int x=`y;}", "initializer type mismatch")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A extends B {}", "unknown class or interface B")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A{native void f();}", "methods should be abstract iff they have no body")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A{native void f()`{}}", "C typedef for 'JNIEnv' missing; did you forget to #include <jni.h>?")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A{native void f(){}}", "methods should be native iff their body is in C")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A{static{String b=\"x\";b=\"y\";}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{}class A{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.Java{import java.util.*;}typedef int JNIEnv;typedef void* jobject;jobject f(JNIEnv*env){return `((Vector)null);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.Java{import java.util.Vector;}int i=`0;", "C typedef for 'jint' missing; did you forget to #include <jni.h>?")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.Java{import java.util.Vector;}typedef int JNIEnv;typedef int jint;int f(JNIEnv*env){return `0;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.Java{import java.util.Vector;}typedef int JNIEnv;typedef void* jobject;jobject f(JNIEnv*env){return `((Vector)null);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`Exception e;", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "int f(){return 123;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "int i;void f(){_cancel i;}", "no enclosing _with statement for 'i'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "int i;void f(){_commit i;}", "no enclosing _with statement for 'i'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "package p;`.C{typedef int JNIEnv;void printf(char*);void fflush(int);int stdout;void f(JNIEnv*env){printf(\"f 1\\n\");fflush(stdout);`p.Main.g();printf(\"f 2\\n\");fflush(stdout);}}public class Main{public static void g(){System.out.println(\"Main.g\");System.out.flush();}public static void main(String[]args){System.out.println(\"Main.main 1\");System.out.flush();`f(env);System.out.println(\"Main.main 2\");System.out.flush();}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef char jboolean;typedef int jintArray;void f(){jboolean* ca;_with(ca=`new int[5]){}}", "type 'jint*' expected")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef double jdouble;jdouble f(JNIEnv*env){return `1.5;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jboolean;typedef int jbooleanArray;void f(JNIEnv*env){jboolean* ca;_with(ca=`new boolean[5]){}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jboolean;typedef int jobjectArray;void f(JNIEnv*env){jboolean* ca;_with(ca=`new String[5]){}}", "type 'jobject*' expected")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;int f(JNIEnv*env)`{return 123;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;typedef void* jintArray;void f(JNIEnv*env){jint* ca;_copyFromJava(ca, 0, `new int[5], 0, 3);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;typedef void* jintArray;void f(JNIEnv*env){jint* ca;_copyFromJava(ca, 0, `new int[5], 3-1, 2);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;typedef void* jintArray;void f(JNIEnv*env){jint* ca;_copyFromJava(ca, 0, `new int[5], 3.1, 3);}", "invalid operand where integer required")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;typedef void* jintArray;void f(JNIEnv*env){jint* ca;_with(ca=`new int[5]){_cancel ca;}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef int jint;typedef void* jintArray;void f(JNIEnv*env){jint* ca;_with(ca=`new int[5]){_commit ca;}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jobject;int f(JNIEnv*env){return `null;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jobject;jobject f(JNIEnv*env){return `((Vector)null);}", "unknown class or interface Vector")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jobject;jobject f(JNIEnv*env){return `null;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jobject;typedef jobject jthrowable;jobject f(JNIEnv*env){return `new Exception();}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;jstring f(JNIEnv*env){return `\"hi\";}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;jstring f(JNIEnv*env){return `new String(1,2,3,4,5);}", "could not find constructor")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef char jbyte;void f(JNIEnv*env){jbyte* ca;_with(ca=`\"abc\"){}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef int jchar;typedef int jint;void f(JNIEnv*env){jchar* ca;_copyFromJava(ca, 0, `\"abc\", 0, 3);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef int jchar;void f(JNIEnv*env){jchar* ca;_copyToJava(`\"abc\", 0, ca, 0, 3);}", "_copyToJava target must not be String")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef int jchar;void f(JNIEnv*env){jchar* ca;_with(ca=`'a'){}}", "string or primitive array expected")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef int jchar;void f(JNIEnv*env){jchar* ca;_with(ca=`(new Object().toString())){}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;typedef int jchar;void f(JNIEnv*env){jchar* ca;_with(ca=`\"abc\"){}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;void f(JNIEnv*env){int* ca;_with(ca=`\"abc\"){}}", "type 'jchar*' or 'jbyte*' expected")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jstring;void f(JNIEnv*env,jstring s)`{throw new Error(`s);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jthrowable;jthrowable f(JNIEnv*env){return `((Exception)null);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;typedef void* jthrowable;jthrowable f(JNIEnv*env){return `new Exception();}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws Exception{`throw new Exception();}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws Exception{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws Exception{}void g(){f(0);}", "uncaught exception")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws Object{}", "throwable expected")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws RuntimeException{}void g(){f(0);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws java.io.FileNotFoundException, java.io.EOFException{}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`throws java.io.IOException{}void g(JNIEnv*env)`throws Exception{f(env);}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env)`{throw new Error();}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`Exception x,y;x=y;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`Object x;`Exception y;x=y;}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`Object x;`Exception y;y=x;}", "illegal C assignment to Java type 'java.lang.Exception'")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`throw new Exception();}", "uncaught exception")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`try`{`throw new Exception();}catch(Exception e){}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){`{String s=\"hi\";}}", "")); s.addTest(new JeannieAnalyzerTestError(false, "File", null, "typedef int JNIEnv;void f(JNIEnv*env){int* x;`Object y;`{y=x;}}", "cannot use C entity 'y' in Java context")); return s; } private static TestSuite makeSuiteJeannieCodeGenerator() { final TestSuite s = new TestSuite(); s.addTest(new JeannieCodeGeneratorTest(false, "File" /* 000 hello world */, null, "`.C{typedef void* JNIEnv;extern int printf(__const char *__restrict __format,...);}class Main{static native void sayHi()`{printf(\"Hello world!\\n\");}public static void main(String[]args){sayHi();}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", /* 013 _with */ null, "`.C{typedef void* JNIEnv;typedef int jint;typedef char jboolean;typedef void* jintArray;}class Main{static native int sum(int[] ja)`{int i,n;jint* ca,s;n=`ja.length;s=0;_with(ca=`ja){for(i=0;i<n;i++)s+=ca[i];_cancel ca;}return s;}public static void main(String[] args){int[] a ={3,1,4};System.out.println(\"expected 8,got \" + sum(a));}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", /* 027 C function */ null, "`.C{typedef void* JNIEnv;struct L{struct L* x;};}class A{native void f()`{struct L* y=0;}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef char jbyte;typedef int jint;typedef void* jstring;typedef char jboolean;extern int printf(__const char*__restrict __format,...);}class Main{public static void main(String[]args){String js=\"abc\";`{jbyte*bs;_with(bs=`js){printf(\"%*s\\n\",bs,`js.length());}}}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef int jint;struct s{int i;}g;}class A{void f(){int j=`g.i;}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef int jlong;}class A{native int f()`{switch(0){case 0:``((jlong)1);}}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef int jstring;}class A{void f(){throw new Error(`_newJavaString(\"boo\"));}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef void* jstring;}class A{native void f()`{jstring s=_newJavaString(\"hi\");}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;void f(JNIEnv*env){`{int i;i=1;}}}class A{}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;void f(JNIEnv*env){`{int i;i=1;}}}class A{}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int jint;jint i=42;typedef void* JNIEnv;}class A{void f(){int j=0;j=`i;}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef void* JNIEnv;}class A{void f(){}}", "typedef void* JNIEnv;", "class A{void f(){}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{}class A{}", "", "class A{}")); s.addTest(new JeannieCodeGeneratorTest(false, "File",/* 002 callStatic */ null, "`.C{typedef void* JNIEnv;typedef int jint;extern int printf(__const char *__restrict __format,...);}class Main{native static void foo()`{int y;y=`Math.max(123,456);printf(\"return value: %d\\n\",y);}public static void main(String[]args){foo();}}")); s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "package p;`.C{typedef int JNIEnv;void printf(char*);void fflush(int);int stdout;void f(JNIEnv*env){printf(\"f 1\\n\");fflush(stdout);`p.Main.g();printf(\"f 2\\n\");fflush(stdout);}}public class Main{public static void g(){System.out.println(\"Main.g\");System.out.flush();}public static void main(String[]args){System.out.println(\"Main.main 1\");System.out.flush();`f(env);System.out.println(\"Main.main 2\");System.out.flush();}}")); return s; } private static TestSuite makeSuiteJeannieParser() { final TestSuite s = new TestSuite(); s.addTest(new JeannieParserTest(false, "Block", "Java", "`{int i = &a; someCFunction(i);}")); s.addTest(new JeannieParserTest(false, "Block", "Java", "{int i = a >>> 3; someJavaMethod(i);}")); s.addTest(new JeannieParserTest(false, "CompoundStatement", "C", "`{int i = a >>> 3; someJavaMethod(i);}")); s.addTest(new JeannieParserTest(false, "CompoundStatement", "C", "{int i = &a; someCFunction(i);}")); s.addTest(new JeannieParserTest(false, "File" /* 000 hello world */, null, "`.C{extern int printf(__const char *__restrict __format, ...);}class Main{static native void sayHi() `{printf(\"Hello world!\\n\");}public static void main(String[]args){sayHi();}}")); s.addTest(new JeannieParserTest(false, "File" /* 001 pure Java hello world */ , null, "`.C{}class Main{public static void main(String[]args){System.out.println(\"Hello, world\");}}")); s.addTest(new JeannieParserTest(false, "File" /* 002 callStatic */, null, "`.C{extern int printf(__const char *__restrict __format, ...);}class Main{native static void foo() `{int y; y = `Math.max(123, 456); printf(\"return value: %d\\n\", y);}public static void main(String[] args){foo();}}")); s.addTest(new JeannieParserTest(false, "File", null, "")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{extern int printf(__const char*__restrict __format,...);}class Main{static native void f(int[]ja)throws Exception`{int i;jint*ca;_with(ca=`ja){for(i=0;i<3;i++){if(ca[i]==4)`throw new Exception();printf(\"p0 (%d:%d)\\n\",i,ca[i]);}printf(\"p1\\n\");_commit ca;}printf(\"p2\\n\");}public static void main(String[]args){int[]a={3,1,4};try{f(a);System.out.println(\"p3\");}catch(Exception e){System.out.println(\"p4\");}}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{typedef int jint; jint i=0;}class A{int f(){return `&i;}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{typedef int jint; jint i=0;}class A{int f(){return `((jint)&i);}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{typedef int jint; jint i=0;}class A{int f(){return `(i+2);}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{typedef int jint;}class Main{static native int sum(int[] ja)`{jint *ca,s;int i,n;s=0;n=`ja.length;_with(ca=`ja){for(i=0;i<n;i++)s+=ca[i];_cancel ca;}return s;}public static void main(String[]args){int[] a={3,1,4};System.out.println(\"expected 8, got \"+sum(a));}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{} class A{int f(){return `(1+2);}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{} class A{void f(){int x=0;}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{} class A{} ")); s.addTest(new JeannieParserTest(false, "File", null, "`.C{}class A{native void f()`{}}")); s.addTest(new JeannieParserTest(false, "File", null, "`.Java{import java.util.Vector;}int f(){}")); s.addTest(new JeannieParserTest(false, "File", null, "`.Java{}")); s.addTest(new JeannieParserTest(false, "File", null, "`.Java{}`java.lang.Integer i;")); s.addTest(new JeannieParserTest(false, "File", null, "`.Java{}const `java.lang.Integer *i[10];")); s.addTest(new JeannieParserTest(false, "File", null, "`.Java{}int f()`throws E{}")); s.addTest(new JeannieParserTest(false, "JeannieC$ConditionalExpression", "C", "1+2")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_cancel a;")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_commit a;")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_copyFromJava(ca, 0, `ja, 0, 2);")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_copyToJava(`ja, 0, ca, 0, `ja.length-1);")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_with(ca=`ja){}")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_with(ca=`new int[123]){}")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_with(ca=ja){ca[0]=3;}")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "_with(ca=ja){}")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "`synchronized(m){}")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "`throw new E();")); s.addTest(new JeannieParserTest(false, "JeannieC$Statement", "C", "`try{}catch(E e){}")); s.addTest(new JeannieParserTest(false, "JeannieC$UnaryExpression", "C", "`(x >>> 3)")); s.addTest(new JeannieParserTest(false, "JeannieC$UnaryExpression", "C", "`x")); s.addTest(new JeannieParserTest(false, "JeannieJava$Declaration", "Java", "A b(C d,E[]f){}")); s.addTest(new JeannieParserTest(false, "JeannieJava$Expression", "Java", "(a==++b.c(1)[d.e()][2].f&g)-h")); s.addTest(new JeannieParserTest(false, "JeannieJava$Expression", "Java", "`&x")); s.addTest(new JeannieParserTest(false, "JeannieJava$Expression", "Java", "`(1?2:3)")); s.addTest(new JeannieParserTest(false, "JeannieJava$Expression", "Java", "new A[][]{{b,c},{d,e}}")); return s; } public static Test suite() { final TestSuite s = new TestSuite(); if (false) { //TD 00 quick test-bed s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;typedef int jint;int f(JNIEnv*env)`{return 0;}}class A{}")); //s.addTest(new JeannieAnalyzerTestError(false, "File", null, "`.C{typedef int JNIEnv;}class A{}", "")); //s.addTest(new JeannieCodeGeneratorTest(false, "File", null, "`.C{typedef int JNIEnv;}class A{}")); } else { s.addTestSuite(xtc.lang.jeannie.UnitTests.class); s.addTest(makeSuiteJeannieCodeGenerator()); s.addTest(makeSuiteJeannieAnalyzerError()); s.addTest(makeSuiteJeannieParser()); s.addTest(JavaUnitTests.suite()); } return s; } private void addJniTypedefs(final Runtime runtime, final SymbolTable tab) { final StringBuffer defs = new StringBuffer(); defs.append("typedef int jint;"); defs.append("typedef long jlong;"); defs.append("typedef void* jobject;"); defs.append("typedef jobject jintArray;"); defs.append("typedef jobject jobjectArray;"); final GNode builtins = Utilities.jeannieStringToAst("CompilationUnit", "Java", "`.C{" + defs + "}class A{}"); new Analyzer(runtime, tab, null).dispatch(builtins); } public final void testJeannieParser_pFile() throws Exception { final GNode ast = Utilities.jeannieStringToAst("File", null, "`.C{} class A { }", false); final String out = Utilities.jeannieAstToString(ast, null); if (false) System.out.println(out); } public final void testJeannieUtil_cAstToString() throws Exception { for (final String s : new String[]{ "{}", "{int*i,j=2+2,(*k)[5];}" }) { final GNode ast = Utilities.cStringToAst("CompoundStatement", s); assertEquals(s, JavaUnitTests.contractSpace(Utilities.cAstToString(ast))); } } public final void testJeannieUtil_containsCCode() throws Exception { assertFalse(Utilities.containsJavaToCTransition(Utilities.jeannieStringToAst("JavaInJavaBlock", "java", "{}"))); assertTrue(Utilities.containsJavaToCTransition(Utilities.jeannieStringToAst("JavaInJavaBlock", "java", "{`{}}"))); assertFalse(Utilities.containsJavaToCTransition(Utilities.jeannieStringToAst("JavaInJavaBlock", "java", "{int i = 2;}"))); assertTrue(Utilities.containsJavaToCTransition(Utilities.jeannieStringToAst("JavaInJavaBlock", "java", "{int i = 3.5 * `(2 + 2);}"))); } public final void testJeannieUtil_cTypeToJavaType() throws Exception { final Runtime runtime = Utilities.newRuntime(); final SymbolTable tab = new SymbolTable(); addJniTypedefs(runtime, tab); assertEquals("int", JavaEntities.javaTypeToString(tab, Utilities.cTypeToJavaType(tab, runtime, null, Utilities.cStringToType("char")))); assertEquals("long", JavaEntities.javaTypeToString(tab, Utilities.cTypeToJavaType(tab, runtime, null, Utilities.cStringToType("long")))); } public final void testJeannieUtil_cTypeToString() throws Exception { for (final String s : new String[]{ "int", "int*", "int[]", "int(*)[3]", "struct s***" }) { final Type type = Utilities.cStringToType(s); assertEquals(s, JavaUnitTests.contractSpace(Utilities.cTypeToString(type))); } assertEquals("struct t", JavaUnitTests.contractSpace(Utilities.cTypeToString(Utilities.cStringToType("struct t{int i;}")))); assertEquals("int(*p)[3]", JavaUnitTests.contractSpace(Utilities.cTypeToString(Utilities.cStringToType("int(*)[3]"), "p"))); } public final void testJeannieUtil_javaTypeToApiType() { assertEquals("int", Utilities.javaTypeToApiType(JavaEntities.javaStringToType("int"))); assertEquals("Object", Utilities.javaTypeToApiType(JavaEntities.javaStringToType("int[][]"))); assertEquals("intArray", Utilities.javaTypeToApiType(JavaEntities.javaStringToType("int[]"))); assertEquals("boolean", Utilities.javaTypeToApiType(JavaEntities.javaStringToType("boolean"))); assertEquals("Object", Utilities.javaTypeToApiType(JavaEntities.javaStringToType("String"))); } public final void testJeannieUtil_javaTypeToCType() throws Exception { final Runtime runtime = Utilities.newRuntime(); final SymbolTable tab = new SymbolTable(); addJniTypedefs(runtime, tab); assertEquals("jint", Utilities.cTypeToString(Utilities.javaTypeToCType(tab, runtime, null, JavaEntities.javaStringToType("int"), false))); assertEquals("jintArray", Utilities.cTypeToString(Utilities.javaTypeToCType(tab, runtime, null, JavaEntities.javaStringToType("int[]"), false))); assertEquals("jobjectArray", Utilities.cTypeToString(Utilities.javaTypeToCType(tab, runtime, null, JavaEntities.javaStringToType("int[][]"), false))); assertEquals("jobject", Utilities.cTypeToString(Utilities.javaTypeToCType(tab, runtime, null, JavaEntities.javaStringToType("Object"), false))); } public final void testJeannieUtil_javaTypeToString() { for (final String s : new String[]{ "int", "int[][]", "java.lang.Object", "java.io.Writer[]" }) { final Type type = JavaEntities.javaStringToType(s); assertEquals(s, JavaEntities.javaTypeToString(null, type)); } assertEquals("java.lang.Object", JavaEntities.javaTypeToString(null, JavaEntities.javaStringToType("Object"))); } public final void testJeannieUtil_jniMangledName() { assertEquals("a_b_C", Utilities.jniMangledName("a.b.C")); assertEquals("C_1x", Utilities.jniMangledName("C_x")); assertEquals("java_lang_Object", Utilities.jniMangledName("java.lang.Object")); assertEquals("java_lang_String", Utilities.jniMangledName(null, JavaEntities.javaStringToType("java.lang.String"))); } }