Revision: 3856
Author: [email protected]
Date: Thu Nov 19 15:57:15 2009
Log: Error message and test cleanup
http://codereview.appspot.com/157079
Changes error messages so they make sense both from linter and from
cajoler..
And make some test code available to the ancillary tools.
Fix a semicolon warning issue after labeled blocks as in
foo: {}
Add class=nocode to HTML error snippets so the filename is not prettified.
[email protected]
http://code.google.com/p/google-caja/source/detail?r=3856
Modified:
/trunk/build.xml
/trunk/src/com/google/caja/cajita-module.js
/trunk/src/com/google/caja/parser/html/HtmlQuasiBuilder.java
/trunk/src/com/google/caja/parser/js/LabeledStmtWrapper.java
/trunk/src/com/google/caja/parser/js/Operation.java
/trunk/src/com/google/caja/parser/js/Parser.java
/trunk/src/com/google/caja/plugin/PluginMessageType.java
/trunk/src/com/google/caja/render/JsMinimalPrinter.java
/trunk/src/com/google/caja/reporting/HtmlSnippetProducer.java
/trunk/src/com/google/caja/util/Maps.java
/trunk/tests/com/google/caja/opensocial/DefaultGadgetRewriterTest.java
/trunk/tests/com/google/caja/parser/js/ExpressionTest.java
/trunk/tests/com/google/caja/plugin/CssValidatorTest.java
/trunk/tests/com/google/caja/reporting/HtmlSnippetProducerTest.java
/trunk/tests/com/google/caja/service/FetchedDataTest.java
/trunk/tests/com/google/caja/service/TestHttpServletRequest.java
/trunk/tests/com/google/caja/service/TestHttpServletResponse.java
=======================================
--- /trunk/build.xml Wed Nov 18 16:37:58 2009
+++ /trunk/build.xml Thu Nov 19 15:57:15 2009
@@ -26,7 +26,7 @@
- benchmarks : runs the benchmarks
- clean : wipes generated files
- demos : demo files
- - docs : javadoc, jsdocs, and rule docs
+ - docs : javadocs, jsdocs, and rule docs
- jars : build the binary distribution
- jars : build the binary distribution
- pluginc : the plugin compiler
@@ -112,7 +112,7 @@
</path>
<path id="classpath.javadocs">
<path refid="classpath.compile"/>
- <path refid="classpath.ant"/>
+ <path refid="classpath.tools"/>
</path>
<!--== Tasks Used Below ==-->
=======================================
--- /trunk/src/com/google/caja/cajita-module.js Fri Nov 13 13:37:15 2009
+++ /trunk/src/com/google/caja/cajita-module.js Thu Nov 19 15:57:15 2009
@@ -157,6 +157,7 @@
var xhr = bridal.makeXhr();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
+ xhr.onreadystatechange = noop; // avoid memory leak
if (xhr.status === 200) {
var savedModuleHandler = ___.getNewModuleHandler();
___.setNewModuleHandler(___.primFreeze({
@@ -183,7 +184,6 @@
//TODO: validate the response before eval it
eval(xhr.responseText);
___.setNewModuleHandler(savedModuleHandler);
- xhr.onreadystatechange = noop; // avoid memory leak
} else {
r.resolve(Q.reject(
"Retrieving the module " + mid + " failed, "
=======================================
--- /trunk/src/com/google/caja/parser/html/HtmlQuasiBuilder.java Fri Nov 13
11:43:08 2009
+++ /trunk/src/com/google/caja/parser/html/HtmlQuasiBuilder.java Thu Nov 19
15:57:15 2009
@@ -360,6 +360,9 @@
String quasiIdentifier = m.group(1);
Object binding = bindings.get(quasiIdentifier);
+ if (!(binding instanceof String)) {
+ throw new ClassCastException("@" + quasiIdentifier);
+ }
Escaping.escapeXml((String) binding, false, sb);
} while (m.find());
sb.append(unescaped, pos, unescaped.length());
=======================================
--- /trunk/src/com/google/caja/parser/js/LabeledStmtWrapper.java Thu Nov 12
13:05:03 2009
+++ /trunk/src/com/google/caja/parser/js/LabeledStmtWrapper.java Thu Nov 19
15:57:15 2009
@@ -68,6 +68,11 @@
}
body.render(rc);
}
+
+ @Override
+ public boolean isTerminal() {
+ return body.isTerminal();
+ }
public boolean hasHangingConditional() {
return body.hasHangingConditional();
=======================================
--- /trunk/src/com/google/caja/parser/js/Operation.java Wed Nov 18 16:37:58
2009
+++ /trunk/src/com/google/caja/parser/js/Operation.java Thu Nov 19 15:57:15
2009
@@ -533,6 +533,15 @@
} else {
return left;
}
+ } else {
+ bv = right.conditionResult();
+ // foo != bar && true -> foo != bar
+ if (bv != null && bv.booleanValue() == (op == Operator.LOGICAL_AND)
+ && "boolean".equals(left.typeOf())
+ && "boolean".equals(right.typeOf())
+ && right.simplifyForSideEffect() == null) {
+ return left;
+ }
}
} else if (op == Operator.MEMBER_ACCESS) {
if (left instanceof StringLiteral) {
@@ -578,6 +587,19 @@
if (lhs instanceof Number && rhs instanceof Number) {
double a = ((Number) lhs).doubleValue();
double b = ((Number) rhs).doubleValue();
+ if (isIntOp(op) && !Double.isNaN(a) && !Double.isNaN(b)) {
+ long result;
+ switch (op) {
+ case BITWISE_AND: result = toInt32(a) & toInt32(b); break;
+ case BITWISE_OR: result = toInt32(a) | toInt32(b); break;
+ case BITWISE_XOR: result = toInt32(a) ^ toInt32(b); break;
+ case LSHIFT: result = toInt32(a) << toUint32(b); break;
+ case RSHIFT: result = toInt32(a) >> toUint32(b); break;
+ case RUSHIFT: result = toUint32(a) >>> toUint32(b); break;
+ default: return this;
+ }
+ return new IntegerLiteral(pos, result);
+ }
double result;
switch (op) {
case ADDITION: result = a + b; break;
@@ -640,4 +662,26 @@
}
return null;
}
-}
+
+ private static boolean isIntOp(Operator op) {
+ switch (op) {
+ case BITWISE_AND:
+ case BITWISE_OR:
+ case BITWISE_XOR:
+ case LSHIFT:
+ case RSHIFT:
+ case RUSHIFT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static long toInt32(double n) {
+ return (int) n;
+ }
+
+ private static long toUint32(double n) {
+ return ((long) n) & 0xffffffffL;
+ }
+}
=======================================
--- /trunk/src/com/google/caja/parser/js/Parser.java Mon Nov 16 17:29:55
2009
+++ /trunk/src/com/google/caja/parser/js/Parser.java Thu Nov 19 15:57:15
2009
@@ -1256,6 +1256,9 @@
}
private static boolean isTerminal(Statement s) {
+ if (s instanceof LabeledStmtWrapper) {
+ return isTerminal(((LabeledStmtWrapper) s).getBody());
+ }
return ((s instanceof Loop && !(s instanceof DoWhileLoop))
|| s instanceof Conditional || s instanceof FunctionDeclaration
|| s instanceof Block || s instanceof TryStmt
@@ -1265,9 +1268,7 @@
private Statement parseTerminatedStatement() throws ParseException {
Statement s = parseStatement();
- if (!isTerminal(s)) {
- checkSemicolon();
- }
+ if (!isTerminal(s)) { checkSemicolon(); }
return s;
}
=======================================
--- /trunk/src/com/google/caja/plugin/PluginMessageType.java Wed Sep 9
11:41:56 2009
+++ /trunk/src/com/google/caja/plugin/PluginMessageType.java Thu Nov 19
15:57:15 2009
@@ -32,7 +32,7 @@
"%s: access not allowed to global %s", MessageLevel.FATAL_ERROR),
UNSAFE_ACCESS(
"%s: unsafe access to protected namespace: %s",
MessageLevel.FATAL_ERROR),
- UNKNOWN_TAG("%s: removing unknown tag %s", MessageLevel.WARNING),
+ UNKNOWN_TAG("%s: unknown tag %s", MessageLevel.WARNING),
UNSAFE_TAG("%s: removing disallowed tag %s", MessageLevel.WARNING),
MISSING_ATTRIBUTE("%s: expected param %s on %s", MessageLevel.ERROR),
UNKNOWN_ATTRIBUTE("%s: removing unknown attribute %s on %s",
@@ -50,7 +50,7 @@
DISALLOWED_URI("%s: url %s cannot be linked to",
MessageLevel.FATAL_ERROR),
MALFORMED_URL("%s: malformed url %s", MessageLevel.FATAL_ERROR),
MALFORMED_CSS_PROPERTY_VALUE(
- "%s: removing css property %s with bad value: %s",
MessageLevel.WARNING),
+ "%s: css property %s has bad value: %s", MessageLevel.WARNING),
DISALLOWED_CSS_PROPERTY_IN_SELECTOR(
"%s: css property %s not allowed in :visited selector at %s",
MessageLevel.ERROR),
=======================================
--- /trunk/src/com/google/caja/render/JsMinimalPrinter.java Mon Nov 2
13:56:19 2009
+++ /trunk/src/com/google/caja/render/JsMinimalPrinter.java Thu Nov 19
15:57:15 2009
@@ -44,7 +44,7 @@
}
/** Visible for testing. Should not be used by clients. */
- void setLineLengthLimit(int lineLengthLimit) {
+ public void setLineLengthLimit(int lineLengthLimit) {
this.lineLengthLimit = lineLengthLimit;
}
=======================================
--- /trunk/src/com/google/caja/reporting/HtmlSnippetProducer.java Wed Aug
6 20:25:46 2008
+++ /trunk/src/com/google/caja/reporting/HtmlSnippetProducer.java Thu Nov
19 15:57:15 2009
@@ -58,7 +58,7 @@
StringBuilder filename = new StringBuilder();
pos.source().format(mc, filename);
- out.append("<a href=\"#\" class=\"filepos\" onclick=\"selectLine(")
+ out.append("<a href=\"#\" class=\"filepos nocode\"
onclick=\"selectLine(")
.append(html(js(pos.source().getUri().toString())))
.append(",")
.append(String.valueOf(pos.startLineNo()))
=======================================
--- /trunk/src/com/google/caja/util/Maps.java Wed Nov 18 16:37:58 2009
+++ /trunk/src/com/google/caja/util/Maps.java Thu Nov 19 15:57:15 2009
@@ -16,6 +16,7 @@
import java.util.Collections;
import java.util.Comparator;
+import java.util.EnumMap;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
@@ -94,25 +95,59 @@
public static final class ImmutableMapBuilder<K, V> {
private Map<K, V> map;
+ private boolean canUseEnumMap = true;
+ @SuppressWarnings("unchecked")
+ private Class<? extends Enum> enumKeyType;
ImmutableMapBuilder(Map<K, V> emptyMap) { this.map = emptyMap; }
public ImmutableMapBuilder<K, V> put(K key, V value) {
+ if (canUseEnumMap) {
+ if (enumKeyType != null) {
+ if (!enumKeyType.isInstance(key)) { // Values from different
enums
+ canUseEnumMap = false;
+ enumKeyType = null;
+ }
+ } else if (key instanceof Enum) {
+ enumKeyType = Enum.class.cast(key).getClass();
+ } else {
+ canUseEnumMap = false;
+ }
+ }
map.put(key, value);
return this;
}
public ImmutableMapBuilder<K, V> putAll(Map<K, V> map) {
- map.putAll(map);
+ if (canUseEnumMap) {
+ for (Map.Entry<K, V> e : map.entrySet()) {
+ put(e.getKey(), e.getValue());
+ }
+ } else {
+ map.putAll(map);
+ }
return this;
}
public Map<K, V> create() {
- Map<K, V> map = this.map;
+ if (this.map.isEmpty()) { return Collections.<K, V>emptyMap(); }
+ Map<K, V> map;
+ if (canUseEnumMap) {
+ map = Maps.<K, V>makeEnumMap(enumKeyType);
+ map.putAll(this.map);
+ } else {
+ map = this.map;
+ }
if (map == null) { throw new IllegalStateException(); }
this.map = null;
return Collections.unmodifiableMap(map);
}
}
+
+ // This is legit because enumKeyType above is both an enum type (checked
at
+ // runtime in the EnumMap ctor) and is the type of a subclass of K.
+ @SuppressWarnings("unchecked")
+ private static <K, V>
+ Map<K, V> makeEnumMap(Class<? extends Enum> t) { return new EnumMap(t); }
private Maps() {}
}
=======================================
--- /trunk/tests/com/google/caja/opensocial/DefaultGadgetRewriterTest.java
Fri Nov 13 13:37:15 2009
+++ /trunk/tests/com/google/caja/opensocial/DefaultGadgetRewriterTest.java
Thu Nov 19 15:57:15 2009
@@ -1,4 +1,5 @@
// Copyright (C) 2007 Google Inc.
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -130,7 +131,7 @@
public final void testStylesSanitized() throws Exception {
assertRewritesWithMessage(
"<p style=\"color: expression(foo)\">Bar</p>",
- "removing css property color with bad value:
==>expression(foo)<==",
+ "css property color has bad value: ==>expression(foo)<==",
MessageLevel.WARNING, false /* should not fail */);
}
=======================================
--- /trunk/tests/com/google/caja/parser/js/ExpressionTest.java Wed Nov 18
16:37:58 2009
+++ /trunk/tests/com/google/caja/parser/js/ExpressionTest.java Thu Nov 19
15:57:15 2009
@@ -166,6 +166,15 @@
assertFolded("!void foo()", "!(void foo())");
assertFolded("false", "!(4,true)");
assertFolded("! (foo() || true)", "!(foo()||true)");
+ assertFolded("false", "false && foo()");
+ assertFolded("true", "true || foo()");
+ assertFolded("foo()", "false || foo()");
+ assertFolded("foo()", "true && foo()");
+ assertFolded("foo != bar", "foo != bar && true");
+ assertFolded("foo != bar", "foo != bar || false");
+ // Can't fold. foo() might return non-boolean
+ assertFolded("foo() && true", "foo() && true");
+ assertFolded("foo() || false", "foo() || false");
assertFolded("true", "'foo' == 'foo'");
assertFolded("true", "'foo' === 'foo'");
assertFolded("false", "'foo' == 'bar'");
@@ -187,6 +196,24 @@
assertFolded("1.0", "1 % -3");
assertFolded("-1.0", "-1 % 3");
assertFolded("-1.0", "-1 % -3");
+ assertFolded("1024", "1 << 10");
+ assertFolded("" + (1 << 20), "1 << 20");
+ assertFolded("2", "4 >> 1");
+ assertFolded("1", "4 >> 2");
+ assertFolded("0", "4 >> 3");
+ assertFolded("-1", "-1 >> 1");
+ assertFolded("" + (-1 >>> 1), "-1 >>> 1");
+ assertFolded("1", "4 >>> 2");
+ assertFolded("0", "1 & 2");
+ assertFolded("2", "2 & 3");
+ assertFolded("2", "3 & 2");
+ assertFolded("3", "1 | 2");
+ assertFolded("7", "6 | 5");
+ assertFolded("11", "3 | 9");
+ assertFolded("0", "0 ^ 0");
+ assertFolded("0", "1 ^ 1");
+ assertFolded("3", "1 ^ 2");
+ assertFolded("-2", "-1 ^ 1");
assertFolded("4.0", "4.0");
assertFolded("4.0", "+4.0");
assertFolded("-1", "~0");
=======================================
--- /trunk/tests/com/google/caja/plugin/CssValidatorTest.java Wed Sep 9
11:41:56 2009
+++ /trunk/tests/com/google/caja/plugin/CssValidatorTest.java Thu Nov 19
15:57:15 2009
@@ -199,7 +199,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value: "
+ "WARNING: css property font has bad value: "
+ "status-bar ==><== caption");
// size and family
@@ -235,7 +235,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " -12pt ==>url('Arial')<==");
runTest("p, dl { font: twelve Arial; }",
"StyleSheet\n"
@@ -292,7 +292,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " ==>150Arial<==");
runTest("p, dl { font: 150/Arial; }",
"StyleSheet\n"
@@ -304,7 +304,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " 150 / ==>Arial<==");
runTest("p, dl { font: medium Arial; }",
"StyleSheet\n"
@@ -385,7 +385,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " italic ==>bolderer<== 150% Arial");
runTest("p, dl { font: italix bolder 150% Arial; }",
"StyleSheet\n"
@@ -397,7 +397,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " ==>italix<== bolder 150% Arial");
// font-size also matches by previous terms
@@ -431,7 +431,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value: inherit");
+ "WARNING: css property font has bad value: inherit");
// weight size family
runTest("p, dl { font: 800 150% Arial; }",
@@ -517,7 +517,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " ==>abnormal<== 150% Arial");
// with line-height following /
@@ -564,7 +564,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " ==>abnormal<== 150% / 175% Arial");
runTest("p, dl { font: normal 800 150%/ Arial; }",
"StyleSheet\n"
@@ -576,7 +576,7 @@
+ " SimpleSelector\n"
+ " IdentLiteral : dl\n"
+ " EmptyDeclaration",
- "WARNING: removing css property font with bad value:"
+ "WARNING: css property font has bad value:"
+ " normal 800 150% / ==>Arial<==");
runTest("p, dl { font: normal 800 150%/17.5 Arial; }",
"StyleSheet\n"
@@ -1356,7 +1356,7 @@
+ " Selector\n"
+ " SimpleSelector\n"
+ " IdentLiteral : p\n",
- "WARNING: removing css property filter with bad value:"
+ "WARNING: css property filter has bad value:"
+ " ==>progid:foo.bar()<==");
runTest("p { filter:
progid:dximagetransform.microsoft.alpha(opaquity=50) }",
"StyleSheet\n"
@@ -1364,7 +1364,7 @@
+ " Selector\n"
+ " SimpleSelector\n"
+ " IdentLiteral : p\n",
- "WARNING: removing css property filter with bad value:"
+ "WARNING: css property filter has bad value:"
+ "
==>progid:dximagetransform.microsoft.alpha(opaquity=50)<==");
}
@@ -1397,7 +1397,7 @@
+ " Selector\n"
+ " SimpleSelector\n"
+ " IdentLiteral : p\n",
- "WARNING: removing css property color with bad value:
==>yelow<==");
+ "WARNING: css property color has bad value: ==>yelow<==");
}
public final void testHtmlStarHack() throws Exception {
=======================================
--- /trunk/tests/com/google/caja/reporting/HtmlSnippetProducerTest.java Thu
Jul 23 09:16:30 2009
+++ /trunk/tests/com/google/caja/reporting/HtmlSnippetProducerTest.java Thu
Nov 19 15:57:15 2009
@@ -32,7 +32,7 @@
pos, MessagePart.Factory.valueOf("http://<h1>foo</h1>")));
assertEquals(
""
- + "<a href=\"#\" class=\"filepos\""
+ + "<a href=\"#\" class=\"filepos nocode\""
+ "
onclick=\"selectLine('test:///testSnippetEscaped',1)\">"
+ "testSnippetEscaped:1</a>"
+ ": <style>background: url("
=======================================
--- /trunk/tests/com/google/caja/service/FetchedDataTest.java Thu Oct 8
15:42:37 2009
+++ /trunk/tests/com/google/caja/service/FetchedDataTest.java Thu Nov 19
15:57:15 2009
@@ -58,7 +58,7 @@
testUrl = URI.create("http://www.example.com/").toURL();
}
- public void testSimpleContent() throws Exception {
+ public final void testSimpleContent() throws Exception {
FetchedData fd = new FetchedData(
new TestURLConnection(testUrl, "abcdef", "text/html"));
assertEquals("text/html", fd.getContentType());
@@ -76,7 +76,7 @@
assertEquals(expectedCharSet, fd.getCharSet());
}
- public void testCharSetParsing() throws Exception {
+ public final void testCharSetParsing() throws Exception {
assertCharSet(
"iso-8859-1",
"text/html;charset=iso-8859-1");
=======================================
--- /trunk/tests/com/google/caja/service/TestHttpServletRequest.java Fri
Nov 13 11:43:08 2009
+++ /trunk/tests/com/google/caja/service/TestHttpServletRequest.java Thu
Nov 19 15:57:15 2009
@@ -14,18 +14,20 @@
package com.google.caja.service;
+import com.google.caja.util.Maps;
import com.google.caja.util.Strings;
import java.io.BufferedReader;
-import java.io.UnsupportedEncodingException;
import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
import java.io.IOException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.Enumeration;
-import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -39,15 +41,15 @@
/**
* @author [email protected] (Jasvir Nagra)
*/
-final class TestHttpServletRequest implements HttpServletRequest {
+public final class TestHttpServletRequest implements HttpServletRequest {
private final String queryString;
- private final Hashtable<String, List<String>> params
- = new Hashtable<String, List<String>>();
+ private final Map<String, List<String>> params = Maps.newHashMap();
private final byte[] content;
private final String contentType;
private final String characterEncoding;
-
- TestHttpServletRequest(String queryString) {
+ private final Map<String, String> headers = Maps.newHashMap();
+
+ public TestHttpServletRequest(String queryString) {
this.queryString = queryString;
this.content = new byte[0];
this.contentType = null;
@@ -80,17 +82,20 @@
public String getAuthType() { throw new UnsupportedOperationException();
}
public Cookie[] getCookies() { throw new
UnsupportedOperationException(); }
+ @SuppressWarnings("deprecation")
public long getDateHeader(String a) {
- throw new UnsupportedOperationException();
+ String h = headers.get(a);
+ return h != null ? new Date(h).getTime() : -1;
}
public String getHeader(String a) {
- throw new UnsupportedOperationException();
+ return headers.get(a);
}
public Enumeration<String> getHeaderNames() {
- throw new UnsupportedOperationException();
+ return enumeration(headers.keySet().iterator());
}
public int getIntHeader(String arg0) {
- throw new UnsupportedOperationException();
+ String h = headers.get(arg0);
+ return h != null ? Integer.valueOf(h) : -1;
}
public String getMethod() { throw new UnsupportedOperationException(); }
public String getPathInfo() { throw new UnsupportedOperationException();
}
@@ -146,7 +151,9 @@
public String getParameter(String k) {
return params.containsKey(k) ? params.get(k).get(0) : null;
}
- public Enumeration<?> getParameterNames() { return params.keys(); }
+ public Enumeration<String> getParameterNames() {
+ return enumeration(params.keySet().iterator());
+ }
public String[] getParameterValues(String k) {
List<String> vals = params.get(k);
return vals != null ? vals.toArray(new String[0]) : null;
@@ -223,4 +230,11 @@
public void setCharacterEncoding(String encodingName) {
throw new UnsupportedOperationException();
}
-}
+
+ private static <T> Enumeration<T> enumeration(final Iterator<T> it) {
+ return new Enumeration<T>() {
+ public boolean hasMoreElements() { return it.hasNext(); }
+ public T nextElement() { return it.next(); }
+ };
+ }
+}
=======================================
--- /trunk/tests/com/google/caja/service/TestHttpServletResponse.java Fri
Nov 13 11:43:08 2009
+++ /trunk/tests/com/google/caja/service/TestHttpServletResponse.java Thu
Nov 19 15:57:15 2009
@@ -14,6 +14,7 @@
package com.google.caja.service;
+import com.google.caja.util.Maps;
import com.google.caja.util.Strings;
import java.io.ByteArrayOutputStream;
@@ -24,8 +25,8 @@
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Date;
-import java.util.Hashtable;
import java.util.Locale;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -36,9 +37,9 @@
/**
* @author [email protected] (Jasvir Nagra)
*/
-final class TestHttpServletResponse implements HttpServletResponse {
+public final class TestHttpServletResponse implements HttpServletResponse {
private int status = 200;
- private Hashtable<String, String> headers = new Hashtable<String,
String>();
+ private Map<String, String> headers = Maps.newLinkedHashMap();
private Object output;
public void addCookie(Cookie a) { throw new
UnsupportedOperationException(); }
public boolean containsHeader(String n) { return headers.containsKey(n);
}
@@ -66,14 +67,14 @@
throw new UnsupportedOperationException();
}
public void setDateHeader(String arg0, long arg1) {
- throw new UnsupportedOperationException();
+ setHeader(arg0, new Date(arg1).toString());
}
public void setHeader(String k, String v) {
if (output != null) { throw new IllegalStateException(); }
headers.put(Strings.toLowerCase(k), v);
}
public void setIntHeader(String arg0, int arg1) {
- throw new UnsupportedOperationException();
+ setHeader(arg0, "" + arg1);
}
public void setStatus(int status) {
if (output != null) { throw new IllegalStateException(); }
@@ -167,4 +168,6 @@
public void setLocale(Locale arg0) {
throw new UnsupportedOperationException();
}
-}
+
+ public Map<String, String> getHeaders() { return headers; }
+}