From 385b696de9ad223fbe38326e0bdfbc6247d3631d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 20 Oct 2015 22:21:06 +0300 Subject: [PATCH] Add mocks for WebSockets in html4j --- .../org/teavm/html4j/test/KnockoutFXTest.java | 74 +++++++++++++++---- .../java/org/teavm/html4j/test/WSImpl.java | 18 +++++ .../org/teavm/jso/impl/JSBodyInlineUtil.java | 3 +- .../org/teavm/jso/impl/JSClassProcessor.java | 12 +-- 4 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 html4j/src/test/java/org/teavm/html4j/test/WSImpl.java diff --git a/html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java b/html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java index 54ee419d8..fa463f57f 100644 --- a/html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java +++ b/html4j/src/test/java/org/teavm/html4j/test/KnockoutFXTest.java @@ -29,6 +29,7 @@ import org.netbeans.html.context.spi.Contexts; import org.netbeans.html.json.spi.JSONCall; import org.netbeans.html.json.spi.Technology; import org.netbeans.html.json.spi.Transfer; +import org.netbeans.html.json.spi.WSTransfer; import org.netbeans.html.json.tck.KnockoutTCK; import org.netbeans.html.ko4j.KO4J; import org.teavm.jso.JSBody; @@ -43,23 +44,24 @@ import org.testng.Assert; * * @author Jaroslav Tulach */ -public final class KnockoutFXTest extends KnockoutTCK implements Transfer { +public final class KnockoutFXTest extends KnockoutTCK implements Transfer, WSTransfer { private static Class browserClass; private static Fn.Presenter browserContext; private KO4J ko4j = new KO4J(); private final Map urlMap = new HashMap<>(); + private final Map wsUrlMap = new HashMap<>(); public KnockoutFXTest() { } - static synchronized ClassLoader getClassLoader() throws InterruptedException { + static ClassLoader getClassLoader() throws InterruptedException { while (browserClass == null) { KnockoutFXTest.class.wait(); } return browserClass.getClassLoader(); } - public static synchronized void initialized(Class browserCls) throws Exception { + public static void initialized(Class browserCls) throws Exception { browserClass = browserCls; browserContext = Fn.activePresenter(); KnockoutFXTest.class.notifyAll(); @@ -81,6 +83,7 @@ public final class KnockoutFXTest extends KnockoutTCK implements Transfer { return Contexts.newBuilder() .register(Transfer.class, this, 1) .register(Technology.class, ko4j.knockout(), 1) + .register(WSTransfer.class, this, 1) .build(); } @@ -105,21 +108,24 @@ public final class KnockoutFXTest extends KnockoutTCK implements Transfer { ) public native Object executeScript(String s, Object[] args); - @JavaScriptBody(args = { }, body = - "var h;" + - "if (!!window && !!window.location && !!window.location.href)\n" + - " h = window.location.href;\n" + - "else " + - " h = null;" + - "return h;\n") - private static native String findBaseURL(); - @Override public URI prepareURL(String content, String mimeType, String[] parameters) { try { + boolean isWS = false; + for (String param : parameters) { + if (param.equals("protocol:ws")) { + isWS = true; + break; + } + } String url = "http://localhost/dynamic/" + urlMap.size(); - urlMap.put(url, new Request(content, mimeType, parameters)); - return new URI(url); + if (!isWS) { + urlMap.put(url, new Request(content, mimeType, parameters)); + return new URI(url); + } else { + wsUrlMap.put(url, new WSImpl(url, content)); + return new URI(url); + } } catch (URISyntaxException ex) { throw new IllegalStateException(ex); } @@ -224,6 +230,43 @@ public final class KnockoutFXTest extends KnockoutTCK implements Transfer { }); } + @Override + public WSImpl open(String url, JSONCall callback) { + WSImpl impl = wsUrlMap.get(url); + if (impl != null) { + impl.callback = callback; + callback.notifySuccess(null); + } else { + callback.notifyError(null); + } + return impl; + } + + @Override + public void send(WSImpl socket, JSONCall data) { + String content = socket.content; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) == '$') { + int digit = content.charAt(++i) - '0'; + if (digit == 0) { + sb.append(data.getMessage()); + } else { + sb.append('$').append(content.charAt(i)); + } + } else { + sb.append(content.charAt(i)); + } + } + socket.callback.notifySuccess(eval("(" + sb + ")")); + } + + @Override + public void close(WSImpl socket) { + wsUrlMap.remove(socket.url); + socket.callback.notifyError(null); + } + @JSBody(params = { "name", "callback" }, script = "window[name] = callback;") private static native void defineFunction(String name, JSONPCallback callback); @@ -235,6 +278,9 @@ public final class KnockoutFXTest extends KnockoutTCK implements Transfer { void dataReceived(JSObject dataReceived); } + @JSBody(params = "text", script = "return eval(text);") + private static native JSObject eval(String text); + private static final class Request { final String content; final String mimeType; diff --git a/html4j/src/test/java/org/teavm/html4j/test/WSImpl.java b/html4j/src/test/java/org/teavm/html4j/test/WSImpl.java new file mode 100644 index 000000000..31d34022c --- /dev/null +++ b/html4j/src/test/java/org/teavm/html4j/test/WSImpl.java @@ -0,0 +1,18 @@ +package org.teavm.html4j.test; + +import org.netbeans.html.json.spi.JSONCall; + +/** + * + * @author Alexey Andreev + */ +class WSImpl { + String url; + JSONCall callback; + String content; + + public WSImpl(String url, String content) { + this.url = url; + this.content = content; + } +} diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java index 716d0a119..92051c637 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java @@ -19,7 +19,6 @@ import java.util.HashMap; import java.util.Map; import org.mozilla.javascript.Token; import org.mozilla.javascript.ast.AstNode; -import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.ExpressionStatement; import org.mozilla.javascript.ast.Name; import org.mozilla.javascript.ast.NodeVisitor; @@ -37,7 +36,7 @@ final class JSBodyInlineUtil { private JSBodyInlineUtil() { } - public static AstNode isSuitableForInlining(MethodReference method, String[] parameters, AstRoot ast) { + public static AstNode isSuitableForInlining(MethodReference method, String[] parameters, AstNode ast) { AstNode statement = isSingleStatement(ast); if (statement == null) { return null; diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java index c92a85f4a..432ae6dfa 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java @@ -29,6 +29,7 @@ import org.mozilla.javascript.CompilerEnvirons; import org.mozilla.javascript.Context; import org.mozilla.javascript.ast.AstNode; import org.mozilla.javascript.ast.AstRoot; +import org.mozilla.javascript.ast.FunctionNode; import org.teavm.diagnostics.Diagnostics; import org.teavm.javascript.spi.GeneratedBy; import org.teavm.javascript.spi.InjectedBy; @@ -562,14 +563,15 @@ class JSClassProcessor { env.setLanguageVersion(Context.VERSION_1_8); env.setIdeMode(true); JSParser parser = new JSParser(env, errorReporter); - parser.enterFunction(); + //parser.enterFunction(); AstRoot rootNode; try { - rootNode = parser.parse(new StringReader(script), null, 0); + rootNode = parser.parse(new StringReader("function(){" + script + "}"), null, 0); } catch (IOException e) { throw new RuntimeException("IO Error occured", e); } - parser.exitFunction(); + AstNode body = ((FunctionNode) rootNode.getFirstChild()).getBody(); + //parser.exitFunction(); repository.methodMap.put(methodToProcess.getReference(), proxyMethod); if (errorReporter.hasErrors()) { @@ -577,11 +579,11 @@ class JSClassProcessor { script, parameterNames)); } else { AstNode expr = JSBodyInlineUtil.isSuitableForInlining(methodToProcess.getReference(), - parameterNames, rootNode); + parameterNames, body); if (expr != null) { repository.inlineMethods.add(methodToProcess.getReference()); } else { - expr = rootNode; + expr = body; } javaInvocationProcessor.process(location, expr); repository.emitters.put(proxyMethod, new JSBodyAstEmitter(isStatic, expr, parameterNames));