You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by be...@apache.org on 2008/06/23 15:14:46 UTC

svn commit: r670557 - in /incubator/shindig/trunk/features: core.io/io.js core.io/iotest.js mockenv.js mocks/ mocks/env.js mocks/xhr.js pom.xml

Author: beaton
Date: Mon Jun 23 06:14:45 2008
New Revision: 670557

URL: http://svn.apache.org/viewvc?rev=670557&view=rev
Log:
Fix SHINDIG-383, unittests for io.js.

Added:
    incubator/shindig/trunk/features/core.io/iotest.js
    incubator/shindig/trunk/features/mocks/
    incubator/shindig/trunk/features/mocks/env.js
    incubator/shindig/trunk/features/mocks/xhr.js
Removed:
    incubator/shindig/trunk/features/mockenv.js
Modified:
    incubator/shindig/trunk/features/core.io/io.js
    incubator/shindig/trunk/features/pom.xml

Modified: incubator/shindig/trunk/features/core.io/io.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/io.js?rev=670557&r1=670556&r2=670557&view=diff
==============================================================================
--- incubator/shindig/trunk/features/core.io/io.js (original)
+++ incubator/shindig/trunk/features/core.io/io.js Mon Jun 23 06:14:45 2008
@@ -46,7 +46,7 @@
    */
   function makeXhr() {
     if (window.XMLHttpRequest) {
-      return new XMLHttpRequest();
+      return new window.XMLHttpRequest();
     } else if (window.ActiveXObject) {
       var x = new ActiveXObject("Msxml2.XMLHTTP");
       if (!x) {

Added: incubator/shindig/trunk/features/core.io/iotest.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/core.io/iotest.js?rev=670557&view=auto
==============================================================================
--- incubator/shindig/trunk/features/core.io/iotest.js (added)
+++ incubator/shindig/trunk/features/core.io/iotest.js Mon Jun 23 06:14:45 2008
@@ -0,0 +1,494 @@
+/*
+ * 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.
+ */
+
+var gadgets = gadgets || {};
+
+function IoTest(name) {
+  TestCase.call(this, name);
+};
+IoTest.inherits(TestCase);
+
+IoTest.prototype.setUp = function() {
+  this.oldGetUrlParameters = gadgets.util.getUrlParameters;
+  gadgets.util.getUrlParameters = function() {
+    return { "st" : "authtoken", "url" : "http://www.gadget.com/gadget.xml" };
+  };
+  if (!shindig.auth) {
+    shindig.auth = new shindig.Auth();
+  }
+
+  this.fakeXhrs = new fakeXhr.Factory(this);
+  this.oldXMLHttpRequest = window.XMLHTTPRequest;
+  window.XMLHttpRequest = this.fakeXhrs.getXhrConstructor();
+
+  gadgets.config.init({ "core.io" : {
+      "proxyUrl" : "http://www.example.com/proxy?url=%url%&refresh=%refresh%",
+      "jsonProxyUrl" : "http://www.example.com/json" }}); 
+};
+
+IoTest.prototype.tearDown = function() {
+  gadgets.util.getUrlParameters = this.oldGetUrlParameters;
+  window.XMLHttpRequest = this.oldXMLHTTPRequest;
+};
+
+IoTest.prototype.testEncodeDecode = function() {
+  // BEE: remove this, just testing workaround for
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=217257
+  var s = "http://www.example.com/somepage";
+  var enc = encodeURIComponent(s);
+  var dec = unescape(enc);
+  this.assertEquals(s, dec);
+};
+
+IoTest.prototype.testGetProxyUrl = function() {
+  var proxied = gadgets.io.getProxyUrl("http://target.example.com/image.gif");
+  this.assertEquals(
+      "http://www.example.com/proxy?url=http%3a%2f%2ftarget.example.com%2f" +
+          "image.gif&refresh=3600",
+      proxied);
+};
+
+IoTest.prototype.testGetProxyUrl_nondefaultRefresh = function() {
+  var proxied = gadgets.io.getProxyUrl("http://target.example.com/image.gif",
+      { 'REFRESH_INTERVAL' : 30 });
+  this.assertEquals(
+      "http://www.example.com/proxy?url=http%3a%2f%2ftarget.example.com%2f" +
+          "image.gif&refresh=30",
+      proxied);
+};
+
+// Disabling this test for now, because it uncovered a bug ingadgets.io.js, but
+// I don't want to make functional changes at the same time as I refactor
+// it for testing.
+/*
+IoTest.prototype.testGetProxyUrl_disableCache = function() {
+  var proxied = gadgets.io.getProxyUrl("http://target.example.com/image.gif",
+      { 'REFRESH_INTERVAL' : 0 });
+  this.assertEquals(
+      "http://www.example.com/proxy?url=http%3a%2f%2ftarget.example.com%2f" +
+          "image.gif&refresh=0",
+      proxied);
+};
+*/
+
+IoTest.prototype.testEncodeValues = function() {
+  var x = gadgets.io.encodeValues({ 'foo' : 'bar' });
+  this.assertEquals("foo=bar", x);
+};
+
+IoTest.prototype.setArg = function(req, inBody, name, value) {
+  if (inBody) {
+    req.setBodyArg(name, value);
+  } else {
+    req.setQueryArg(name, value);
+  }
+}
+
+IoTest.prototype.setStandardArgs = function(req, inBody) {
+  this.setArg(req, inBody, "refresh", "3600");
+  this.setArg(req, inBody, "st", "");
+  this.setArg(req, inBody, "contentType", "TEXT");
+  this.setArg(req, inBody, "oauthService", "");
+  this.setArg(req, inBody, "authz", "");
+  this.setArg(req, inBody, "bypassSpecCache", "");
+  this.setArg(req, inBody, "signViewer", "true");
+  this.setArg(req, inBody, "oauthToken", "");
+  this.setArg(req, inBody, "signOwner", "true");
+  this.setArg(req, inBody, "getSummaries", "false");
+  this.setArg(req, inBody, "gadget", "http://www.gadget.com/gadget.xml");
+  this.setArg(req, inBody, "oauthState", "");
+  this.setArg(req, inBody, "headers", "");
+  this.setArg(req, inBody, "numEntries", "3");
+  this.setArg(req, inBody, "postData", "");
+  this.setArg(req, inBody, "httpMethod", "GET");
+};
+
+IoTest.prototype.makeFakeResponse = function(text) {
+  return new fakeXhr.Response("throw 1; < don't be evil' >" + text, 200);
+};
+
+IoTest.prototype.testNoMethod = function() {
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      });
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testPost = function() {
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("httpMethod", "POST");
+  req.setBodyArg("postData", "foo=bar");
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("refresh", null);
+  req.setBodyArg("headers", "Content-Type=application%2fx-www-form-urlencoded");
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params[gadgets.io.RequestParameters.METHOD] = "POST";
+  params[gadgets.io.RequestParameters.POST_DATA] = "foo=bar";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testPut = function() {
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("httpMethod", "PUT");
+  req.setBodyArg("postData", "abcd");
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("refresh", null);
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params[gadgets.io.RequestParameters.METHOD] = "PUT";
+  params[gadgets.io.RequestParameters.POST_DATA] = "abcd";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testSignedGet = function() {
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("signOwner", "true");
+  req.setBodyArg("signViewer", "true");
+  req.setBodyArg("authz", "signed");
+  req.setBodyArg("st", "authtoken");
+  req.setBodyArg("refresh", null);
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params["AUTHORIZATION"] = "SIGNED";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testSignedPost = function() {
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("signOwner", "true");
+  req.setBodyArg("signViewer", "true");
+  req.setBodyArg("authz", "signed");
+  req.setBodyArg("st", "authtoken");
+  req.setBodyArg("refresh", null);
+  req.setBodyArg("httpMethod", "POST");
+  req.setBodyArg("headers", "Content-Type=application%2fx-www-form-urlencoded");
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params["AUTHORIZATION"] = "SIGNED";
+  params["METHOD"] = "POST";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testOAuth = function() {
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("authz", "authenticated");
+  req.setBodyArg("st", "authtoken");
+  req.setBodyArg("refresh", null);
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(gadgets.json.stringify(
+      { 'http://target.example.com/somepage' : { 
+          'approvalUrl' : 'http://sp.example.com/authz?oauth_token=foo',
+          'oauthState' : 'newState' 
+         }
+      }));
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params["AUTHORIZATION"] = "AUTHENTICATED";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals("http://sp.example.com/authz?oauth_token=foo",
+      resp.approvalUrl);
+
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("authz", "authenticated");
+  req.setBodyArg("st", "authtoken");
+  req.setBodyArg("oauthState", "newState");
+  req.setBodyArg("refresh", null);
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'personal data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params["AUTHORIZATION"] = "AUTHENTICATED";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals("personal data", resp.text);
+};
+
+IoTest.prototype.testJson = function() {
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+  req.setQueryArg("contentType", "JSON");
+
+  var resp = this.makeFakeResponse(gadgets.json.stringify(
+      { 'http://target.example.com/somepage' : { 
+          'body' : '{ "somejsonparam" : 3 }',
+         }
+      }));
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      {
+        "CONTENT_TYPE" : "JSON",
+      });
+  this.assertEquals(3, resp.data.somejsonparam);
+};
+
+IoTest.prototype.testJson_malformed = function() {
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+  req.setQueryArg("contentType", "JSON");
+
+  var resp = this.makeFakeResponse(gadgets.json.stringify(
+      { 'http://target.example.com/somepage' : { 
+          'body' : '{ bogus : 3 }',
+         }
+      }));
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      {
+        "CONTENT_TYPE" : "JSON",
+      });
+  this.assertEquals("failed to parse JSON", resp.errors[0]);
+};
+
+IoTest.prototype.testPreload = function() {
+  gadgets.io.preloaded_ = {
+    "http://target.example.com/somepage" : {
+      "rc" : 200,
+      "body" : "preloadedbody",
+    }
+  };
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      });
+
+  this.assertEquals("preloadedbody", resp.text);
+
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+
+  var resp = this.makeFakeResponse(gadgets.json.stringify(
+      { 'http://target.example.com/somepage' : { 
+          'body' : 'not preloaded',
+         }
+      }));
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      });
+  this.assertEquals("not preloaded", resp.text);
+};
+
+IoTest.prototype.testPreloadMiss_postRequest = function() {
+  gadgets.io.preloaded_ = {
+    "http://target.example.com/somepage" : {
+      "rc" : 200,
+      "body" : "preloadedbody",
+    }
+  };
+
+  var req = new fakeXhr.Expectation("POST", "http://www.example.com/json");
+  this.setStandardArgs(req, true);
+  req.setBodyArg("httpMethod", "POST");
+  req.setBodyArg("postData", "foo=bar");
+  req.setBodyArg("url", "http://target.example.com/somepage");
+  req.setBodyArg("refresh", null);
+  req.setBodyArg("headers", "Content-Type=application%2fx-www-form-urlencoded");
+  req.setHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  params[gadgets.io.RequestParameters.METHOD] = "POST";
+  params[gadgets.io.RequestParameters.POST_DATA] = "foo=bar";
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testPreloadMiss_wrongUrl = function() {
+  gadgets.io.preloaded_ = {
+    "http://target.example.com/somepage2" : {
+      "rc" : 200,
+      "body" : "preloadedbody",
+    }
+  };
+
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+
+  var resp = this.makeFakeResponse(
+      "{ 'http://target.example.com/somepage' : { 'body' : 'some data' }}");
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  var params = {};
+  gadgets.io.makeRequest(
+      "http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      },
+      params);
+  this.assertEquals('some data', resp.text);
+};
+
+IoTest.prototype.testPreload_error404 = function() {
+  gadgets.io.preloaded_ = {
+    "http://target.example.com/somepage" : {
+      "rc" : 404,
+    }
+  };
+
+  var req = new fakeXhr.Expectation("GET", "http://www.example.com/json");
+  this.setStandardArgs(req, false);
+  req.setQueryArg("url", "http://target.example.com/somepage");
+
+  var resp = this.makeFakeResponse(gadgets.json.stringify(
+      { 'http://target.example.com/somepage' : { 
+          'body' : 'not preloaded',
+         }
+      }));
+
+  this.fakeXhrs.expect(req, resp);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      });
+  this.assertEquals("Error 404", resp.errors[0]);
+
+  var resp = null;
+  gadgets.io.makeRequest("http://target.example.com/somepage",
+      function(data) {
+        resp = data;
+      });
+  this.assertEquals("not preloaded", resp.text);
+};

Added: incubator/shindig/trunk/features/mocks/env.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/mocks/env.js?rev=670557&view=auto
==============================================================================
--- incubator/shindig/trunk/features/mocks/env.js (added)
+++ incubator/shindig/trunk/features/mocks/env.js Mon Jun 23 06:14:45 2008
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * Provides a simulated browser environment.
+ * TODO Port John Resig's env.js.
+ */
+
+var document = {
+  location: {
+    href: "http://localhost"
+  }
+};
+
+var window = {};
+

Added: incubator/shindig/trunk/features/mocks/xhr.js
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/mocks/xhr.js?rev=670557&view=auto
==============================================================================
--- incubator/shindig/trunk/features/mocks/xhr.js (added)
+++ incubator/shindig/trunk/features/mocks/xhr.js Mon Jun 23 06:14:45 2008
@@ -0,0 +1,247 @@
+/*
+ * 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
+ *
+ * Provides a simulated XMLHttpRequest object.
+ *
+ * To use, create a FakeXhrFactory, then populate the factory
+ * with FakeXhrExpectation and FakeXhrResponse objects.
+ */
+
+var fakeXhr = fakeXhr || {};
+
+/**
+ * @class
+ * What XHR to expect.  Requests are matched based on method, url, headers
+ * query string parameters, and body parameters.  Parameter ordering does
+ * not matter.
+ *
+ * Parameters are assumed to be HTML form encoded.
+ *
+ * @name fakeXhr.Expectation
+ */
+
+/**
+ * Create a request.
+ *
+ * @constructor
+ */
+fakeXhr.Expectation = function(method, url) {
+  this.method = method;
+  this.url = url;
+  this.queryArgs = {};
+  this.bodyArgs = {};
+  this.headers = {};
+};
+
+fakeXhr.Expectation.prototype.setMethod = function(method) {
+  this.method = method;
+};
+
+fakeXhr.Expectation.prototype.setUrl = function(url) {
+  this.url = url;
+  var query = url.indexOf("?");
+  if (query !== -1) {
+    this.queryArgs = this.parseForm(url.substr(query+1));
+    this.url = url.substr(0, query);
+  }
+};
+
+fakeXhr.Expectation.prototype.setBodyArg = function(name, value) {
+  if (value !== null) {
+    this.bodyArgs[name] = value;
+  } else {
+    delete this.bodyArgs[name];
+  }
+};
+
+fakeXhr.Expectation.prototype.setQueryArg = function(name, value) {
+  if (value !== null) {
+    this.queryArgs[name] = value;
+  } else {
+    delete this.queryArgs[name];
+  }
+};
+
+fakeXhr.Expectation.prototype.setHeader = function(name, value) {
+  if (value !== null) {
+    this.headers[name] = value;
+  } else {
+    delete this.headers[name];
+  }
+};
+
+fakeXhr.Expectation.prototype.parseForm = function(form) {
+  var result = {};
+  if (form) {
+    var pairs = form.split("&");
+    for (var i=0; i < pairs.length; ++i) {
+      var arg = pairs[i].split("=");
+      // We use unescape here instead of decodeURIComponent because of a bug
+      // in Rhino: https://bugzilla.mozilla.org/show_bug.cgi?id=217257.
+      // Rhino fixed this ages ago, but there hasn't been a new release of
+      // the Berlios jsunit package that incorporates the fix.
+      var name = unescape(arg[0]);
+      var value = unescape(arg[1]);
+      result[name] = value;
+    }
+  }
+  return result;
+};
+
+fakeXhr.Expectation.prototype.toString = function() {
+  return gadgets.json.stringify(this);
+};
+
+fakeXhr.Expectation.prototype.checkMatch = function(testcase, other) {
+  testcase.assertEquals(this.method, other.method);
+  testcase.assertEquals(this.url, other.url);
+  this.checkTableEquals(testcase, "query", this.queryArgs, other.queryArgs);
+  this.checkTableEquals(testcase, "body", this.bodyArgs, other.bodyArgs);
+  this.checkTableEquals(testcase, "header", this.headers, other.headers);
+};
+
+fakeXhr.Expectation.prototype.checkTableEquals = function(testcase, type, x, y) {
+  // Check for things in x that aren't in y
+  var member;
+  for (member in x) if (x.hasOwnProperty(member)) {
+    testcase.assertEquals(
+        "wrong value for " + type + " parameter " + member,
+        x[member], y[member]);
+  }
+  // Check for things in y that aren't in x
+  for (member in y) if (y.hasOwnProperty(member)) {
+    testcase.assertEquals(
+        "extra value for " + type + " parameter " + member,
+        x[member], y[member]);
+  }
+};
+
+
+/**
+ * @class
+ * What data to return for an XMLHttpRequest.
+ *
+ * @name fakeXhr.Response
+ */
+
+/**
+ * Create a response.
+ *
+ * @constructor
+ */
+fakeXhr.Response = function(responseText, status) {
+  this.responseText = responseText;
+  this.status = status || 200;
+};
+
+fakeXhr.Response.prototype.getResponseText = function() {
+  return this.responseText;
+};
+
+fakeXhr.Response.prototype.getStatus = function() {
+  return this.status;
+};
+
+
+/**
+ * @class
+ * Holds a list of expected XMLHTTPRequests and responses.
+ *
+ * @name fakeXhr.Factory
+ */
+
+/**
+ * Create a factory to collect requests and responses.
+ *
+ * @constructor
+ */
+fakeXhr.Factory = function(testcase) {
+  this.testcase = testcase;
+  this.expectations = [];
+};
+
+/**
+ * Expect a certain request and return the specified response.
+ */
+fakeXhr.Factory.prototype.expect = function(expect, response) {
+  this.expectations.push({ "expect" : expect, "response" : response});
+};
+
+/**
+ * Finds the response matching a particular request.
+ */
+fakeXhr.Factory.prototype.find = function(req) {
+  this.testcase.assertTrue(this.expectations.length > 0);
+  var next = this.expectations.shift();
+  next.expect.checkMatch(this.testcase, req);
+  return next.response;
+};
+
+/**
+ * Create a new XMLHttpRequest that will be fed from the expectations
+ * associated with this factory.
+ */
+fakeXhr.Factory.prototype.getXhrConstructor = function() {
+  var factory = this;
+  return function() {
+    return new fakeXhr.Request(factory);
+  };
+};
+
+
+/**
+ * @class
+ * An XMLHTTPRequest object
+ *
+ * @name fakeXhr.Factory
+ */
+
+/**
+ * Create a new XMLHTTPRequest, with response data returned from the
+ * specified factory.
+ *
+ * @constructor
+ */
+fakeXhr.Request = function(factory) {
+  this.factory = factory;
+  this.actual = new fakeXhr.Expectation(null, null);
+  this.response = null;
+  this.onreadystatechange = null;
+};
+
+fakeXhr.Request.prototype.open = function(method, url, async) {
+  this.actual.setMethod(method);
+  this.actual.setUrl(url);
+};
+
+fakeXhr.Request.prototype.setRequestHeader = function(name, value) {
+  this.actual.setHeader(name, value);
+};
+
+fakeXhr.Request.prototype.send = function(body) {
+  this.actual.bodyArgs = this.actual.parseForm(body);
+  var response = this.factory.find(this.actual);
+  this.readyState = 4;
+  this.status = response.status;
+  this.responseText = response.responseText;
+  this.onreadystatechange();
+};

Modified: incubator/shindig/trunk/features/pom.xml
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/features/pom.xml?rev=670557&r1=670556&r2=670557&view=diff
==============================================================================
--- incubator/shindig/trunk/features/pom.xml (original)
+++ incubator/shindig/trunk/features/pom.xml Mon Jun 23 06:14:45 2008
@@ -86,11 +86,14 @@
               <configuration>
                 <sourceDirectory>${basedir}</sourceDirectory>
                 <sources>
-                  <source>mockenv.js</source>
+                  <source>mocks/env.js</source>
+                  <source>mocks/xhr.js</source>
                   <source>core/config.js</source>
+                  <source>core/json.js</source>
                   <source>core/auth.js</source>
                   <source>core/util.js</source>
                   <source>core/prefs.js</source>
+                  <source>core.io/io.js</source>
                   <source>views/views.js</source>
                   <source>opensocial-reference/opensocial.js</source>
                   <source>opensocial-reference/activity.js</source>
@@ -125,6 +128,7 @@
                     <type>TESTCASES</type>
                     <includes>
                       <include>core/*test.js</include>
+                      <include>core.io/*test.js</include>
                       <include>views/*test.js</include>
                     </includes>
                   </testSuite>