Author: evan
Date: Thu Mar 19 22:17:49 2009
New Revision: 756236
URL: http://svn.apache.org/viewvc?rev=756236&view=rev
Log:
Patch for SHINDIG-988
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/index.html
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/datatest.js
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/index.html
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/domutil.js
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/index.html
Removed:
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/ost_test.html
incubator/shindig/trunk/java/server/src/test/resources/endtoend/opensocial-data/data_test.js
incubator/shindig/trunk/java/server/src/test/resources/endtoend/opensocial-data/data_test.xml
incubator/shindig/trunk/java/server/src/test/resources/endtoend/opensocial-data/testadapter.js
Modified:
incubator/shindig/trunk/features/pom.xml
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/datacontexttest.js
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/template_test.js
incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndTest.java
Modified: incubator/shindig/trunk/features/pom.xml
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/pom.xml?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
--- incubator/shindig/trunk/features/pom.xml (original)
+++ incubator/shindig/trunk/features/pom.xml Thu Mar 19 22:17:49 2009
@@ -81,6 +81,8 @@
<source>setprefs/setprefs.js</source>
<source>views/views.js</source>
<source>opensocial-data-context/datacontext.js</source>
+ <source>xmlutil/xmlutil.js</source>
+ <source>opensocial-data/data.js</source>
<source>opensocial-reference/opensocial.js</source>
<source>opensocial-reference/activity.js</source>
<source>opensocial-reference/address.js</source>
Modified:
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
(original)
+++
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data-context/datacontext.js
Thu Mar 19 22:17:49 2009
@@ -36,6 +36,81 @@
var dataSets = {};
/**
+ * Puts a data set into the global DataContext object. Fires listeners
+ * if they are satisfied by the associated key being inserted.
+ *
+ * Note that if this is passed a ResponseItem object, it will crack it open
+ * and extract the JSON payload of the wrapped API Object. This includes
+ * iterating over an array of API objects and extracting their JSON into a
+ * simple array structure.
+ *
+ * @param {string} key The key to associate with this object.
+ * @param {ResponseItem|Object} obj The data object.
+ * @param {boolean} opt_fireListeners Default true.
+ */
+ var putDataSet = function(key, obj, opt_fireListeners) {
+ var data = obj;
+ if (typeof data === 'undefined' || data === null) {
+ return;
+ }
+
+ // NOTE: This is ugly, but required since we need to get access
+ // to the JSON/Array payload of API responses.
+ // This will crack the actual API objects and extract their JSON payloads.
+ // TODO: this code block is not described by the spec, and should be
removed.
+ // Developers using ResponseItems should call getData() themselves.
+ if (data.getData) {
+ data = data.getData();
+ if (data.array_) {
+ var out = [];
+ for (var i = 0; i < data.array_.length; i++) {
+ out.push(data.array_[i].fields_);
+ }
+ data = out;
+ } else {
+ data = data.fields_ || data;
+ }
+ }
+
+ dataSets[key] = data;
+ if (!(opt_fireListeners === false)) {
+ fireCallbacks(key);
+ }
+ };
+
+ /**
+ * Registers a callback listener for a given set of keys.
+ * @param {string|Array.<string>} keys Key or set of keys to listen on.
+ * @param {Function(Array.<string>)} callback Function to call when a
+ * listener is fired.
+ * @param {booelan} oneTimeListener Remove this listener after first
callback?
+ */
+ var registerListener = function(keys, callback, oneTimeListener) {
+ var oneTime = !!oneTimeListener;
+ var listener = {keys : {}, callback : callback, oneTime: oneTime};
+
+ if (typeof keys === 'string') {
+ listener.keys[keys] = true;
+ if (keys != '*') {
+ keys = [ keys ];
+ }
+ } else {
+ for (var i = 0; i < keys.length; i++) {
+ listener.keys[keys[i]] = true;
+ }
+ }
+
+ listeners.push(listener);
+
+ // Check to see if this one should fire immediately.
+ if (keys !== '*' && isDataReady(listener.keys)) {
+ window.setTimeout(function() {
+ maybeFireListener(listener, keys);
+ }, 1);
+ }
+ };
+
+ /**
* Checks if the data for a map of keys is available.
* @param {Object<string, ?>} An map of keys to check.
* @return {boolean} Data for all the keys is present.
@@ -53,7 +128,6 @@
return true;
};
-
/**
* Fires a listener for a key, but only if the data is ready for other
* keys this listener is bound to.
@@ -62,12 +136,13 @@
*/
var maybeFireListener = function(listener, key) {
if (isDataReady(listener.keys)) {
- if (listener.callback(key) ==
opensocial.data.DataContext.REMOVE_LISTENER) {
+ listener.callback(key);
+ if (listener.oneTime) {
removeListener(listener);
}
}
- };
-
+ };
+
/**
* Removes a listener from the list.
* @param {Object} listener The listener to remove.
@@ -96,7 +171,7 @@
for (var j = 0; j < keys.length; j++) {
var key = keys[j];
if (listener.keys[key] || listener.keys['*']) {
- maybeFireListener(listener, key);
+ maybeFireListener(listener, keys);
break;
}
}
@@ -106,44 +181,43 @@
return {
- REMOVE_LISTENER : "remove",
-
/**
- * Map of existing data. This is used externally by both the
+ * Returns a map of existing data. This is used externally by both the
* opensocial-data and opensocial-templates feature, hence is
- * not hidden.
+ * not hidden, despite not being part of the spec.
+ * @return {Object} A map of current data sets.
+ * TODO: Add to the spec API?
*/
- dataSets : dataSets,
-
+ getData : function() {
+ var data = {};
+ for (var key in dataSets) {
+ if (dataSets.hasOwnProperty(key)) {
+ data[key] = dataSets[key];
+ }
+ }
+ return data;
+ },
/**
* Registers a callback listener for a given set of keys.
* @param {string|Array.<string>} keys Key or set of keys to listen on.
- * @param {Function(string)} callback Function to call when a listener is
fired.
- * TODO: Should return a value that can later be used to return
- * a value.
+ * @param {Function(Array.<string>)} callback Function to call when a
+ * listener is fired.
*/
registerListener : function(keys, callback) {
- var listener = {keys : {}, callback : callback};
-
- if (typeof keys === 'string') {
- listener.keys[keys] = true;
- } else {
- for (var i = 0; i < keys.length; i++) {
- listener.keys[keys[i]] = true;
- }
- }
-
- listeners.push(listener);
-
- // Check to see if this one should fire immediately.
- if (keys !== '*' && isDataReady(listener.keys)) {
- window.setTimeout(function() {
- maybeFireListener(listener, keys);
- }, 1);
- }
+ registerListener(keys, callback, false);
+ },
+
+ /**
+ * Private version of registerListener which allows one-time listeners to
+ * be registered. Not part of the spec. Exposed because needed by
+ * opensocial-templates.
+ * @param {string|Array.<string>} keys Key or set of keys to listen on.
+ * @param {Function(Array.<string>)} callback Function to call when a
+ */
+ registerOneTimeListener_ : function(keys, callback) {
+ registerListener(keys, callback, true);
},
-
/**
* Retrieve a data set for a given key.
@@ -153,49 +227,16 @@
getDataSet : function(key) {
return dataSets[key];
},
-
-
+
/**
* Puts a data set into the global DataContext object. Fires listeners
* if they are satisfied by the associated key being inserted.
*
- * Note that if this is passed a ResponseItem object, it will crack it open
- * and extract the JSON payload of the wrapped API Object. This includes
- * iterating over an array of API objects and extracting their JSON into a
- * simple array structure.
- *
* @param {string} key The key to associate with this object.
* @param {ResponseItem|Object} obj The data object.
- * @param {boolean} opt_fireListeners Default true.
*/
- putDataSet : function(key, obj, opt_fireListeners) {
- var data = obj;
- if (typeof data === 'undefined' || data === null) {
- return;
- }
-
- // NOTE: This is ugly, but required since we need to get access
- // to the JSON/Array payload of API responses.
- // This will crack the actual API objects and extract their JSON
payloads.
- // TODO: this code block is not described by the spec, and should be
removed.
- // Developers using ResponseItems should call getData() themselves.
- if (data.getData) {
- data = data.getData();
- if (data.array_) {
- var out = [];
- for (var i = 0; i < data.array_.length; i++) {
- out.push(data.array_[i].fields_);
- }
- data = out;
- } else {
- data = data.fields_ || data;
- }
- }
-
- dataSets[key] = data;
- if (!(opt_fireListeners === false)) {
- fireCallbacks(key);
- }
+ putDataSet : function(key, obj) {
+ putDataSet(key, obj, true)
},
/**
@@ -208,7 +249,7 @@
var keys = [];
for (var key in dataSets) {
keys.push(key);
- this.putDataSet(key, dataSets[key], false);
+ putDataSet(key, dataSets[key], false);
}
fireCallbacks(keys);
}
Modified:
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
(original)
+++
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-data/data.js
Thu Mar 19 22:17:49 2009
@@ -213,7 +213,7 @@
*/
opensocial.data.DataContext.evalExpression = function(expr) {
return (new Function("context", "with (context) return " + expr))
- (opensocial.data.DataContext.dataSets);
+ (opensocial.data.DataContext.getData());
};
Modified:
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
(original)
+++
incubator/shindig/trunk/features/src/main/javascript/features/opensocial-templates/container.js
Thu Mar 19 22:17:49 2009
@@ -209,7 +209,7 @@
if (!os.Container.defaultContext) {
if ((window['gadgets'] && gadgets.util.hasFeature('opensocial-data')) ||
(opensocial.data.DataContext)) {
- os.Container.defaultContext =
os.createContext(opensocial.data.DataContext.dataSets);
+ os.Container.defaultContext =
os.createContext(opensocial.data.DataContext.getData());
} else {
os.Container.defaultContext = os.createContext({});
}
@@ -254,9 +254,13 @@
if (requiredData) {
// This template will render when the specified data is available.
var keys = requiredData.split(/[\, ]+/);
- opensocial.data.DataContext.registerListener(keys,
- os.Container.createRenderClosure(template, el, null,
- os.Container.getDefaultContext()));
+ var callback = os.Container.createRenderClosure(template, el, null,
+ os.Container.getDefaultContext());
+ if ("true".equalsIgnoreCase(node.getAttribute("autoUpdate"))) {
+ opensocial.data.DataContext.registerListener(keys, callback);
+ } else {
+ opensocial.data.DataContext.registerOneTimeListener_(keys, callback);
+ }
} else {
template.renderInto(el, null, context);
}
@@ -280,7 +284,6 @@
opt_context) {
var closure = function() {
template.renderInto(element, opt_data, opt_context);
- return opensocial.data.DataContext.REMOVE_LISTENER;
};
return closure;
};
Modified:
incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js
(original)
+++
incubator/shindig/trunk/features/src/main/javascript/features/xmlutil/xmlutil.js
Thu Mar 19 22:17:49 2009
@@ -40,7 +40,7 @@
throw doc.firstChild.firstChild.nodeValue;
}
return doc;
- } else {
+ } else if (typeof(ActiveXObject) != "undefined") {
var doc = new ActiveXObject("MSXML2.DomDocument");
doc.validateOnParse = false;
doc.loadXML(str);
@@ -49,6 +49,7 @@
}
return doc;
}
+ throw "No XML parser found in this browser.";
};
Modified:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/datacontexttest.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/datacontexttest.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/datacontexttest.js
(original)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/datacontexttest.js
Thu Mar 19 22:17:49 2009
@@ -55,7 +55,6 @@
this.assertEquals('value', context.getDataSet('key'));
};
-
/**
* Test registerListener()
*/
@@ -75,15 +74,13 @@
this.assertNull(listenerCalledWithKey);
context.putDataSet('key', 2);
- this.assertEquals('key', listenerCalledWithKey);
+ this.assertEquals('key', listenerCalledWithKey[0]);
listenerCalledWithKey = null;
context.putDataSet('key', 3);
- this.assertEquals('key', listenerCalledWithKey);
+ this.assertEquals('key', listenerCalledWithKey[0]);
}
-
-
/**
* Test registerListener()
*/
@@ -96,20 +93,19 @@
that.assertNotNull(key);
};
- context.registerListener(['one', 'two'], listener);
+ context.registerListener(['aone', 'atwo'], listener);
this.assertNull(listenerCalledWithKey);
-
- context.putDataSet('one', 1);
+
+ context.putDataSet('aone', 1);
this.assertNull(listenerCalledWithKey);
- context.putDataSet('two', 2);
- this.assertEquals('two', listenerCalledWithKey);
+ context.putDataSet('atwo', 2);
+ this.assertEquals('atwo', listenerCalledWithKey[0]);
- context.putDataSet('one', 3);
- this.assertEquals('one', listenerCalledWithKey);
+ context.putDataSet('aone', 3);
+ this.assertEquals('aone', listenerCalledWithKey[0]);
}
-
/**
* Test registerListener() with '*'
*/
@@ -126,8 +122,63 @@
this.assertNull(listenerCalledWithKey);
context.putDataSet('one', 1);
- this.assertEquals('one', listenerCalledWithKey);
+ this.assertEquals('one', listenerCalledWithKey[0]);
context.putDataSet('two', 2);
- this.assertEquals('two', listenerCalledWithKey);
+ this.assertEquals('two', listenerCalledWithKey[0]);
+}
+
+/**
+ * Test getData()
+ */
+DataContextTest.prototype.testGetData = function() {
+ var context = opensocial.data.getDataContext();
+ context.putDataSet('key', 'value');
+ this.assertEquals('value', context.getData()['key']);
+ context.putDataSet('key', 'value2');
+ this.assertEquals('value2', context.getData()['key']);
+
+ // Test that altering the result of getData doesn't change the context
+ var data = context.getData();
+ data['key'] = 'ball';
+ this.assertEquals('value2', context.getDataSet('key'));
+}
+
+/**
+ * Test putDataSets()
+ */
+DataContextTest.prototype.testPutDataSets = function() {
+ var context = opensocial.data.getDataContext();
+ var counter = 0;
+ var passedKeys = null;
+ var listener = function(keys) {
+ counter++;
+ passedKeys = keys;
+ }
+ context.registerListener(['sets1', 'sets2'], listener);
+ context.putDataSets({ sets1: 'a', sets2: 'b' });
+ this.assertEquals('a', context.getDataSet('sets1'));
+ this.assertEquals('b', context.getDataSet('sets2'));
+
+ // Test that listener was only called once.
+ this.assertEquals(1, counter);
+
+ // Test that listener was passed both keys.
+ this.assertEquals(2, passedKeys.length);
+}
+
+/**
+ * Test registerOneTimeListener_()
+ */
+DataContextTest.prototype.testOneTimeListener = function() {
+ var context = opensocial.data.getDataContext();
+ var counter = 0;
+ var listener = function(keys) {
+ counter++;
+ }
+ context.registerOneTimeListener_('oneTime', listener);
+ context.putDataSet('oneTime', 'foo');
+ this.assertEquals(1, counter);
+ context.putDataSet('oneTime', 'bar');
+ this.assertEquals(1, counter);
}
\ No newline at end of file
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/index.html
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/index.html?rev=756236&view=auto
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/index.html
(added)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data-context/index.html
Thu Mar 19 22:17:49 2009
@@ -0,0 +1,68 @@
+<html>
+<head>
+ <title>Opensocial Data Context Tests</title>
+ <script>
+ function TestCase() {};
+ Function.prototype.inherits = function() {};
+ </script>
+ <script
src="../../../../main/javascript/features/opensocial-data-context/datacontext.js"></script>
+ <script src="datacontexttest.js"></script>
+ <script type="text/javascript">
+ DataContextTest.prototype.assertNotNull = function(a) {
+ if (a === null) {
+ throw("Null: " + a);
+ }
+ };
+ DataContextTest.prototype.assertNull = function(a) {
+ if (a !== null) {
+ throw("Not null: " + a);
+ }
+ };
+ DataContextTest.prototype.assertEquals = function(a, b) {
+ if (a !== b) {
+ throw("Not equal: " + typeof(a) + "[" + a + "] and " + typeof(b) +
"[" + b + "]");
+ }
+ };
+
+ function exposeTestFunctionNames(obj) {
+ var testSource = obj ? obj.prototype :
+ (typeof RuntimeObject != 'undefined' ? RuntimeObject('test' + '*')
: self);
+ var testFunctionNames = [];
+ for (var i in testSource) {
+ if (i.substring(0, 4) == 'test' && typeof(testSource[i]) ==
'function')
+ testFunctionNames.push(i);
+ }
+ return testFunctionNames;
+ }
+
+ function runAllTests() {
+ var log = function(msg, forcePage) {
+ if (window.console && !forcePage) {
+ console.log(msg);
+ return;
+ }
+ var div = document.createElement("div");
+ div.appendChild(document.createTextNode(msg));
+ document.body.appendChild(div);
+ };
+ var obj = new DataContextTest();
+ var tests = exposeTestFunctionNames(DataContextTest);
+ var failed = 0;
+ for (var i = 0; i < tests.length; i++) {
+ log(tests[i]);
+ try {
+ obj[tests[i]]();
+ log("OK");
+ } catch (e) {
+ log("FAIL: " + e);
+ failed++;
+ }
+ }
+ log("All finished. " + i + " run. " + failed + " failed.", true);
+ }
+ </script>
+</head>
+<body>
+ <input type="button" onclick="runAllTests()" value="Run tests"/>
+</body>
+</html>
\ No newline at end of file
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/datatest.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/datatest.js?rev=756236&view=auto
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/datatest.js
(added)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/datatest.js
Thu Mar 19 22:17:49 2009
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+/**
+ * @fileoverview
+ *
+ * Unittests for the opensocial-data-context feature.
+ */
+function DataTest(name) {
+ TestCase.call(this, name);
+}
+
+DataTest.inherits(TestCase);
+
+DataTest.prototype.setUp = function() {
+};
+
+DataTest.prototype.testParseExpression = function() {
+ var expressions = [
+ [ "Hello world", null ],
+ [ "${foo}", "(foo)" ],
+ [ "Hello ${foo} world", "'Hello '+(foo)+' world'" ],
+ [ "${foo} ${bar}", "(foo)+' '+(bar)" ]
+ ];
+ for (var i = 0; i < expressions.length; i++) {
+ this.assertEquals(
+ expressions[i][1],
+ opensocial.data.parseExpression_(expressions[i][0])
+ );
+ }
+};
+
+DataTest.prototype.testEvalExpression = function() {
+ var data = {
+ 'foo': 'Hello',
+ 'bar': 'World'
+ };
+ data.name = {
+ 'first': 'John',
+ 'last': 'Doe'
+ };
+ opensocial.data.DataContext.putDataSet("test", data);
+ var expressions = [
+ [ opensocial.data.parseExpression_("Test: ${test.foo}"), "Test: Hello" ],
+ [ opensocial.data.parseExpression_("${test.foo} ${test.bar}!"), "Hello
World!" ],
+ [ opensocial.data.parseExpression_("${test.name.first}
${test.name.last}"), "John Doe" ]
+ ];
+ for (var i = 0; i < expressions.length; i++) {
+ this.assertEquals(
+ expressions[i][1],
+ opensocial.data.DataContext.evalExpression(expressions[i][0])
+ );
+ }
+};
+
+/**
+ * Unit test to test data result handlers.
+ */
+DataTest.prototype.testPutDataSet = function() {
+ var key = 'test1';
+ var value = 'foo';
+ opensocial.data.DataContext.putDataSet(key, value);
+ this.assertEquals(value, opensocial.data.DataContext.getDataSet(key));
+};
+
+function registerNS(prefix) {
+ opensocial.xmlutil.NSMAP[prefix] = "#" + prefix;
+};
+
+/**
+ * Unit test to check full functionality of a request handler.
+ */
+DataTest.prototype.testRequestHandler = function() {
+ registerNS("test");
+ var results = {};
+
+ opensocial.data.registerRequestHandler('test:request', function(descriptor) {
+ results[descriptor.key] = descriptor.getAttribute('data');
+ });
+
+ var xmlData =
+ '<test:request key="first" data="testData"/>' +
+ '<test:request key="second" data="${foo}"/>';
+
+ try {
+ opensocial.data.loadRequests(xmlData);
+ } catch (e) {
+ // TODO: This test breaks because Mavan's JSUnit doesn't implement neither
+ // IE's nor FF's XML parsing interface.
+ return;
+ }
+
+ this.assertNotNull(opensocial.data.requests_['first']);
+ this.assertNotNull(opensocial.data.requests_['second']);
+
+ opensocial.data.DataContext.putDataSet("foo", "bar");
+ opensocial.data.executeRequests();
+
+ this.assertEquals('testData', results['first']);
+ this.assertEquals('bar', results['second']);
+};
+
+/**
+ * Unit test to test listener functionality when a data key is put.
+ */
+DataTest.prototype.testListener = function() {
+ var fired = false;
+ opensocial.data.DataContext.registerListener('testKey', function() {
+ fired = true;
+ });
+ opensocial.data.DataContext.putDataSet('testKey', {});
+ this.assertEquals(true, fired);
+}
+
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/index.html
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/index.html?rev=756236&view=auto
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/index.html
(added)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-data/index.html
Thu Mar 19 22:17:49 2009
@@ -0,0 +1,70 @@
+<html>
+<head>
+ <title>Opensocial Data Tests</title>
+ <script>
+ function TestCase() {};
+ Function.prototype.inherits = function() {};
+ </script>
+ <script
src="../../../../main/javascript/features/opensocial-data-context/datacontext.js"></script>
+ <script
src="../../../../main/javascript/features/xmlutil/xmlutil.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-data/data.js"></script>
+ <script src="datatest.js"></script>
+ <script type="text/javascript">
+ DataTest.prototype.assertNotNull = function(a) {
+ if (a === null) {
+ throw("Null: " + a);
+ }
+ };
+ DataTest.prototype.assertNull = function(a) {
+ if (a !== null) {
+ throw("Not null: " + a);
+ }
+ };
+ DataTest.prototype.assertEquals = function(a, b) {
+ if (a !== b) {
+ throw("Not equal: " + typeof(a) + "[" + a + "] and " + typeof(b) +
"[" + b + "]");
+ }
+ };
+
+ function exposeTestFunctionNames(obj) {
+ var testSource = obj ? obj.prototype :
+ (typeof RuntimeObject != 'undefined' ? RuntimeObject('test' + '*')
: self);
+ var testFunctionNames = [];
+ for (var i in testSource) {
+ if (i.substring(0, 4) == 'test' && typeof(testSource[i]) ==
'function')
+ testFunctionNames.push(i);
+ }
+ return testFunctionNames;
+ }
+
+ function runAllTests() {
+ var log = function(msg, forcePage) {
+ if (window.console && !forcePage) {
+ console.log(msg);
+ return;
+ }
+ var div = document.createElement("div");
+ div.appendChild(document.createTextNode(msg));
+ document.body.appendChild(div);
+ };
+ var obj = new DataTest();
+ var tests = exposeTestFunctionNames(DataTest);
+ var failed = 0;
+ for (var i = 0; i < tests.length; i++) {
+ log(tests[i]);
+ try {
+ obj[tests[i]]();
+ log("OK");
+ } catch (e) {
+ log("FAIL: " + e);
+ failed++;
+ }
+ }
+ log("All finished. " + i + " run. " + failed + " failed.", true);
+ }
+ </script>
+</head>
+<body>
+ <input type="button" onclick="runAllTests()" value="Run tests"/>
+</body>
+</html>
\ No newline at end of file
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/domutil.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/domutil.js?rev=756236&view=auto
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/domutil.js
(added)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/domutil.js
Thu Mar 19 22:17:49 2009
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// A pseudo namespace.
+var domutil = {};
+
+/**
+ * Helper functions adapted from Selenium code.
+ *
+ * Determines if the specified element is visible. An element can be rendered
+ * invisible by setting the CSS "visibility" property to "hidden", or the
+ * "display" property to "none", either for the element itself or one if its
+ * ancestors. This method will fail if the element is not present.
+ * @param {Node} node The node to check.
+ * @return {boolean} Whether the node is visible.
+ */
+domutil.isVisible = function(node) {
+ // This test is necessary because getComputedStyle returns nothing
+ // for WebKit-based browsers if node not in document. See comment below.
+ if (node.style.display == 'none' || node.style.visibility == 'hidden') {
+ return false;
+ }
+ var visibility = this.findEffectiveStyleProperty(node, 'visibility');
+ var display = this.findEffectiveStyleProperty(node, 'display');
+ return visibility != 'hidden' && display != 'none';
+};
+
+
+/**
+ * Returns the value of the effective style specified by {...@code property}.
+ * @param {Node} element The node to query.
+ * @param {string} property The name of a style that is of interest.
+ * @return {string} The value of style {...@code property}.
+ */
+domutil.findEffectiveStyleProperty = function(element, property) {
+ var effectiveStyle = this.findEffectiveStyle(element);
+ var propertyValue = effectiveStyle[property];
+ if (propertyValue == 'inherit' && element.parentNode.style) {
+ return this.findEffectiveStyleProperty(element.parentNode, property);
+ }
+ return propertyValue;
+};
+
+
+/**
+ * Returns the effective style object.
+ * @param {Node} element The node to query.
+ * @return {CSSStyleDeclaration|undefined} The style object.
+ */
+domutil.findEffectiveStyle = function(element) {
+ if (!element.style) {
+ return undefined; // not a styled element
+ }
+ if (window.getComputedStyle) {
+ // DOM-Level-2-CSS
+ // WebKit-based browsers (Safari included) return nothing if the element
+ // is not a descendent of document ...
+ return window.getComputedStyle(element, null);
+ }
+ if (element.currentStyle) {
+ // non-standard IE alternative
+ return element.currentStyle;
+ // TODO: this won't really work in a general sense, as
+ // currentStyle is not identical to getComputedStyle()
+ // ... but it's good enough for 'visibility'
+ }
+ throw new Error('cannot determine effective stylesheet in this browser');
+};
+
+
+/**
+ * Returns the text content of the current node, without markup and invisible
+ * symbols. New lines are stripped and whitespace is collapsed,
+ * such that each character would be visible.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @return {string} The text content.
+ */
+domutil.getVisibleText = function(node) {
+ var textContent;
+ // NOTE(kjin): IE innerText is more like Firefox textContent -- visibility
+ // is not concerned. Safari 3 and Chrome innerText is just the visible text.
+ var buf = [];
+ domutil.getVisibleText_(node, buf, true);
+ textContent = buf.join('');
+
+ textContent = textContent.replace(/\xAD/g, '');
+
+ textContent = textContent.replace(/ +/g, ' ');
+ if (textContent != ' ') {
+ textContent = textContent.replace(/^\s*/, '');
+ }
+
+ return textContent;
+};
+
+
+/**
+ * Returns the domutil.getVisibleText without trailing space, if any.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @return {string} The text content.
+ */
+domutil.getVisibleTextTrim = function(node) {
+ return domutil.getVisibleText(node).replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
+};
+
+
+/**
+ * Recursive support function for text content retrieval.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @param {Array} buf string buffer.
+ * @param {boolean} normalizeWhitespace Whether to normalize whitespace.
+ * @private
+ */
+domutil.getVisibleText_ = function(node, buf, normalizeWhitespace) {
+ var TAGS_TO_IGNORE_ = {
+ 'SCRIPT': 1,
+ 'STYLE': 1,
+ 'HEAD': 1,
+ 'IFRAME': 1,
+ 'OBJECT': 1
+ };
+ var PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'};
+
+ if (node.nodeName in TAGS_TO_IGNORE_) {
+ // ignore certain tags
+ } else if (node.nodeType == 3) {
+ if (normalizeWhitespace) {
+ buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
+ } else {
+ buf.push(node.nodeValue);
+ }
+ } else if (!domutil.isVisible(node)) {
+ // ignore invisible node
+ // this has to be after the check for NodeType.TEXT because text node
+ // does not have style.
+ } else if (node.nodeName in PREDEFINED_TAG_VALUES_) {
+ buf.push(PREDEFINED_TAG_VALUES_[node.nodeName]);
+ } else {
+ var child = node.firstChild;
+ while (child) {
+ domutil.getVisibleText_(child, buf, normalizeWhitespace);
+ child = child.nextSibling;
+ }
+ }
+};
+
Added:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/index.html
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/index.html?rev=756236&view=auto
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/index.html
(added)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/index.html
Thu Mar 19 22:17:49 2009
@@ -0,0 +1,179 @@
+<!--
+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.
+-->
+<html>
+ <head>
+ <title>OpenSocial templates JsUnit tests</title>
+ <script src="../../lib/JsUtil.js"></script>
+ <script src="../../lib/JsUnit.js"></script>
+ <script>
+ // TODO: These adapters are needed because the tests were originally
+ // created with a different version of JSUnit in mind. Refactor this file
+ // and the various test files to use the TestCase class infrastructure.
+ var _assert = new Assert();
+ function assertTrue(a) {
+ _assert.assertTrue(a);
+ }
+ function assertEquals(a,b) {
+ _assert.assertEquals(a,b);
+ }
+ function assertNotNull(a) {
+ _assert.assertNotNull(a);
+ }
+ function assertContains(a,b) {
+ _assert.assertTrue(b.indexOf(a) >= 0);
+ }
+ </script>
+
+ <!-- the set of js files that make up opensocial-templates feature, as
they appear in feature.xml -->
+ <script
src="http://google-jstemplate.googlecode.com/svn/trunk/util.js"></script>
+ <script
src="http://google-jstemplate.googlecode.com/svn/trunk/jsevalcontext.js"></script>
+ <script
src="http://google-jstemplate.googlecode.com/svn/trunk/jstemplate.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-template/jstemplate_debug.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-data-context/datacontext.js"></script>
+ <script
src="../../../../main/javascript/features/xmlutil/xmlutil.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-data/data.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/base.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/namespaces.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/util.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/template.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/compiler.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/loader.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/container.js"></script>
+ <script
src="../../../../main/javascript/features/opensocial-templates/os.js"></script>
+ <!-- the JsUnit tests -->
+ <script src="domutil.js"></script>
+ <script type="text/javascript" src="compiler_test.js"></script>
+ <script type="text/javascript" src="container_test.js"></script>
+ <script type="text/javascript" src="loader_test.js"></script>
+ <script type="text/javascript" src="os_test.js"></script>
+ <script type="text/javascript" src="util_test.js"></script>
+ <script type="text/javascript" src="template_test.js"></script>
+ <!-- JsUnit work-around for non-FireFox browsers -->
+ <script type="text/javascript">
+ function exposeTestFunctionNames() {
+ var testSource = typeof RuntimeObject != 'undefined' ?
+ RuntimeObject('test' + '*') : self;
+ var testFunctionNames = [];
+ for (var i in testSource) {
+ if (i.substring(0, 4) == 'test' && typeof(testSource[i]) ==
'function')
+ testFunctionNames.push(i);
+ }
+ return testFunctionNames;
+ }
+
+ function runAllTests() {
+ var log = function(msg, forcePage) {
+ if (window.console && !forcePage) {
+ console.log(msg);
+ return;
+ }
+ var div = document.createElement("div");
+ div.appendChild(document.createTextNode(msg));
+ document.body.appendChild(div);
+ };
+ var tests = exposeTestFunctionNames();
+ var failed = 0;
+ for (var i = 0; i < tests.length; i++) {
+ log(tests[i]);
+ try {
+ window[tests[i]]();
+ log("OK");
+ } catch (e) {
+ log("FAIL: " + e);
+ failed++;
+ }
+ }
+ log("All finished. " + i + " run. " + failed + " failed.", true);
+ }
+
+ os.createNamespace("test", "http://www.google.com/#test");
+ </script>
+ </head>
+ <body>
+ <input type="button" onclick="runAllTests()" value="Run tests"/>
+ <script type="text/os-template" tag="os:Test">tag template</script>
+ <script type="text/os-template">
+ <div id="test"><os:Test/></div>
+ </script>
+
+ <div style="display: none">
+ <div id="domSource">
+ <ul>
+ <li>one</li>
+ <li>two</li>
+ </ul>
+ <b>bold</b>
+ </div>
+ <div id="domTarget">
+ </div>
+ </div>
+
+ <xmp id="_T_Substitution_attribute" style="display: none">
+ <button id="${id}" style="color: ${color}" a1="value
${A1}">${text}</button>
+ </xmp>
+ <xmp id="my:user" style="display: none">
+ <a href="${url}">${name}</a> (${$my.foo})
+ </xmp>
+ <xmp id="my:record" style="display: none">
+ <b style="color: ${$my.color}">${title}</b>: <my:user context="user"
foo="${$my.foo}"/>
+ </xmp>
+ <xmp id="_T_Substitution_nested" style="display: none">
+ <div repeat="users">
+ <my:record color="${color}" foo="${user.id}"/>
+ </div>
+ </xmp>
+
+ <xmp id="_T_Conditional_Number" style="display: none">
+ <span if="42==42">TRUE</span>
+ <span if="!(42==42)">FALSE</span>
+ </xmp>
+ <xmp id="_T_Conditional_String" style="display: none">
+ <span if="'101'=='101'">TRUE</span>
+ <span if="'101'!='101'">FALSE</span>
+ </xmp>
+ <xmp id="_T_Conditional_Mixed" style="display: none">
+ <span if="'101' gt 42">TRUE</span>
+ <span if="'101' lt 42">FALSE</span>
+ </xmp>
+
+ <xmp id="_T_Repeat" style="display: none">
+ <div repeat="entries">
+ ${data}
+ </div>
+ </xmp>
+
+ <xmp id="_T_Options" style="display: none">
+ <select id="options">
+ <option repeat="options" value="${value}">${value}</option>
+ </select>
+ </xmp>
+
+ <xmp id="custom:list" style="display: none">
+ <div repeat="$my.item"><os:renderAll content="header"/><os:renderAll
content="body"/></div>
+ </xmp>
+
+ <xmp id="_T_List" style="display: none">
+ <custom:list>
+ <item>
+ <header>hello</header>
+ <body>world</body>
+ </item>
+ </custom:list>
+ </xmp>
+
+ <xmp id="_T_Tag_blink" style="display: none">
+ <custom:blink>blink text</custom:blink>
+ </xmp>
+ </body>
+</html>
Modified:
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/template_test.js
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/template_test.js?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/template_test.js
(original)
+++
incubator/shindig/trunk/features/src/test/javascript/features/opensocial-templates/template_test.js
Thu Mar 19 22:17:49 2009
@@ -384,36 +384,6 @@
assertEquals(contentNode.value, data.data);
}
-function testTag_blink() {
- var custom = os.createNamespace("custom", "http://google.com/#custom");
- /**
- * A controller that reproduces blink behavior.
- */
- custom.blink = function(node, context) { // returns HTML
- var root = document.createElement("span");
- root.appendChild(node.firstChild);
- function blink() {
- var isVisible = root.style["visibility"] == "visible";
- root.style["visibility"] = isVisible ? "hidden" : "visible";
- setTimeout(blink, 500);
- }
- root.onAttach = function() {
- blink();
- };
- return root;
- };
-
- Clock.reset();
- var outputNode = compileAndRender_("_T_Tag_blink");
- // contentNode is wrapped by <div><span>
- var contentNode = outputNode.firstChild.firstChild;
- assertEquals(contentNode.style.visibility, "visible");
- Clock.tick(500);
- assertEquals(contentNode.style.visibility, "hidden");
- Clock.tick(500);
- assertEquals(contentNode.style.visibility, "visible");
-}
-
function testHelloWorld() {
assertTemplateOutput(
'<div>Hello world!</div>',
Modified:
incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndTest.java
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndTest.java?rev=756236&r1=756235&r2=756236&view=diff
==============================================================================
---
incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndTest.java
(original)
+++
incubator/shindig/trunk/java/server/src/test/java/org/apache/shindig/server/endtoend/EndToEndTest.java
Thu Mar 19 22:17:49 2009
@@ -137,11 +137,6 @@
}
@Test
- public void testData() throws Exception {
- executeAllPageTests("opensocial-data/data_test");
- }
-
- @Test
public void testTemplates() throws Exception {
executeAllPageTests("opensocial-templates/ost_test");
}