Split SDM's JavaScript into a lib that can be tested.
Change-Id: I11b7821871fbd626a579d4dba9b5f9a312f537ca
diff --git a/dev/codeserver/build.xml b/dev/codeserver/build.xml
index fc7f96b..8b40e3a 100755
--- a/dev/codeserver/build.xml
+++ b/dev/codeserver/build.xml
@@ -21,6 +21,7 @@
<src path="java" />
<src path="javatests" />
<classpath>
+ <pathelement location="${gwt.root}/build/out/dev/bin-test"/>
<pathelement location="${javac.out}"/>
<pathelement location="${gwt.dev.jar}" />
<pathelement location="${gwt.tools.lib}/junit/junit-4.8.2.jar" />
@@ -57,11 +58,14 @@
test.out="${junit.out}/codeserver"
test.cases="tests">
<extraclasspaths>
+ <pathelement location="${gwt.root}/build/out/dev/bin-test"/>
<pathelement location="${project.lib}"/>
<pathelement location="${gwt.dev.jar}" />
<!-- Pull in gwt-user sources -->
<pathelement location="${gwt.root}/user/src/"/>
<pathelement location="${gwt.root}/user/super/"/>
+ <pathelement location="java/" />
+ <pathelement location="javatests/" />
</extraclasspaths>
</gwt.junit>
</target>
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index 7f07ca0..53f9c30 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -51,7 +51,6 @@
import java.io.File;
import java.io.IOException;
-import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -260,13 +259,20 @@
String outputModuleName = module.getName();
try {
- URL resource = Resources.getResource(Recompiler.class, "recompile.nocache.js");
- String stub = Resources.toString(resource, Charsets.UTF_8);
- return "(function() {\n"
- + " var moduleName = '" + outputModuleName + "';\n"
- + PropertiesUtil.generatePropertiesSnippet(module, compileLogger)
- + stub
- + "})();\n";
+ String templateJs = Resources.toString(
+ Resources.getResource(Recompiler.class, "recompile_template.js"), Charsets.UTF_8);
+ String propertyProviders = PropertiesUtil.generatePropertiesSnippet(module, compileLogger);
+ String libJs = Resources.toString(
+ Resources.getResource(Recompiler.class, "recompile_lib.js"), Charsets.UTF_8);
+ String recompileJs = Resources.toString(
+ Resources.getResource(Recompiler.class, "recompile_main.js"), Charsets.UTF_8);
+ templateJs = templateJs.replace("__MODULE_NAME__", "'" + outputModuleName + "'");
+ templateJs = templateJs.replace("__PROPERTY_PROVIDERS__", propertyProviders);
+ templateJs = templateJs.replace("__LIB_JS__", libJs);
+ templateJs = templateJs.replace("__MAIN__", recompileJs);
+
+ return templateJs;
+
} catch (IOException e) {
compileLogger.log(Type.ERROR, "Can not generate + " + outputModuleName
+ " + .recompile.nocache.js", e);
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile.nocache.js b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_lib.js
similarity index 75%
rename from dev/codeserver/java/com/google/gwt/dev/codeserver/recompile.nocache.js
rename to dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_lib.js
index 0c412fa..c74d699 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile.nocache.js
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_lib.js
@@ -14,11 +14,9 @@
* under the License.
*/
-
-// These variables are used by property providers.
-// (We also use them below.)
-var $wnd = window;
-var $doc = document;
+// Export into our name space
+// We do not consider any of these classes a public API and they will be changed as needed.
+$namespace.lib = $namespace.lib || {};
/**
* Construct an instance of the PropertyHelper.
@@ -50,7 +48,8 @@
// TODO(dankurka): trigger this error in the ui
// IE8 only has console defined if its dev tools have been opened before
if ($wnd.console && $wnd.console.log) {
- $wnd.console.log("provider for " + propName + " returned unexpected value: '" + val + "'");
+ $wnd.console.log("provider for " + propName
+ + " returned unexpected value: '" + val + "'");
}
throw "can't compute binding property value for " + propName;
}
@@ -70,6 +69,9 @@
return result;
};
+// Export PropertyHelper to namespace
+$namespace.lib.PropertyHelper = PropertyHelper;
+
/**
* Create a dialog.
* @constructor
@@ -147,6 +149,9 @@
$doc.body.removeChild(this.__dialog);
};
+//Export Dialog to namespace
+$namespace.lib.Dialog = Dialog;
+
/**
* Construct a Recompiler object.
* @constructor
@@ -155,10 +160,15 @@
* @returns
*/
function Recompiler(moduleName, permutationProperties) {
- $wnd.__gwt_sdm__recompiler = $wnd.__gwt_sdm__recompiler || {};
- $wnd.__gwt_sdm__recompiler.counter = $wnd.__gwt_sdm__recompiler.counter || 0;
- $wnd.__gwt_sdm__recompiler.callbacks = $wnd.__gwt_sdm__recompiler.callback || {};
- this.__globals = $wnd.__gwt_sdm__recompiler;
+ if ($wnd.__gwt_sdm_globals) {
+ this.__globals = $wnd.__gwt_sdm_globals;
+ } else {
+ this.__globals = {
+ callbackCounter: new Date().getTime(), // avoid cache hits
+ callbacks: {}
+ };
+ $wnd.__gwt_sdm_globals = this.__globals;
+ }
this.__moduleName = moduleName;
this.__permutationProperties = permutationProperties;
this.__compiling = false;
@@ -175,7 +185,7 @@
props.push($wnd.encodeURIComponent(key) + '=' +
$wnd.encodeURIComponent(this.__permutationProperties[key]));
}
- return url + props.join('&') + '&';
+ return url + props.join('&');
};
/**
@@ -205,7 +215,7 @@
callback(json);
};
- var url = url + '_callback=__gwt_sdm__recompiler.callbacks.' + callback_id;
+ var url = url + '&_callback=__gwt_sdm_globals.callbacks.' + callback_id;
var script = $doc.createElement('script');
script.src = url;
var $head = $doc.head || $doc.getElementsByTagName('head')[0];
@@ -268,65 +278,5 @@
return this.getCodeServerBaseUrl() + 'log/' + this.__moduleName;
};
-/**
- * Construct the main class.
- *
- * @constructor
- * @param {string} moduleName
- * @param {Object} propertyProviders
- * @param {Object} propertyValues
- */
-function Main(moduleName, propertyProviders, propertyValues){
- var propertyHelper = new PropertyHelper(moduleName, propertyProviders, propertyValues);
- this.__moduleName = moduleName;
- this.__dialog = new Dialog();
- this.__recompiler = new Recompiler(moduleName, propertyHelper.computeBindingProperties());
- // Publish a global variable to let others know that we have been loaded
- $wnd.__gwt_sdm__recompiler = $wnd.__gwt_sdm__recompiler || {};
- $wnd.__gwt_sdm__recompiler.loaded = true;
-}
-
-/**
- * Compile the current gwt module.
- */
-Main.prototype.compile = function() {
- var that = this;
- this.__dialog.clear();
- this.__dialog.add(this.__dialog.createTextElement("div", "12pt", "Compiling " + this.__moduleName));
- this.__dialog.show();
- this.__recompiler.compile(function(result) {
- that.__dialog.clear();
- if (result.status != 'ok') {
- that.__renderError(result);
- } else {
- that.__dialog.hide();
- that.__recompiler.loadApp();
- }
- });
-};
-
-/**
- * Render an error if compile failed.
- * @param {object} result - the jsonp object from the compile server.
- */
-Main.prototype.__renderError = function(result) {
- var that = this;
- var link = this.__dialog.createTextElement('a', '16pt', result.status);
- link.setAttribute('href', this.__recompiler.getLogUrl());
- link.setAttribute('target', 'gwt_dev_mode_log');
- link.style.color = 'red';
- link.style.textDecoration = 'underline';
- this.__dialog.add(link);
-
- var button = this.__dialog.createTextElement('button', '12pt', 'Try Again');
- button.onclick = function() {
- that.compile();
- };
- button.style.marginLeft = '10px';
- this.__dialog.add(button);
-};
-
-
-new Main(moduleName, providers, values).compile();
-
-
+//Export Recompiler to namespace
+$namespace.lib.Recompiler = Recompiler;
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_main.js b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_main.js
new file mode 100644
index 0000000..16f05d8
--- /dev/null
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_main.js
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+var Dialog = $namespace.lib.Dialog;
+var PropertyHelper = $namespace.lib.PropertyHelper;
+var Recompiler = $namespace.lib.Recompiler;
+//Publish a global variable to let others know that we have been loaded
+$wnd.__gwt_sdm = $wnd.__gwt_sdm || {};
+$wnd.__gwt_sdm.loaded = true;
+
+/**
+ * Construct the main class.
+ *
+ * @constructor
+ * @param {string} moduleName
+ * @param {Object} propertyProviders
+ * @param {Object} propertyValues
+ */
+function Main(moduleName, propertyProviders, propertyValues){
+ var propertyHelper = new PropertyHelper(moduleName, propertyProviders, propertyValues);
+ this.__moduleName = moduleName;
+ this.__dialog = new Dialog();
+ this.__recompiler = new Recompiler(moduleName, propertyHelper.computeBindingProperties());
+}
+
+/**
+ * Compile the current gwt module.
+ */
+Main.prototype.compile = function() {
+ var that = this;
+ this.__dialog.clear();
+ this.__dialog.add(this.__dialog.createTextElement("div", "12pt", "Compiling " + this.__moduleName));
+ this.__dialog.show();
+ this.__recompiler.compile(function(result) {
+ that.__dialog.clear();
+ if (result.status != 'ok') {
+ that.__renderError(result);
+ } else {
+ that.__dialog.hide();
+ that.__recompiler.loadApp();
+ }
+ });
+};
+
+/**
+ * Render an error if compile failed.
+ * @param {object} result - the jsonp object from the compile server.
+ */
+Main.prototype.__renderError = function(result) {
+ var that = this;
+ var link = this.__dialog.createTextElement('a', '16pt', result.status);
+ link.setAttribute('href', this.__recompiler.getLogUrl());
+ link.setAttribute('target', 'gwt_dev_mode_log');
+ link.style.color = 'red';
+ link.style.textDecoration = 'underline';
+ this.__dialog.add(link);
+
+ var button = this.__dialog.createTextElement('button', '12pt', 'Try Again');
+ button.onclick = function() {
+ that.compile();
+ };
+ button.style.marginLeft = '10px';
+ this.__dialog.add(button);
+};
+
+new Main(moduleName, providers, values).compile();
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_template.js b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_template.js
new file mode 100644
index 0000000..0afd4a5
--- /dev/null
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/recompile_template.js
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+(function(){
+ var $wnd = window;
+ var $doc = $wnd.document;
+ var $namespace = {};
+ var moduleName = __MODULE_NAME__;
+ __PROPERTY_PROVIDERS__
+ __LIB_JS__
+ __MAIN__
+})();
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerSuite.java b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerSuite.java
new file mode 100644
index 0000000..9f8ea74
--- /dev/null
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerSuite.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.codeserver;
+
+import com.google.gwt.dev.codeserver.client.CodeServerGwtTest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CodeServerSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite("Tests of the code server package");
+ suite.addTestSuite(CodeServerGwtTest.class);
+ return suite;
+ }
+}
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerTest.gwt.xml b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerTest.gwt.xml
new file mode 100644
index 0000000..38f5f90
--- /dev/null
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/CodeServerTest.gwt.xml
@@ -0,0 +1,18 @@
+<!-- -->
+<!-- Copyright 2014 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+<module>
+ <inherits name='com.google.gwt.resources.Resources'/>
+ <source path="" includes="recompile_lib.js"/>
+ <source path="client"/>
+</module>
diff --git a/dev/codeserver/javatests/com/google/gwt/dev/codeserver/client/CodeServerGwtTest.java b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/client/CodeServerGwtTest.java
new file mode 100644
index 0000000..6ebea95
--- /dev/null
+++ b/dev/codeserver/javatests/com/google/gwt/dev/codeserver/client/CodeServerGwtTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.codeserver.client;
+
+import com.google.gwt.core.client.ScriptInjector;
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.TextResource;
+
+/**
+ * A GwtTestCase for the JavaScript that is part of super dev mode.
+ *
+ * Since inside of the GWT SDK there is not a lot of JavaScript it does not make sense to add a
+ * extra testing framework for JavaScript. Rather this class bundles the JavaScript that should
+ * be tested as a TextResource and injects it into the current page. This way we can write test
+ * against it using JSNI.
+ */
+public class CodeServerGwtTest extends GWTTestCase {
+
+ interface Resource extends ClientBundle {
+ @Source("com/google/gwt/dev/codeserver/recompile_lib.js")
+ TextResource libJS();
+ }
+
+ private boolean injected;
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.codeserver.CodeServerTest";
+ }
+
+ @Override
+ protected void gwtSetUp() throws Exception {
+ ensureJsInjected();
+ }
+
+ public native void testPropertyHelper_withProperInput() /*-{
+ // setup property providers and values for the test
+ var mocks = (function(){
+ var propProviders = {};
+ var propValues = {};
+ propProviders['prop1'] = function(){
+ return 'val1_1';
+ };
+
+ propValues['prop1'] = {'val1_1':0,'val1_2':1,'val1_3':2};
+
+ propProviders['prop2'] = function(){
+ return 'val2_2';
+ };
+
+ propValues['prop2'] = {'val2_1':0,'val2_2':1,'val2_3':2};
+ return {provider: propProviders, values : propValues};
+ })();
+
+ // Actual test
+ var PropertyHelper = $wnd.namespace.lib.PropertyHelper;
+ var propertyHelper = new PropertyHelper('testModule', mocks.provider, mocks.values);
+ var result = propertyHelper.computeBindingProperties();
+ var assertStringEquals = @CodeServerGwtTest::assertEquals(Ljava/lang/String;Ljava/lang/String;);
+ var assertTrue = @CodeServerGwtTest::assertTrue(Ljava/lang/String;Z);
+
+ var length = Object.keys(result).length;
+ assertTrue(length == 2, "PropertyHelper did not return two entries: " + length);
+ assertStringEquals('val1_1', result['prop1']);
+ assertStringEquals('val2_2', result['prop2']);
+ }-*/;
+
+ public native void testRecompiler() /*-{
+ var Recompiler = $wnd.namespace.lib.Recompiler;
+ var recompiler = new Recompiler('testModule', {prop1: 'val1', prop2 : 'val2'});
+
+ var jsonpUrl = '';
+ var callbackCalled = false;
+
+ var assertStringEquals = @CodeServerGwtTest::assertEquals(Ljava/lang/String;Ljava/lang/String;);
+ var assertTrue = @CodeServerGwtTest::assertTrue(Ljava/lang/String;Z);
+
+ // patch up functions of recompiler that need the actual SDM environment
+ recompiler.getCodeServerBaseUrl = function() {
+ return "http://mytesthost:7812/";
+ };
+
+ recompiler.__jsonp = function(url, callback) {
+ jsonpUrl = url;
+ callback({status : 'ok'});
+ };
+
+ // do the test
+ recompiler.compile(function(result) {
+ callbackCalled = true;
+ //compile is done
+ assertStringEquals('ok', result.status);
+ assertStringEquals('http://mytesthost:7812/recompile/testModule?prop1=val1&prop2=val2',
+ jsonpUrl);
+ });
+ assertTrue(callbackCalled, 'callback for successful recompile was not executed');
+ }-*/;
+
+ private void ensureJsInjected() {
+ if(injected) {
+ return;
+ }
+ Resource res = GWT.create(Resource.class);
+ String before = "(function(){ \n" +
+ "$wnd.namespace = {};$namespace = $wnd.namespace; $global = $wnd";
+ String js = res.libJS().getText();
+ ScriptInjector.fromString(before + js + "})()").inject();
+ }
+}
diff --git a/eclipse/dev/codeserver/.classpath b/eclipse/dev/codeserver/.classpath
index 92a2b6c..5837833 100644
--- a/eclipse/dev/codeserver/.classpath
+++ b/eclipse/dev/codeserver/.classpath
@@ -10,5 +10,6 @@
<classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-8.1.12.v20130726/servlet-api-3.0-NoMetaInf.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/junit/junit-4.8.2.jar" sourcepath="/GWT_TOOLS/lib/junit/junit-4.8.2-src.zip"/>
<classpathentry combineaccessrules="false" kind="src" path="/gwt-dev"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
<classpathentry kind="output" path="bin"/>
</classpath>