webwork/src/test/webwork/util EncodingTestCase.java, NONE, 1.1 FastByteArrayOutputStreamTestCase.java, NONE, 1.1
[email protected] Wed, 16 Jan 2008 02:54:07 -0800
| Newsgroups | gmane.comp.java.open-symphony.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/opensymphony/webwork/src/test/webwork/util
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv9103/test/webwork/util
Added Files:
EncodingTestCase.java FastByteArrayOutputStreamTestCase.java
Log Message:
Fix encoding so that multi-byte characters don't mess up webwork's tags.
This fixes WW-1495 for the 1.4 webwork branch.
Patch courtesy of Brad Baker from Atlassian.
--- NEW FILE: EncodingTestCase.java ---
package webwork.util;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
/**
* Holds test strings and encodings. There was more test written hence the base class.
*/
public abstract class EncodingTestCase extends TestCase
{
static final int K = 1024;
static final String ASCII = "ASCII";
static final String UTF_8 = "UTF-8";
static final String LATIN = "ISO8859_1";
static final String UTF_16 = "UTF-16";
static final String KOI8_R = "KOI8_R";
static final String WINDOWS_CYRILLIC = "Cp1251";
static final String UBIG_ENDIAN = "UnicodeBig";
static final String ULITTLE_ENDIAN = "UnicodeLittle";
static final String UBIG_ENDIAN_UNMARKED = "UnicodeBigUnmarked";
static final String ULITTLE_ENDIAN_UNMARKED = "UnicodeLittleUnmarked";
static final String RUSSIAN_DESC1 = "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f";
static final String RUSSIAN_DESC_SHORT = "\u0418\u0441\u043f\u043e";
static final String ASCII_TEXT = "will this string be written to bytes and then back to chars as expected?";
static final String ASCII_TEXT_SHORT = "ok";
static final String CHINESE_TIMETRACKING = "\\u65f6\\u95f4\\u8ddf\\u8e2a\\u62a5\\u544a";
static final String HUNGRIAN_APPLET_PROBLEM = "Az Applet biztons\\u00e1gi be\\u00e1ll\\u00edt\\u00e1sai helytelenek. Fogadja el az Applet tan\\u00fas\\u00edtv\\u00e1ny\\u00e1t a futtat\\u00e1shoz.";
protected abstract void implementEncodingTest(String expectedStr, String encoding, int bufferSize) throws Exception;
void assertEncoding(String expectedStr, String encoding) throws Exception
{
doAssertionsOnCombinations(new String[] { expectedStr }, new String[] { encoding });
}
public void assertEncodings(String[] testStrs, String[] encodings) throws Exception
{
doAssertionsOnCombinations(testStrs, encodings);
}
private void doAssertionsOnCombinations(String[] testStrs, String[] encodings) throws Exception
{
int[] bufferSizes = { 1, 3, 5, 10, 101, 1024, 8192 };
int[] outputLens = { 100 * K, 50 * K, 20 * K, 10 * K, 1 * K };
// given a bunch of output buffer sizes
for (int i = 0; i < encodings.length; i++)
{
String encoding = encodings[i];
// but only if we have the encoding in this JDK
if (Charset.isSupported(encoding))
{
for (int j = 0; j < bufferSizes.length; j++)
{
int bufferSize = bufferSizes[j];
// with a number of strings
for (int k = 0; k < testStrs.length; k++)
{
String testStr = testStrs[k];
implementEncodingTest(testStr, encoding, bufferSize);
// now make the strings bigger up to a bunch of sizes
for (int l = 0; l < outputLens.length; l++)
{
int outputLen = outputLens[l];
final String largeStr = makeRoughly(testStr, outputLen);
try
{
implementEncodingTest(largeStr, encoding, bufferSize);
}
catch (AssertionFailedError afe)
{
throw afe;
}
catch (Throwable t)
{
t.printStackTrace();
throw new RuntimeException("enc :" + encoding + " bufferSize:" + bufferSize + " outputlen:" + outputLen);
}
}
}
}
}
}
}
protected String makeRoughly(String srcStr, int roughSize)
{
StringBuffer sb = new StringBuffer(srcStr);
while (sb.length() < roughSize)
{
sb.append(srcStr);
}
return sb.toString();
}
protected void assertTheyAreEqual(Object expected, Object actual, String encoding)
throws UnsupportedEncodingException
{
String expectedStr = expected.toString();
String actualStr = actual.toString();
try
{
Assert.assertEquals(expectedStr, actualStr);
}
catch (AssertionFailedError afe)
{
System.out.println("___ " + encoding + "__________");
System.out.println("EL:|" + expectedStr.length() + "|");
System.out.println("AL:|" + actualStr.length() + "|");
System.out.println("E:|" + expectedStr + "|");
System.out.println("A:|" + actualStr + "|");
byte[] expectedBytes = expectedStr.getBytes(encoding);
byte[] actualBytes = actualStr.getBytes(encoding);
System.out.println("E:|" + toHex(expectedBytes) + "|");
System.out.println("A:|" + toHex(actualBytes) + "|");
throw afe;
}
}
String toHex(byte[] bytes)
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++)
{
sb.append(Integer.toHexString(bytes[i]).toUpperCase());
}
return sb.toString();
}
}
--- NEW FILE: FastByteArrayOutputStreamTestCase.java ---
package webwork.util;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
/**
* A test class for {@link webwork.util.FastByteArrayOutputStream}
*
* @since v4.0
*/
public class FastByteArrayOutputStreamTestCase extends EncodingTestCase
{
public void testLatinCharsets() throws Exception
{
assertEncoding(ASCII_TEXT, LATIN);
assertEncoding(ASCII_TEXT, ASCII);
}
public void testRussianCharsets() throws Exception
{
assertEncoding(RUSSIAN_DESC_SHORT, KOI8_R);
assertEncoding(RUSSIAN_DESC1, KOI8_R);
assertEncoding(RUSSIAN_DESC_SHORT, WINDOWS_CYRILLIC);
assertEncoding(RUSSIAN_DESC1, WINDOWS_CYRILLIC);
}
public void testUnicodeCharsets() throws Exception
{
String[] testStrs = {ASCII_TEXT_SHORT, ASCII_TEXT, RUSSIAN_DESC_SHORT, RUSSIAN_DESC1, CHINESE_TIMETRACKING, HUNGRIAN_APPLET_PROBLEM, };
String[] encodings = { UTF_8, UTF_16, UBIG_ENDIAN, ULITTLE_ENDIAN, UBIG_ENDIAN_UNMARKED, ULITTLE_ENDIAN_UNMARKED };
assertEncodings(testStrs, encodings);
}
protected void implementEncodingTest(final String srcStr, final String encoding, final int bufferSize)
throws Exception
{
FastByteArrayOutputStream bout = new FastByteArrayOutputStream(bufferSize);
byte[] bytes = srcStr.getBytes(encoding);
bout.write(bytes);
JspWriter writer = new StringCapturingJspWriter();
bout.writeTo(writer, encoding);
String actualStr = writer.toString();
String expectedStr = new String(bytes, encoding);
assertTheyAreEqual(expectedStr, actualStr, encoding);
}
/**
* Before it was changed to use {@link java.nio.charset.CharsetDecoder} is took an this time
* <p/>
* Total Call Time = 1112.0ms
* Average Call Time = 0.001112ms
* <p/>
* Now with the change it takes this time
* <p/>
* <p/>
* The idea is that it did not get significantly worse in performance
*
* @throws IOException
*/
public void testPerformanceOfWriteToJspWriter() throws IOException
{
final String NINEK_STR = makeRoughly(ASCII, 9 * K);
final String FIFTYK_STR = makeRoughly(ASCII, 50 * K);
final String ONEHUNDREDK_STR = makeRoughly(ASCII, 100 * K);
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With < than 8K of data";
}
public String getText(final int times)
{
return ASCII_TEXT;
}
});
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With > than 8K of data";
}
public String getText(final int times)
{
return NINEK_STR;
}
});
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With a 2/3 mix of small data and 1/3 > 8K of data";
}
public String getText(final int times)
{
if (times % 3 == 0)
{
return NINEK_STR;
}
return ASCII_TEXT;
}
});
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With a 1/2 mix of small data and 1/2 > 8K of data";
}
public String getText(final int times)
{
if (times % 2 == 0)
{
return NINEK_STR;
}
return ASCII_TEXT;
}
});
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With 50K of data";
}
public String getText(final int times)
{
return FIFTYK_STR;
}
});
testPerformanceOfWriteToJspWriter(new TextSource()
{
public String getDesc()
{
return "With 100K of data";
}
public String getText(final int times)
{
return ONEHUNDREDK_STR;
}
});
}
public void testPerformanceOfWriteToJspWriter(TextSource textSource) throws IOException
{
NoopJspWriter noopJspWriter = new NoopJspWriter();
String[] methods = {
"writeTo (using hueristics)",
"writeToViaSmoosh",
};
System.out.println("====================");
System.out.println(textSource.getDesc());
System.out.println();
float bestTime = Float.MAX_VALUE;
String bestMethod = methods[0];
for (int methodIndex = 0; methodIndex < methods.length; methodIndex++)
{
String method = methods[methodIndex];
float totalTime = 0;
final int MAX_TIMES = 10;
final int MAX_ITERATIONS = 100;
for (int times = 0; times < MAX_TIMES; times++)
{
String srcText = textSource.getText(times);
for (int i = 0; i < MAX_ITERATIONS; i++)
{
FastByteArrayOutputStream bout = new FastByteArrayOutputStream();
bout.write(srcText.getBytes(UTF_8));
// just time the JspWriter output. And let it warm u first as well
if (times > 3)
{
long then = System.currentTimeMillis();
switch (methodIndex)
{
case 0:
bout.writeTo(noopJspWriter, UTF_8);
break;
case 1:
bout.writeToViaSmoosh(noopJspWriter, UTF_8);
break;
}
long now = System.currentTimeMillis();
totalTime += (now - then);
}
}
}
float avgTime = totalTime / MAX_TIMES / MAX_ITERATIONS;
System.out.println(method + " - Total Call Time = " + totalTime + "ms");
System.out.println(method + " - Average Call Time = " + avgTime + "ms");
System.out.println();
if (avgTime < bestTime) {
bestTime = avgTime;
bestMethod = method;
}
}
System.out.println(bestMethod + " was the best method - Average Call Time = " + bestTime + "ms");
System.out.println("____________________\n");
}
interface TextSource
{
String getDesc();
String getText(int times);
}
static class StringCapturingJspWriter extends NoopJspWriter
{
StringCapturingJspWriter()
{
super(true);
}
}
static class NoopJspWriter extends JspWriter
{
final StringBuffer sb = new StringBuffer();
final boolean capture;
NoopJspWriter()
{
this(false);
}
NoopJspWriter(boolean capture)
{
super(0, false);
this.capture = capture;
}
NoopJspWriter(final int i, final boolean b)
{
super(i, b);
this.capture = false;
}
public String toString()
{
return sb.toString();
}
public void clear() throws IOException
{
}
public void clearBuffer() throws IOException
{
}
public void close() throws IOException
{
}
public void flush() throws IOException
{
}
public int getRemaining()
{
return 0;
}
public void newLine() throws IOException
{
}
public void print(final char c) throws IOException
{
if (capture)
{
sb.append(c);
}
}
public void print(final double v) throws IOException
{
if (capture)
{
sb.append(v);
}
}
public void print(final float v) throws IOException
{
if (capture)
{
sb.append(v);
}
}
public void print(final int i) throws IOException
{
if (capture)
{
sb.append(i);
}
}
public void print(final long l) throws IOException
{
if (capture)
{
sb.append(l);
}
}
public void print(final Object o) throws IOException
{
if (capture)
{
sb.append(o);
}
}
public void print(final String s) throws IOException
{
if (capture)
{
sb.append(s);
}
}
public void print(final boolean b) throws IOException
{
if (capture)
{
sb.append(b);
}
}
public void print(final char[] chars) throws IOException
{
if (capture)
{
sb.append(chars);
}
}
public void println() throws IOException
{
print('\n');
}
public void println(final char c) throws IOException
{
print(c);
println();
}
public void println(final double v) throws IOException
{
print(v);
println();
}
public void println(final float v) throws IOException
{
print(v);
println();
}
public void println(final int i) throws IOException
{
print(i);
println();
}
public void println(final long l) throws IOException
{
print(l);
println();
}
public void println(final Object o) throws IOException
{
print(o);
println();
}
public void println(final String s) throws IOException
{
print(s);
println();
}
public void println(final boolean b) throws IOException
{
print(b);
println();
}
public void println(final char[] chars) throws IOException
{
print(chars);
println();
}
public void write(final char cbuf[], final int off, final int len) throws IOException
{
String s = new String(cbuf, off, len);
print(s);
}
}
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/