You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by et...@apache.org on 2008/03/11 10:53:01 UTC

svn commit: r635862 [4/5] - in /incubator/shindig/trunk: config/ features/core/ features/setprefs/ java/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/ java/gadgets/src/main/java/org/apache/shindig/gadgets/http/ java/gadgets/src/main/ja...

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/View.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/View.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/View.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/View.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+package org.apache.shindig.gadgets.spec;
+import org.apache.shindig.gadgets.Substitutions;
+import org.apache.shindig.util.XmlUtil;
+
+import org.w3c.dom.Element;
+
+import java.net.URI;
+import java.util.List;
+
+/**
+ * Represents a Content section, but normalized into an individual
+ * view value after views are split on commas.
+ */
+public class View {
+
+  /**
+   * Content@view
+   */
+  private final String name;
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Content@type
+   */
+  private final ContentType type;
+  public ContentType getType() {
+    return type;
+  }
+
+  /**
+   * Content@href
+   *
+   * All substitutions
+   */
+  private URI href;
+  public URI getHref() {
+    return href;
+  }
+
+  /**
+   * Content@quirks
+   */
+  private final boolean quirks;
+  public boolean getQuirks() {
+    return quirks;
+  }
+
+  /**
+   * Content#CDATA
+   *
+   * All substitutions
+   */
+  private String content;
+  public String getContent() {
+    return content;
+  }
+
+  /**
+   * Whether or not the content section has any __UP_ hangman variables.
+   */
+  private final boolean needsUserPrefSubstitution;
+  public boolean needsUserPrefSubstitution() {
+    return needsUserPrefSubstitution;
+  }
+
+  /**
+   * Creates a new view by performing hangman substitution. See field comments
+   * for details on what gets substituted.
+   *
+   * @param substituter
+   * @return The substituted view.
+   */
+  public View substitute(Substitutions substituter) {
+    View view = new View(this);
+    view.content = substituter.substituteString(null, content);
+    view.href = substituter.substituteUri(null, href);
+    return view;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder buf = new StringBuilder();
+    buf.append("<Content type=\"")
+       .append(type.toString().toLowerCase())
+       .append("\" href=\"")
+       .append(href)
+       .append("\" view=\"")
+       .append(name)
+       .append("\">")
+       .append(content)
+       .append("</Content>");
+    return buf.toString();
+  }
+
+  /**
+   * @param elements List of all views, in order, that make up this view.
+   *     An ordered list is required per the spec, since values must
+   *     overwrite one another.
+   * @throws SpecParserException
+   */
+  public View(String name, List<Element> elements) throws SpecParserException {
+    this.name = name;
+
+    boolean quirks = true;
+    URI href = null;
+    ContentType type = null;
+    StringBuilder content = new StringBuilder();
+    for (Element element : elements) {
+      String contentType = XmlUtil.getAttribute(element, "type");
+      if (contentType != null) {
+        ContentType newType = ContentType.parse(contentType);
+        if (type != null && newType != type) {
+          throw new SpecParserException(
+              "You may not mix content types in the same view.");
+        } else {
+          type = newType;
+        }
+      }
+      href = XmlUtil.getUriAttribute(element, "href", href);
+      quirks = XmlUtil.getBoolAttribute(element, "quirks", quirks);
+      content.append(element.getTextContent());
+    }
+    this.content = content.toString();
+    this.needsUserPrefSubstitution = this.content.indexOf("__UP_") != -1;
+    this.quirks = quirks;
+    this.href = href;
+    this.type = type;
+    if (type == ContentType.URL && this.href == null) {
+      throw new SpecParserException(
+          "Content@href must be set when Content@type is \"url\".");
+    } else if (type == ContentType.HTML && this.href != null) {
+      throw new SpecParserException(
+          "Content@href must not be set when Content@type is not \"url\".");
+    }
+  }
+
+  /**
+   * Allows the creation of a view from an existing view so that localization
+   * can be performed.
+   *
+   * @param view
+   */
+  private View(View view) {
+    needsUserPrefSubstitution = view.needsUserPrefSubstitution;
+    name = view.name;
+    type = view.type;
+    quirks = view.quirks;
+  }
+
+  /**
+   * Possible values for Content@type
+   */
+  public enum ContentType {
+    HTML, URL;
+
+    /**
+     * @param value
+     * @return The parsed value (defaults to html)
+     */
+    public static ContentType parse(String value) {
+      return "url".equals(value) ? URL : HTML;
+    }
+  }
+}
\ No newline at end of file

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/file/XmlStateFileFetcher.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/file/XmlStateFileFetcher.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/file/XmlStateFileFetcher.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/social/file/XmlStateFileFetcher.java Tue Mar 11 02:52:52 2008
@@ -5,7 +5,6 @@
 import org.apache.shindig.gadgets.BasicRemoteContentFetcher;
 import org.apache.shindig.gadgets.RemoteContent;
 import org.apache.shindig.gadgets.RemoteContentRequest;
-import org.apache.shindig.gadgets.ProcessingOptions;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
@@ -45,8 +44,7 @@
     // TODO: Eventually get the fetcher and processing options from a
     // config file, just like the GadgetServer
     RemoteContentFetcher fetcher = new BasicRemoteContentFetcher(1024 * 1024);
-    RemoteContent xml = fetcher.fetch(new RemoteContentRequest(uri),
-        new ProcessingOptions());
+    RemoteContent xml = fetcher.fetch(new RemoteContentRequest(uri));
 
     InputSource is = new InputSource(new StringReader(
         xml.getResponseAsString()));

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/HashUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/HashUtil.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/HashUtil.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/HashUtil.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Routines for producing hashes.
+ */
+public class HashUtil {
+  /**
+   * Produces a checksum for the given input data.
+   *
+   * @param data
+   * @return The checksum.
+   */
+  public static String checksum(byte[] data) {
+    MessageDigest md;
+    try {
+      md = MessageDigest.getInstance("MD5");
+    } catch (NoSuchAlgorithmException noMD5) {
+      try {
+        md = MessageDigest.getInstance("SHA");
+      } catch (NoSuchAlgorithmException noSha) {
+        throw new RuntimeException("No suitable MessageDigest found!");
+      }
+    }
+    byte[] hash = md.digest(data);
+    // Convert to hex. possibly change to base64 in the future for smaller
+    // signatures.
+    StringBuffer hexString = new StringBuffer();
+    for (byte b : hash) {
+      hexString.append(Integer.toHexString(0xFF & b));
+    }
+    return hexString.toString();
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlException.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlException.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlException.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlException.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+package org.apache.shindig.util;
+
+public class XmlException extends Exception {
+  public XmlException(String message, Exception cause) {
+    super(message, cause);
+  }
+  public XmlException(Exception cause) {
+    super(cause);
+  }
+  public XmlException(String message) {
+    super(message);
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/util/XmlUtil.java Tue Mar 11 02:52:52 2008
@@ -18,12 +18,20 @@
 
 package org.apache.shindig.util;
 
+import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
 
+import java.io.IOException;
+import java.io.StringReader;
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
 public class XmlUtil {
 
   /**
@@ -79,5 +87,52 @@
    */
   public static URI getUriAttribute(Node node, String attr) {
     return getUriAttribute(node, attr, null);
+  }
+
+  /**
+   * Retrieves an attribute as a boolean.
+   *
+   * @param node
+   * @param attr
+   * @param def
+   * @return True if the attribute exists and is not equal to "false"
+   *    false if equal to "false", and def if not present.
+   */
+  public static boolean getBoolAttribute(Node node, String attr, boolean def) {
+    String value = getAttribute(node, attr);
+    if (value == null) {
+      return def;
+    }
+    return !"false".equals(value);
+  }
+
+  /**
+   * @param node
+   * @param attr
+   * @return True if the attribute exists and is not equal to "false"
+   *    false otherwise.
+   */
+  public static boolean getBoolAttribute(Node node, String attr) {
+    return getBoolAttribute(node, attr, false);
+  }
+
+  /**
+   * Attempts to parse the input xml into a single element.
+   * @param xml
+   * @return The document object
+   * @throws XmlException if a parse error occured.
+   */
+  public static Element parse(String xml) throws XmlException {
+    try {
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      InputSource is = new InputSource(new StringReader(xml.trim()));
+      return factory.newDocumentBuilder().parse(is).getDocumentElement();
+    } catch (SAXException e) {
+      throw new XmlException(e);
+    } catch (ParserConfigurationException e) {
+      throw new XmlException(e);
+    } catch (IOException e) {
+      throw new XmlException(e);
+    }
   }
 }

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicRemoteContentFetcherTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicRemoteContentFetcherTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicRemoteContentFetcherTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/BasicRemoteContentFetcherTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+package org.apache.shindig.gadgets;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.net.URI;
+
+public class BasicRemoteContentFetcherTest extends TestCase {
+  private RemoteContentFetcher fetcher
+      = new BasicRemoteContentFetcher(Integer.MAX_VALUE);
+
+  public void testFetch() throws Exception {
+    String content = "Hello, world!";
+    File temp = File.createTempFile(this.getName(), ".txt");
+    temp.deleteOnExit();
+    BufferedWriter out = new BufferedWriter(new FileWriter(temp));
+    out.write(content);
+    out.close();
+    RemoteContentRequest request = new RemoteContentRequest(temp.toURI());
+    RemoteContent response = fetcher.fetch(request);
+    assertEquals(RemoteContent.SC_OK, response.getHttpStatusCode());
+    assertEquals(content, response.getResponseAsString());
+  }
+
+  public void testNotExists() throws Exception {
+    RemoteContentRequest request
+        = new RemoteContentRequest(new URI("file:///does/not/exist"));
+    RemoteContent response = fetcher.fetch(request);
+    assertEquals(RemoteContent.SC_NOT_FOUND, response.getHttpStatusCode());
+  }
+
+  // TODO simulate fake POST requests, headers, options, etc.
+}
\ No newline at end of file

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/EasyMockTestCase.java Tue Mar 11 02:52:52 2008
@@ -17,9 +17,9 @@
  */
 package org.apache.shindig.gadgets;
 
-import junit.framework.TestCase;
-
 import org.easymock.EasyMock;
+
+import junit.framework.TestCase;
 
 import java.util.ArrayList;
 import java.util.List;

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetFeatureRegistryTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetFeatureRegistryTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetFeatureRegistryTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetFeatureRegistryTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class GadgetFeatureRegistryTest extends TestCase {
+  private GadgetFeatureRegistry registry;
+  private static final GadgetFeatureFactory DUMMY_FEATURE
+      = new GadgetFeatureFactory() {
+          // Dummy feature.
+          public GadgetFeature create() {
+            return new GadgetFeature() {};
+          }
+        };
+
+  private static final String FEATURE_NAME = "feature";
+  private static final String DEP_NAME = "dependency";
+  private static final String[] FEATURE_LIST = new String[] {
+    "feature0", "feature1", "feature2", "feature3"
+  };
+  private static final String UNREGISTERED_FEATURE = "unregistered";
+  @Override
+  public void setUp() throws Exception {
+    // TODO: Add a mock fetcher here and add tests for retrieving remote files
+    registry = new GadgetFeatureRegistry(null, null);
+  }
+
+
+  public void testDependencyChain() throws Exception {
+    registry.register(FEATURE_NAME, Arrays.asList(DEP_NAME), DUMMY_FEATURE);
+    registry.register(DEP_NAME, null, DUMMY_FEATURE);
+
+    GadgetFeatureRegistry.Entry entry = registry.getEntry(FEATURE_NAME);
+    // Object comparison is OK here.
+    assertEquals(DUMMY_FEATURE, entry.getFeature());
+    assertEquals(DEP_NAME, entry.getDependencies().iterator().next());
+  }
+
+  public void testGetAllFeatures() throws Exception {
+    for (String feature : FEATURE_LIST) {
+      registry.register(feature, Arrays.asList(DEP_NAME), DUMMY_FEATURE);
+    }
+
+    Map<String, GadgetFeatureRegistry.Entry> entries
+        = registry.getAllFeatures();
+
+    for (String feature : FEATURE_LIST) {
+      GadgetFeatureRegistry.Entry entry = entries.get(feature);
+      assertNotNull(entry);
+      assertEquals(feature, entry.getName());
+      assertEquals(DEP_NAME, entry.getDependencies().iterator().next());
+    }
+  }
+
+  public void testGetIncluded() throws Exception {
+    Set<String> requested = new HashSet<String>();
+    for (String feature : FEATURE_LIST) {
+      registry.register(feature, Arrays.asList(DEP_NAME), DUMMY_FEATURE);
+      requested.add(feature);
+    }
+
+    registry.register(DEP_NAME, null, DUMMY_FEATURE);
+
+    requested.add(UNREGISTERED_FEATURE);
+
+    Set<GadgetFeatureRegistry.Entry> found
+        = new HashSet<GadgetFeatureRegistry.Entry>();
+    Set<String> missing = new HashSet<String>();
+    registry.getIncludedFeatures(requested, found, missing);
+
+    assertEquals(1, missing.size());
+    assertEquals(UNREGISTERED_FEATURE, missing.iterator().next());
+
+    for (String feature : FEATURE_LIST) {
+      boolean contains = false;
+      for (GadgetFeatureRegistry.Entry entry : found) {
+        if (entry.getName().equals(feature)) {
+          contains = true;
+        }
+      }
+      if (!contains) {
+        fail("Feature " + feature + " not included in needed set.");
+      }
+    }
+
+    boolean contains = false;
+    for (GadgetFeatureRegistry.Entry entry : found) {
+      if (entry.getName().equals(DEP_NAME)) {
+        contains = true;
+      } else if (entry.getName().equals(UNREGISTERED_FEATURE)) {
+        fail("Unregistered dependency included in needed set.");
+      }
+    }
+    if (!contains) {
+      fail("Transitive dependency " + DEP_NAME + " not included in needed set");
+    }
+
+    assertEquals(UNREGISTERED_FEATURE, missing.iterator().next());
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetServerTest.java Tue Mar 11 02:52:52 2008
@@ -17,120 +17,98 @@
  */
 package org.apache.shindig.gadgets;
 
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.DATETIME_ID;
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.DATETIME_SPEC;
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.DATETIME_URI;
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.DATETIME_URI_STRING;
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.DATETIME_XML;
-import static org.apache.shindig.gadgets.GadgetSpecTestFixture.EN_US_LOCALE;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
 
-import java.util.concurrent.Executors;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.MessageBundle;
 
-public class GadgetServerTest extends EasyMockTestCase {
-  GadgetServer gadgetServer;
-  final RemoteContentFetcher fetcher = mock(RemoteContentFetcher.class);
-  @SuppressWarnings(value="unchecked")
-  final GadgetDataCache<GadgetSpec> specCache = mock(GadgetDataCache.class);
-  @SuppressWarnings(value="unchecked")
-  final GadgetDataCache<MessageBundle> bundleCache = mock(GadgetDataCache.class);
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GadgetServerTest extends GadgetTestFixture {
+
+  private final static URI SPEC_URL = URI.create("http://example.org/g.xml");
+  private final static URI BUNDLE_URL = URI.create("http://example.org/m.xml");
+  private final static GadgetContext BASIC_CONTEXT = new GadgetContext() {
+    @Override
+    public URI getUrl() {
+      return SPEC_URL;
+    }
+  };
+  private final static String BASIC_SPEC_XML
+      = "<Module>" +
+        "  <ModulePrefs title=\"GadgetServerTest\"/>" +
+        "  <Content type=\"html\">Hello, world!</Content>" +
+        "</Module>";
+
+  private final static String BASIC_BUNDLE_XML
+      = "<messagebundle>" +
+        "  <msg name=\"title\">TITLE</msg>" +
+       "</messagebundle>";
+
+  public void testGadgetSpecLookup() throws Exception {
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, BASIC_SPEC_XML);
+    RemoteContentRequest req = new RemoteContentRequest(SPEC_URL);
 
-  void initServer(GadgetServerConfigReader customConfig) throws GadgetException {
-    GadgetServerConfig config = new GadgetServerConfig();
-
-    if (customConfig != null) {
-      config.copyFrom(customConfig);
-    }
-
-    if (config.getExecutor() == null) {
-      config.setExecutor(Executors.newCachedThreadPool());
-    }
-
-    if (config.getSpecCache() == null) {
-      config.setSpecCache(specCache);
-    }
-
-    if (config.getMessageBundleCache() == null) {
-      config.setMessageBundleCache(bundleCache);
-    }
-
-    if (config.getFeatureRegistry() == null) {
-      config.setFeatureRegistry(new GadgetFeatureRegistry(null));
-    }
-
-    if (config.getContentFetcher() == null) {
-      config.setContentFetcher(fetcher);
-    }
-
-    gadgetServer = new GadgetServer(config);
-  }
-
-  public void testGadgetSpecNotInCache() throws Exception {
-    initServer(null);
-    RemoteContent results = new RemoteContent(200, DATETIME_XML.getBytes(), null);
-    ProcessingOptions options = new ProcessingOptions();
-
-    RemoteContentRequest req = new RemoteContentRequest(DATETIME_URI);
-
-    expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
-    expect(fetcher.fetch(eq(req),
-                         eq(options))).andReturn(results);
-    specCache.put(eq(DATETIME_URI_STRING), isA(GadgetSpec.class));
+    expect(specFetcher.fetch(eq(SPEC_URL), eq(false))).andReturn(spec);
     replay();
 
-    Gadget gadget = gadgetServer.processGadget(DATETIME_ID, UserPrefs.EMPTY, EN_US_LOCALE,
-                                               RenderingContext.GADGET, options);
+    Gadget gadget = gadgetServer.processGadget(BASIC_CONTEXT);
     verify();
   }
 
-  public void testGadgetSpecInCache() throws Exception {
-    initServer(null);
-    expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(DATETIME_SPEC);
-    replay();
+  public void testSubstitutionsDone() throws Exception {
+    String gadgetXml
+        = "<Module>" +
+          "  <ModulePrefs title=\"__MSG_title__\">" +
+          "    <Locale messages=\"" + BUNDLE_URL.toString() + "\"/>" +
+          "  </ModulePrefs>" +
+          "  <UserPref name=\"body\" datatype=\"string\"/>" +
+          "  <Content type=\"html\">__UP_body__</Content>" +
+          "</Module>";
+
+    GadgetContext context = new GadgetContext() {
+      @Override
+      public URI getUrl() {
+        return SPEC_URL;
+      }
+
+      @Override
+      public UserPrefs getUserPrefs() {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("body", "BODY");
+        return new UserPrefs(map);
+      }
+    };
 
-    Gadget gadget = gadgetServer.processGadget(DATETIME_ID, UserPrefs.EMPTY, EN_US_LOCALE,
-                                               RenderingContext.GADGET, null);
-    assertSame(DATETIME_SPEC, gadget.getBaseSpec());
-    verify();
-  }
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, gadgetXml);
+    MessageBundle bundle = new MessageBundle(BASIC_BUNDLE_XML);
 
-  public void testBasicGadget() throws Exception {
-    initServer(null);
-    RemoteContent results = new RemoteContent(200, DATETIME_XML.getBytes(), null);
-    ProcessingOptions options = new ProcessingOptions();
-
-    RemoteContentRequest req = new RemoteContentRequest(DATETIME_URI);
-
-    expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
-    expect(fetcher.fetch(eq(req),
-                         eq(options))).andReturn(results);
-    specCache.put(eq(DATETIME_URI_STRING), isA(GadgetSpec.class));
+    expect(specFetcher.fetch(eq(SPEC_URL), eq(false))).andReturn(spec);
+    expect(bundleFetcher.fetch(eq(BUNDLE_URL), eq(false))).andReturn(bundle);
     replay();
 
-    Gadget gadget = gadgetServer.processGadget(DATETIME_ID, UserPrefs.EMPTY, EN_US_LOCALE,
-                                               RenderingContext.GADGET, options);
-    assertEquals("Hello, World!", gadget.getTitle());
-    assertEquals("Goodbye, World!", gadget.getView(null).getData());
-    verify();
+    Gadget gadget = gadgetServer.processGadget(context);
+
+    // No verification because the cache store ops happen on separate threads
+    // and easy mock doesn't handle that properly.
+
+    assertEquals("TITLE", gadget.getSpec().getModulePrefs().getTitle());
+    assertEquals("BODY",
+        gadget.getSpec().getView(GadgetSpec.DEFAULT_VIEW).getContent());
   }
 
   public void testBlacklistedGadget() throws Exception {
-    GadgetBlacklist blacklist = mock(GadgetBlacklist.class);
-    initServer(new GadgetServerConfig().setGadgetBlacklist(blacklist));
-    expect(specCache.get(eq(DATETIME_URI_STRING))).andReturn(null);
-    expect(blacklist.isBlacklisted(eq(DATETIME_URI))).andReturn(true);
+    expect(blacklist.isBlacklisted(eq(SPEC_URL))).andReturn(true);
     replay();
 
     try {
-      gadgetServer.processGadget(DATETIME_ID, UserPrefs.EMPTY, EN_US_LOCALE,
-                                 RenderingContext.GADGET, null);
-      fail();
-    } catch (GadgetServer.GadgetProcessException ex) {
-      assertEquals(1, ex.getComponents().size());
-      assertEquals(GadgetException.Code.BLACKLISTED_GADGET,
-                   ex.getComponents().get(0).getCode());
+      gadgetServer.processGadget(BASIC_CONTEXT);
+      fail("No exception thrown when a gadget is black listed!");
+    } catch (GadgetException e) {
+      assertEquals(GadgetException.Code.BLACKLISTED_GADGET, e.getCode());
     }
     verify();
   }

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/GadgetTestFixture.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets;
+
+
+import org.apache.shindig.gadgets.http.CrossServletState;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.MessageBundle;
+
+import java.util.Set;
+import java.util.concurrent.Executors;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class GadgetTestFixture extends EasyMockTestCase {
+  public final HttpServletRequest request = mock(HttpServletRequest.class, true);
+  public final HttpServletResponse response = mock(HttpServletResponse.class, true);
+  public final GadgetServer gadgetServer;
+  public final RemoteContentFetcher fetcher = mock(RemoteContentFetcher.class, true);
+  @SuppressWarnings(value="unchecked")
+  public final DataFetcher<GadgetSpec> specFetcher = mock(DataFetcher.class, true);
+  @SuppressWarnings(value="unchecked")
+  public final DataFetcher<MessageBundle> bundleFetcher
+      = mock(DataFetcher.class);
+  public final GadgetBlacklist blacklist = mock(GadgetBlacklist.class, true);
+  public final GadgetFeatureRegistry registry;
+  public final CrossServletState state = new CrossServletState() {
+    @Override
+    public GadgetServer getGadgetServer() {
+      return gadgetServer;
+    }
+
+    @Override
+    public GadgetSigner getGadgetSigner() {
+      return null;
+    }
+
+    @Override
+    public String getJsUrl(Set<String> libs, GadgetContext context) {
+      StringBuilder bs = new StringBuilder();
+      boolean first = false;
+      for (String lib : libs) {
+        if (!first) {
+          first = true;
+        } else {
+          bs.append(":");
+        }
+        bs.append(lib);
+      }
+      return bs.toString();
+    }
+
+    @Override
+    public String getIframeUrl(Gadget gadget) {
+      return "";
+    }
+
+    @Override
+    public void init(ServletContext config) {
+
+    }
+  };
+
+  public GadgetTestFixture() {
+    GadgetServerConfig config = new GadgetServerConfig();
+    config.setExecutor(Executors.newSingleThreadExecutor());
+    config.setGadgetSpecFetcher(specFetcher);
+    config.setMessageBundleFetcher(bundleFetcher);
+    config.setContentFetcher(fetcher);
+    GadgetFeatureRegistry temp = null;
+    try {
+      temp = new GadgetFeatureRegistry(null, fetcher);
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Failed to create feature registry");
+    }
+    registry = temp;
+    config.setFeatureRegistry(registry);
+    config.setGadgetBlacklist(blacklist);
+    gadgetServer = new GadgetServer(config);
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsFeatureLoaderTest.java Tue Mar 11 02:52:52 2008
@@ -17,13 +17,16 @@
  */
 package org.apache.shindig.gadgets;
 
-import junit.framework.TestCase;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
 
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.net.URI;
 import java.util.List;
 
-public class JsFeatureLoaderTest extends TestCase {
-
-  GadgetFeatureRegistry registry;
+public class JsFeatureLoaderTest extends GadgetTestFixture {
   JsFeatureLoader loader;
 
   private static final String FEATURE_NAME = "test";
@@ -31,12 +34,11 @@
   private static final String ALT_JS_CONTENT = "function test(){while(true);}";
   private static final String SYND_A = "test";
   private static final String SYND_B = "wuwowowaefdf";
-
+  private static final URI JS_URL = URI.create("http://example.org/feature.js");
 
   @Override
   public void setUp() throws Exception {
-    registry = new GadgetFeatureRegistry(null);
-    loader = new JsFeatureLoader();
+    loader = new JsFeatureLoader(fetcher);
   }
 
   public void testBasicLoading() throws Exception {
@@ -50,8 +52,7 @@
 
     assertEquals(FEATURE_NAME, entry.getName());
     GadgetFeature feature = entry.getFeature().create();
-    List<JsLibrary> libs = feature.getJsLibraries(RenderingContext.GADGET,
-                                                  new ProcessingOptions());
+    List<JsLibrary> libs = feature.getJsLibraries(new GadgetContext());
     assertEquals(1, libs.size());
     assertEquals(JsLibrary.Type.INLINE, libs.get(0).getType());
     assertEquals(DEF_JS_CONTENT, libs.get(0).getContent());
@@ -70,22 +71,60 @@
     GadgetFeatureRegistry.Entry entry = loader.loadFeature(registry, xml);
     GadgetFeature feature = entry.getFeature().create();
     List<JsLibrary> libs;
-    libs = feature.getJsLibraries(RenderingContext.GADGET,
-                                  new SyndOptions(SYND_A));
+    libs = feature.getJsLibraries(new SyndContext(SYND_A));
+    assertEquals(DEF_JS_CONTENT, libs.get(0).getContent());
+    libs = feature.getJsLibraries(new SyndContext(SYND_B));
+    assertEquals(ALT_JS_CONTENT, libs.get(0).getContent());
+  }
+
+  public void testFileReferences() throws Exception {
+    File temp = File.createTempFile(getName(), ".js-noopt");
+    BufferedWriter out = new BufferedWriter(new FileWriter(temp));
+    out.write(DEF_JS_CONTENT);
+    out.close();
+    String xml = "<feature>" +
+                 "  <name>" + FEATURE_NAME + "</name>" +
+                 "  <gadget>" +
+                 "    <script src=\"" + temp.getPath() + "\"/>" +
+                 "  </gadget>" +
+                 "</feature>";
+    GadgetFeatureRegistry.Entry entry = loader.loadFeature(registry, xml);
+    GadgetFeature feature = entry.getFeature().create();
+    List<JsLibrary> libs = feature.getJsLibraries(new GadgetContext());
+    assertEquals(1, libs.size());
     assertEquals(DEF_JS_CONTENT, libs.get(0).getContent());
-   libs = feature.getJsLibraries(RenderingContext.GADGET,
-                                 new SyndOptions(SYND_B));
+    assertEquals(FEATURE_NAME, libs.get(0).getFeature());
+  }
+
+  public void testUrlReferences() throws Exception {
+    String xml = "<feature>" +
+                 "  <name>" + FEATURE_NAME + "</name>" +
+                 "  <gadget>" +
+                 "    <script src=\"" + JS_URL + "\"/>" +
+                 "  </gadget>" +
+                 "</feature>";
+    RemoteContentRequest request = new RemoteContentRequest(JS_URL);
+    RemoteContent response
+        = new RemoteContent(200, ALT_JS_CONTENT.getBytes(), null);
+    expect(fetcher.fetch(eq(request))).andReturn(response);
+    replay();
+    GadgetFeatureRegistry.Entry entry = loader.loadFeature(registry, xml);
+    verify();
+    GadgetFeature feature = entry.getFeature().create();
+    List<JsLibrary> libs = feature.getJsLibraries(new GadgetContext());
+    assertEquals(1, libs.size());
     assertEquals(ALT_JS_CONTENT, libs.get(0).getContent());
+    assertEquals(FEATURE_NAME, libs.get(0).getFeature());
   }
 }
 
-class SyndOptions extends ProcessingOptions {
+class SyndContext extends GadgetContext {
   private final String syndicator;
   @Override
   public String getSyndicator() {
     return syndicator;
   }
-  public SyndOptions(String syndicator) {
+  public SyndContext(String syndicator) {
     this.syndicator = syndicator;
   }
 }

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/JsLibraryTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+package org.apache.shindig.gadgets;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.net.URI;
+
+public class JsLibraryTest extends EasyMockTestCase {
+  private final static String INLINE_JS = "var hello = 'world'; alert(hello);";
+  private final static String FILE_JS = "gadgets.test.pattern = function(){};";
+  private final static String UNCOMPRESSED_FILE_JS
+      = "/** Some comments*/\n" +
+        "gadgets.test.pattern = function() {" +
+        "};";
+  private final static String URL_JS = "while(true){alert('hello');}";
+
+  public void testInline() {
+    JsLibrary lib
+        = JsLibrary.create(JsLibrary.Type.INLINE, INLINE_JS, null, null);
+    assertEquals(JsLibrary.Type.INLINE, lib.getType());
+    assertEquals(INLINE_JS, lib.getContent());
+  }
+
+  public void testFile() throws Exception {
+    File temp = File.createTempFile(this.getName(), ".js-standalone");
+    temp.deleteOnExit();
+    BufferedWriter out = new BufferedWriter(new FileWriter(temp));
+    out.write(FILE_JS);
+    out.close();
+
+    JsLibrary lib
+        = JsLibrary.create(JsLibrary.Type.FILE, temp.getPath(), null, null);
+    assertEquals(JsLibrary.Type.FILE, lib.getType());
+    assertEquals(FILE_JS, lib.getContent());
+  }
+
+  public void testOptimized() throws Exception {
+    File uncompressed = File.createTempFile(this.getName(), ".js");
+    uncompressed.deleteOnExit();
+    BufferedWriter out = new BufferedWriter(new FileWriter(uncompressed));
+    out.write(UNCOMPRESSED_FILE_JS);
+    out.close();
+
+    File compressed
+        = new File(uncompressed.getPath().replace(".js", ".opt.js"));
+    // This might fail, but it shouldn't fail if the temp creation worked.
+    compressed.createNewFile();
+    compressed.deleteOnExit();
+    out = new BufferedWriter(new FileWriter(compressed));
+    out.write(FILE_JS);
+    out.close();
+
+    JsLibrary lib = JsLibrary.create(
+          JsLibrary.Type.FILE, uncompressed.getPath(), null, null);
+    assertEquals(JsLibrary.Type.FILE, lib.getType());
+    assertEquals(FILE_JS, lib.getContent());
+    assertEquals(UNCOMPRESSED_FILE_JS, lib.getDebugContent());
+  }
+
+  public void testUrl() throws Exception {
+    RemoteContentFetcher mockFetcher = mock(RemoteContentFetcher.class);
+    URI location = new URI("http://example.org/file.js");
+    RemoteContentRequest request = new RemoteContentRequest(location);
+    RemoteContent content
+        = new RemoteContent(RemoteContent.SC_OK, URL_JS.getBytes(), null);
+    expect(mockFetcher.fetch(eq(request))).andReturn(content);
+    replay();
+    JsLibrary lib = JsLibrary.create(
+        JsLibrary.Type.URL, location.toString(), null, mockFetcher);
+    verify();
+
+    // No type test here because it could potentially change.
+    assertEquals(URL_JS, lib.getContent());
+    assertEquals(URL_JS, lib.getDebugContent());
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentRequestTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentRequestTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentRequestTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/RemoteContentRequestTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets;
+
+import org.apache.shindig.util.InputStreamConsumer;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RemoteContentRequestTest extends TestCase {
+  private static final String POST_BODY = "Hello, world!";
+  private static final String CONTENT_TYPE = "text/plain";
+  private static final String TEST_HEADER_KEY = "X-Test-Header";
+  private static final String TEST_HEADER_VALUE = "Hello!";
+  private static final URI DEFAULT_URI = URI.create("http://example.org/");
+
+  public void testPostBodyCopied() throws Exception {
+    RemoteContentRequest request
+        = new RemoteContentRequest(DEFAULT_URI, POST_BODY.getBytes());
+    assertEquals(POST_BODY.length(), request.getPostBodyLength());
+    assertEquals(POST_BODY,
+        InputStreamConsumer.readToString(request.getPostBody()));
+  }
+
+  public void testContentTypeExtraction() throws Exception {
+    Map<String, List<String>> headers = new HashMap<String, List<String>>();
+    headers.put("Content-Type", Arrays.asList(CONTENT_TYPE));
+    RemoteContentRequest request
+        = new RemoteContentRequest(DEFAULT_URI, headers);
+    assertEquals(CONTENT_TYPE, request.getContentType());
+  }
+
+  public void testGetHeader() throws Exception {
+    Map<String, List<String>> headers = new HashMap<String, List<String>>();
+    headers.put(TEST_HEADER_KEY, Arrays.asList(TEST_HEADER_VALUE));
+    RemoteContentRequest request
+        = new RemoteContentRequest(DEFAULT_URI, headers);
+    assertEquals(TEST_HEADER_VALUE, request.getHeader(TEST_HEADER_KEY));
+  }
+}

Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SubstitutionsTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SubstitutionsTest.java?rev=635862&r1=635861&r2=635862&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SubstitutionsTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/SubstitutionsTest.java Tue Mar 11 02:52:52 2008
@@ -1,3 +1,21 @@
+/*
+ * 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.
+ */
 package org.apache.shindig.gadgets;
 
 import org.apache.shindig.gadgets.Substitutions.Type;
@@ -10,38 +28,43 @@
   public void testMessages() throws Exception {
     String msg = "Hello, __MSG_world__!";
     subst.addSubstitution(Type.MESSAGE, "world", "planet");
-    assertEquals("Hello, planet!", subst.substitute(msg));
+    assertEquals("Hello, planet!", subst.substituteString(null, msg));
   }
 
   public void testBidi() throws Exception {
     String msg = "Hello, __BIDI_DIR__-world!";
     subst.addSubstitution(Type.BIDI, "DIR", "rtl");
-    assertEquals("Hello, rtl-world!", subst.substitute(msg));
+    assertEquals("Hello, rtl-world!", subst.substituteString(null, msg));
   }
 
   public void testUserPref() throws Exception {
     String msg = "__UP_hello__, world!";
     subst.addSubstitution(Type.USER_PREF, "hello", "Greetings");
-    assertEquals("Greetings, world!", subst.substitute(msg));
+    assertEquals("Greetings, world!", subst.substituteString(null, msg));
   }
 
   public void testCorrectOrder() throws Exception {
     String msg = "__UP_hello__, __MSG_world__!";
-    subst.addSubstitution(Type.MESSAGE, "world", "planet __BIDI_DIR__-__UP_planet__");
+    subst.addSubstitution(Type.MESSAGE, "world",
+        "planet __BIDI_DIR__-__UP_planet__");
     subst.addSubstitution(Type.BIDI, "DIR", "rtl");
     subst.addSubstitution(Type.USER_PREF, "hello", "Greetings");
     subst.addSubstitution(Type.USER_PREF, "planet", "Earth");
-    assertEquals("Greetings, planet rtl-Earth!", subst.substitute(msg));
+    assertEquals("Greetings, planet rtl-Earth!",
+        subst.substituteString(null, msg));
   }
 
   public void testIncorrectOrder() throws Exception {
     String msg = "__UP_hello__, __MSG_world__";
-    subst.addSubstitution(Type.MESSAGE, "world", "planet __MSG_earth____UP_punc__");
+    subst.addSubstitution(Type.MESSAGE, "world",
+        "planet __MSG_earth____UP_punc__");
     subst.addSubstitution(Type.MESSAGE, "earth", "Earth");
     subst.addSubstitution(Type.USER_PREF, "punc", "???");
-    subst.addSubstitution(Type.USER_PREF, "hello", "Greetings __MSG_foo____UP_bar__");
+    subst.addSubstitution(Type.USER_PREF, "hello",
+        "Greetings __MSG_foo____UP_bar__");
     subst.addSubstitution(Type.MESSAGE, "foo", "FOO!!!");
     subst.addSubstitution(Type.USER_PREF, "bar", "BAR!!!");
-    assertEquals("Greetings __MSG_foo____UP_bar__, planet __MSG_earth__???", subst.substitute(msg));
+    assertEquals("Greetings __MSG_foo____UP_bar__, planet __MSG_earth__???",
+        subst.substituteString(null, msg));
   }
 }

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/UserPrefSubstituterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/UserPrefSubstituterTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/UserPrefSubstituterTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/UserPrefSubstituterTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets;
+
+import org.apache.shindig.gadgets.Substitutions.Type;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UserPrefSubstituterTest extends TestCase {
+  private final Substitutions substituter = new Substitutions();
+  private final static String DEFAULT_NAME = "default";
+  private final static String DEFAULT_VALUE = "default value";
+  private final static String USER_NAME = "user";
+  private final static String USER_VALUE = "user value";
+  private final static String OVERRIDE_NAME = "override";
+  private final static String OVERRIDE_VALUE = "override value";
+  private final static String UNESCAPED_USER_VALUE = "<hello, & world > \"";
+  private final static String ESCAPED_USER_VALUE
+      = "&lt;hello, &amp; world &gt; &quot;";
+  private static final String DEFAULT_XML
+      = "<Module>" +
+        "<ModulePrefs title=\"Hello, __UP_world__\"/>" +
+        "<UserPref name=\"" + DEFAULT_NAME + "\" datatype=\"string\"" +
+        " default_value=\"" + DEFAULT_VALUE + "\"/>" +
+        "<UserPref name=\"" + USER_NAME + "\" datatype=\"string\"/>" +
+        "<UserPref name=\"" + OVERRIDE_NAME + "\" datatype=\"string\"" +
+        "  default_value=\"FOOOOOOOOOOBAR!\"/>" +
+        "<Content type=\"html\"/>" +
+        "</Module>";
+  private GadgetSpec spec;
+
+  @Override
+  public void setUp() throws Exception {
+    spec = new GadgetSpec(URI.create(""), DEFAULT_XML);
+  }
+
+  public void testSubstitutions() throws Exception {
+    Map<String, String> map = new HashMap<String, String>();
+    map.put(USER_NAME, USER_VALUE);
+    map.put(OVERRIDE_NAME, OVERRIDE_VALUE);
+    UserPrefs prefs = new UserPrefs(map);
+    UserPrefSubstituter.addSubstitutions(substituter, spec, prefs);
+
+    assertEquals(DEFAULT_VALUE,
+        substituter.getSubstitution(Type.USER_PREF, DEFAULT_NAME));
+    assertEquals(USER_VALUE,
+        substituter.getSubstitution(Type.USER_PREF, USER_NAME));
+    assertEquals(OVERRIDE_VALUE,
+        substituter.getSubstitution(Type.USER_PREF, OVERRIDE_NAME));
+  }
+
+  public void testEscaping() throws Exception {
+    Map<String, String> map = new HashMap<String, String>();
+    map.put(USER_NAME, UNESCAPED_USER_VALUE);
+    UserPrefs prefs = new UserPrefs(map);
+    UserPrefSubstituter.addSubstitutions(substituter, spec, prefs);
+    assertEquals(ESCAPED_USER_VALUE,
+        substituter.getSubstitution(Type.USER_PREF, USER_NAME));
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/GadgetRendererTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.http;
+
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+
+import org.apache.shindig.gadgets.GadgetTestFixture;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+public class GadgetRendererTest extends GadgetTestFixture {
+
+  final static Enumeration<String> EMPTY_PARAMS = new Enumeration<String>() {
+    public boolean hasMoreElements() {
+      return false;
+    }
+    public String nextElement() {
+      return null;
+    }
+  };
+
+  final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+  final PrintWriter writer = new PrintWriter(baos);
+
+  final static URI SPEC_URL = URI.create("http://example.org/gadget.xml");
+  final static String CONTENT = "Hello, world!";
+  final static String SPEC_XML
+      = "<Module>" +
+        "<ModulePrefs title=\"hello\"/>" +
+        "<Content type=\"html\" quirks=\"false\">" + CONTENT + "</Content>" +
+        "<Content type=\"html\" view=\"quirks\" quirks=\"true\"/>" +
+        "</Module>";
+  final static String LIBS = "dummy:blah";
+
+  /**
+   * Performs boilerplate operations to get basic gadgets rendered
+   * @return Output of the rendering request
+   * @throws Exception
+   */
+  private String parseBasicGadget() throws Exception {
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, SPEC_XML);
+    expect(request.getParameter("url")).andReturn(SPEC_URL.toString());
+    expect(request.getParameter("libs")).andReturn(LIBS);
+    expect(request.getParameterNames()).andReturn(EMPTY_PARAMS);
+    expect(specFetcher.fetch(eq(SPEC_URL), eq(false))).andReturn(spec);
+    expect(response.getWriter()).andReturn(writer);
+    replay();
+    GadgetRenderer renderer = new GadgetRenderer(request, response, state);
+    renderer.process();
+    verify();
+    writer.close();
+    return new String(baos.toByteArray(), "UTF-8");
+  }
+
+  public void testHasCorrectDocType() throws Exception {
+    String content = parseBasicGadget();
+    assertTrue(-1 != content.indexOf(GadgetRenderer.STRICT_MODE_DOCTYPE));
+  }
+
+  public void testContentRendered() throws Exception {
+    String content = parseBasicGadget();
+    assertTrue(-1 != content.indexOf(CONTENT));
+  }
+
+  public void testForcedLibsIncluded() throws Exception {
+    String content = parseBasicGadget();
+    Set<String> libs = new HashSet<String>();
+    for (String lib : LIBS.split(":")) {
+      libs.add(lib);
+    }
+    String libStr = state.getJsUrl(libs, null);
+    assertTrue(-1 != content.indexOf("<script src=\"" + libStr + "\">"));
+  }
+
+  // TODO: Lots of ugly tests on html content.
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpGadgetContextTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpGadgetContextTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpGadgetContextTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/HttpGadgetContextTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.http;
+
+import static org.easymock.EasyMock.expect;
+
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.GadgetTestFixture;
+
+import java.util.Locale;
+
+public class HttpGadgetContextTest extends GadgetTestFixture {
+  public void testIgnoreCacheParam() {
+    expect(request.getParameter("nocache")).andReturn(
+        Integer.toString(Integer.MAX_VALUE));
+    replay();
+    GadgetContext context = new HttpGadgetContext(request);
+    verify();
+    assertEquals(true, context.getIgnoreCache());
+  }
+
+  public void testLocale() {
+    expect(request.getParameter("lang")).andReturn(Locale.CHINA.getLanguage());
+    expect(request.getParameter("country")).andReturn(
+        Locale.CHINA.getCountry());
+    replay();
+    GadgetContext context = new HttpGadgetContext(request);
+    verify();
+    assertEquals(Locale.CHINA, context.getLocale());
+  }
+
+  public void testDebug() {
+    expect(request.getParameter("debug")).andReturn("1");
+    replay();
+    GadgetContext context = new HttpGadgetContext(request);
+    verify();
+    assertEquals(true, context.getDebug());
+  }
+}
\ No newline at end of file

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcGadgetContextTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcGadgetContextTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcGadgetContextTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcGadgetContextTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.http;
+
+import org.json.JSONObject;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class JsonRpcGadgetContextTest extends TestCase {
+  final static String SPEC_URL = "http://example.org/gadget.xml";
+  final static int SPEC_ID = 1234;
+  final static String[] PREF_KEYS = new String[] {"hello", "foo"};
+  final static String[] PREF_VALUES = new String[] {"world", "bar"};
+  final static Map<String, String> prefs = new HashMap<String, String>();
+  static {
+    for (int i = 0, j = PREF_KEYS.length; i < j; ++i) {
+      prefs.put(PREF_KEYS[i], PREF_VALUES[i]);
+    }
+  }
+
+  public void testCorrectExtraction() throws Exception {
+    JSONObject gadget = new JSONObject()
+        .put("url", SPEC_URL)
+        .put("moduleId", SPEC_ID)
+        .put("prefs", prefs);
+
+    JSONObject context = new JSONObject()
+        .put("language", Locale.US.getLanguage())
+        .put("country", Locale.US.getCountry().toUpperCase());
+
+    JsonRpcGadgetContext jsonContext
+        = new JsonRpcGadgetContext(context, gadget);
+    assertEquals(SPEC_URL, jsonContext.getUrl().toString());
+    assertEquals(SPEC_ID, jsonContext.getModuleId());
+    assertEquals(Locale.US.getLanguage(),
+                 jsonContext.getLocale().getLanguage());
+    assertEquals(Locale.US.getCountry(), jsonContext.getLocale().getCountry());
+
+    for (String key : PREF_KEYS) {
+      String value = jsonContext.getUserPrefs().getPref(key);
+      assertEquals(prefs.get(key), value);
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/http/JsonRpcRequestTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+package org.apache.shindig.gadgets.http;
+
+import static org.easymock.EasyMock.expect;
+
+import org.apache.shindig.gadgets.GadgetTestFixture;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Map;
+
+public class JsonRpcRequestTest extends GadgetTestFixture {
+  private static final URI SPEC_URL = URI.create("http://example.org/g.xml");
+  private static final URI SPEC_URL2 = URI.create("http://example.org/g2.xml");
+  private static final String SPEC_TITLE = "JSON-TEST";
+  private static final String SPEC_TITLE2 = "JSON-TEST2";
+  private static final String SPEC_XML
+      = "<Module>" +
+        "<ModulePrefs title=\"" + SPEC_TITLE + "\"/>" +
+        "<Content type=\"html\">Hello, world</Content>" +
+        "</Module>";
+  private static final String SPEC_XML2
+      = "<Module>" +
+        "<ModulePrefs title=\"" + SPEC_TITLE2 + "\"/>" +
+        "<Content type=\"html\">Hello, world</Content>" +
+        "</Module>";
+
+  private JSONObject createContext(String lang, String country)
+      throws JSONException {
+    return new JSONObject().put("language", lang).put("country", country);
+  }
+
+  private JSONObject createGadget(String url, int moduleId,
+      Map<String, String> prefs) throws JSONException {
+    return new JSONObject()
+        .put("url", url)
+        .put("moduleId", moduleId)
+        .put("prefs", prefs == null ? Collections.emptySet() : prefs);
+  }
+
+  public void testSimpleRequest() throws Exception {
+    JSONArray gadgets = new JSONArray()
+      .put(createGadget(SPEC_URL.toString(), 0, null));
+    JSONObject input = new JSONObject()
+        .put("context", createContext("en", "US"))
+        .put("gadgets", gadgets);
+
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, SPEC_XML);
+
+    expect(specFetcher.fetch(SPEC_URL, false)).andReturn(spec);
+
+    replay();
+    JsonRpcRequest request = new JsonRpcRequest(input.toString());
+    JSONObject response = request.process(state);
+    verify();
+
+    JSONArray outGadgets = response.getJSONArray("gadgets");
+    JSONObject gadget = outGadgets.getJSONObject(0);
+    assertEquals(SPEC_TITLE, gadget.getString("title"));
+    assertEquals(0, gadget.getInt("moduleId"));
+  }
+
+  public void testMultipleGadgets() throws Exception {
+    JSONArray gadgets = new JSONArray()
+     .put(createGadget(SPEC_URL.toString(), 0, null))
+     .put(createGadget(SPEC_URL2.toString(), 1, null));
+    JSONObject input = new JSONObject()
+        .put("context", createContext("en", "US"))
+        .put("gadgets", gadgets);
+
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, SPEC_XML);
+    GadgetSpec spec2 = new GadgetSpec(SPEC_URL2, SPEC_XML2);
+
+    expect(specFetcher.fetch(SPEC_URL, false)).andReturn(spec);
+    expect(specFetcher.fetch(SPEC_URL2, false)).andReturn(spec2);
+
+    replay();
+    JsonRpcRequest request = new JsonRpcRequest(input.toString());
+    JSONObject response = request.process(state);
+    verify();
+
+    JSONArray outGadgets = response.getJSONArray("gadgets");
+    JSONObject gadget = outGadgets.getJSONObject(0);
+    if (gadget.getString("url").equals(SPEC_URL.toString())) {
+      assertEquals(SPEC_TITLE, gadget.getString("title"));
+      assertEquals(0, gadget.getInt("moduleId"));
+    } else {
+      assertEquals(SPEC_TITLE2, gadget.getString("title"));
+      assertEquals(1, gadget.getInt("moduleId"));
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/FeatureTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/FeatureTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/FeatureTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/FeatureTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.spec;
+
+import org.apache.shindig.util.XmlUtil;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+public class FeatureTest extends TestCase {
+  public void testRequire() throws Exception {
+    String xml = "<Require feature=\"foo\"/>";
+    Feature feature = new Feature(XmlUtil.parse(xml));
+    assertEquals("foo", feature.getName());
+    assertEquals(true, feature.getRequired());
+  }
+
+  public void testOptional() throws Exception {
+    String xml = "<Optional feature=\"foo\"/>";
+    Feature feature = new Feature(XmlUtil.parse(xml));
+    assertEquals("foo", feature.getName());
+    assertEquals(false, feature.getRequired());
+  }
+
+  public void testParams() throws Exception {
+    String key = "bar";
+    String value = "Hello, World!";
+    String xml = "<Require feature=\"foo\">" +
+                 "  <Param name=\"" + key + "\">" + value + "</Param>" +
+                 "</Require>";
+    Feature feature = new Feature(XmlUtil.parse(xml));
+    Map<String, String> params = feature.getParams();
+    assertEquals(1, params.size());
+    assertEquals(value, params.get(key));
+  }
+
+  public void testDoesNotLikeUnnamedFeatures() throws Exception {
+    String xml = "<Require/>";
+    try {
+      Feature feature = new Feature(XmlUtil.parse(xml));
+      fail("No exception thrown when an unnamed feature is passed.");
+    } catch (SpecParserException e) {
+      // Ok
+    }
+  }
+
+  public void testEnforceParamNames() throws Exception {
+    String xml = "<Require feature=\"foo\"><Param>Test</Param></Require>";
+    try {
+      Feature feature = new Feature(XmlUtil.parse(xml));
+      fail("No exception thrown when an unnamed parameter is passed.");
+    } catch (SpecParserException e) {
+      // OK.
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/GadgetSpecTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/GadgetSpecTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/GadgetSpecTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/GadgetSpecTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.spec;
+
+import org.apache.shindig.gadgets.Substitutions;
+import org.apache.shindig.gadgets.Substitutions.Type;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+
+public class GadgetSpecTest extends TestCase {
+  private static final URI SPEC_URL = URI.create("http://example.org/g.xml");
+  public void testBasic() throws Exception {
+    String xml = "<Module>" +
+                 "<ModulePrefs title=\"title\"/>" +
+                 "<UserPref name=\"foo\" datatype=\"string\"/>" +
+                 "<Content type=\"html\">Hello!</Content>" +
+                 "</Module>";
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
+    assertEquals("title", spec.getModulePrefs().getTitle());
+    assertEquals(UserPref.DataType.STRING,
+        spec.getUserPrefs().get(0).getDataType());
+    assertEquals("Hello!", spec.getView(GadgetSpec.DEFAULT_VIEW).getContent());
+  }
+
+  public void testMultipleContentSections() throws Exception {
+    String xml = "<Module>" +
+                 "<ModulePrefs title=\"title\"/>" +
+                 "<Content type=\"html\" view=\"hello\">hello </Content>" +
+                 "<Content type=\"html\" view=\"world\">world</Content>" +
+                 "<Content type=\"html\" view=\"hello, test\">test</Content>" +
+                 "</Module>";
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
+    assertEquals("hello test", spec.getView("hello").getContent());
+    assertEquals("world", spec.getView("world").getContent());
+    assertEquals("test", spec.getView("test").getContent());
+  }
+
+  public void testMissingModulePrefs() throws Exception {
+    String xml = "<Module>" +
+                 "<Content type=\"html\"/>" +
+                 "</Module>";
+    try {
+      GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
+      fail("No exception thrown when ModulePrefs is missing.");
+    } catch (SpecParserException e) {
+      // OK
+    }
+  }
+
+  public void testEnforceOneModulePrefs() throws Exception {
+    String xml = "<Module>" +
+                 "<ModulePrefs title=\"hello\"/>" +
+                 "<ModulePrefs title=\"world\"/>" +
+                 "<Content type=\"html\"/>" +
+                 "</Module>";
+    try {
+      GadgetSpec spec = new GadgetSpec(SPEC_URL, xml);
+      fail("No exception thrown when more than 1 ModulePrefs is specified.");
+    } catch (SpecParserException e) {
+      // OK
+    }
+  }
+
+  public void testSubstitutions() throws Exception {
+    Substitutions substituter = new Substitutions();
+    String title = "Hello, World!";
+    String content = "Goodbye, world :(";
+    String xml = "<Module>" +
+                 "<ModulePrefs title=\"__UP_title__\"/>" +
+                 "<Content type=\"html\">__MSG_content__</Content>" +
+                 "</Module>";
+    substituter.addSubstitution(Type.USER_PREF, "title", title);
+    substituter.addSubstitution(Type.MESSAGE, "content", content);
+
+    GadgetSpec spec = new GadgetSpec(SPEC_URL, xml).substitute(substituter);
+    assertEquals(title, spec.getModulePrefs().getTitle());
+    assertEquals(content, spec.getView(GadgetSpec.DEFAULT_VIEW).getContent());
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/IconTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/IconTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/IconTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/IconTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.spec;
+
+import org.apache.shindig.gadgets.Substitutions;
+import org.apache.shindig.util.XmlUtil;
+
+import junit.framework.TestCase;
+
+public class IconTest extends TestCase {
+  public void testBasicIcon() throws Exception {
+    String xml = "<Icon type=\"foo\" mode=\"base64\">helloWorld</Icon>";
+    Icon icon = new Icon(XmlUtil.parse(xml));
+    assertEquals("foo", icon.getType());
+    assertEquals("base64", icon.getMode());
+    assertEquals("helloWorld", icon.getContent());
+  }
+
+  public void testInvalidMode() throws Exception {
+    String xml = "<Icon type=\"foo\" mode=\"broken\"/>";
+    try {
+      Icon icon = new Icon(XmlUtil.parse(xml));
+      fail("No exception thrown when an invalid mode attribute is passed.");
+    } catch (SpecParserException e) {
+      // OK
+    }
+  }
+
+  public void testSubstitutions() throws Exception {
+    String xml = "<Icon>http://__MSG_domain__/icon.png</Icon>";
+    Substitutions substituter = new Substitutions();
+    substituter.addSubstitution(Substitutions.Type.MESSAGE, "domain",
+        "example.org");
+    Icon icon = new Icon(XmlUtil.parse(xml)).substitute(substituter);
+    assertEquals("http://example.org/icon.png", icon.getContent());
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LocaleSpecTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LocaleSpecTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LocaleSpecTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/LocaleSpecTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.spec;
+
+import org.apache.shindig.util.XmlUtil;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+
+public class LocaleSpecTest extends TestCase {
+  private static final URI SPEC_URL = URI.create("http://example.org/foo.xml");
+
+  public void testNormalLocale() throws Exception {
+    String xml = "<Locale" +
+                 " lang=\"en\"" +
+                 " country=\"US\"" +
+                 " language_direction=\"rtl\"" +
+                 " messages=\"http://example.org/msgs.xml\"/>";
+
+    LocaleSpec locale = new LocaleSpec(XmlUtil.parse(xml), SPEC_URL);
+    assertEquals("en", locale.getLanguage());
+    assertEquals("US", locale.getCountry());
+    assertEquals("rtl", locale.getLanguageDirection());
+    assertEquals("http://example.org/msgs.xml",
+        locale.getMessages().toString());
+  }
+
+  public void testRelativeLocale() throws Exception {
+    String xml = "<Locale messages=\"/test/msgs.xml\"/>";
+    LocaleSpec locale = new LocaleSpec(XmlUtil.parse(xml), SPEC_URL);
+    assertEquals("http://example.org/test/msgs.xml",
+        locale.getMessages().toString());
+  }
+
+  public void testDefaultLanguageAndCountry() throws Exception {
+    String xml = "<Locale/>";
+    LocaleSpec locale = new LocaleSpec(XmlUtil.parse(xml), SPEC_URL);
+    assertEquals("all", locale.getLanguage());
+    assertEquals("ALL", locale.getCountry());
+  }
+
+  public void testInvalidLanguageDirection() throws Exception {
+    String xml = "<Locale language_direction=\"invalid\"/>";
+    try {
+      LocaleSpec locale = new LocaleSpec(XmlUtil.parse(xml), SPEC_URL);
+      fail("No exception thrown when invalid language_direction is specified.");
+    } catch (SpecParserException e) {
+      // OK.
+    }
+  }
+
+  public void testInvalidMessagesUrl() throws Exception {
+    String xml = "<Locale messages=\"fobad@$%!fdf\"/>";
+    try {
+      LocaleSpec locale = new LocaleSpec(XmlUtil.parse(xml), SPEC_URL);
+      fail("No exception thrown when invalid messages url is specified.");
+    } catch (SpecParserException e) {
+      // OK.
+    }
+  }
+}

Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/MessageBundleTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/MessageBundleTest.java?rev=635862&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/MessageBundleTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/spec/MessageBundleTest.java Tue Mar 11 02:52:52 2008
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package org.apache.shindig.gadgets.spec;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MessageBundleTest extends TestCase {
+  public void testNormalMessageBundle() throws Exception {
+    Map<String, String> messages = new HashMap<String, String>();
+    messages.put("hello", "world");
+    messages.put("foo", "bar");
+
+    String xml = "<messagebundle>";
+    for (Map.Entry<String, String> entry : messages.entrySet()) {
+      xml += "<msg name=\"" + entry.getKey() + "\">" + entry.getValue() +
+          "</msg>";
+    }
+    xml += "</messagebundle>";
+    MessageBundle bundle = new MessageBundle(xml);
+    assertEquals(messages, bundle.getMessages());
+  }
+
+  public void testMissingNames() {
+    String xml = "<messagebundle><msg>foo</msg></messagebundle>";
+    try {
+      MessageBundle bundle = new MessageBundle(xml);
+      fail("No exception thrown when a msg has no name.");
+    } catch (SpecParserException e) {
+      // OK.
+    }
+  }
+}