/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.citrus.util;
import static com.alibaba.citrus.test.TestUtil.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Formatter;
import java.util.Locale;
import com.alibaba.citrus.util.i18n.LocaleUtil;
import com.alibaba.citrus.util.internal.Entities;
import org.junit.Before;
import org.junit.Test;
/**
* 测试<code>StringEscapeUtil</code>。
*
* @author Michael Zhou
*/
public class StringEscapeUtilTests {
private Entities entities;
@Before
public void init() {
entities = new Entities();
entities.addEntity("foo", '\u00A1');
entities.addEntity("bar", '\u00A2');
}
/* ==================================================================== */
/* 测试Java和JavaScript。 */
/* ==================================================================== */
@Test
public void escapeJava() throws IOException {
assertEquals(null, StringEscapeUtil.escapeJava(null));
try {
StringEscapeUtil.escapeJava(null, null);
fail();
} catch (IllegalArgumentException e) {
}
try {
StringEscapeUtil.escapeJava("", null);
fail();
} catch (IllegalArgumentException e) {
}
assertEscapeJava("empty string", "", "", false);
assertEscapeJava("foo", "foo", false);
assertEscapeJava("tab", "\\t", "\t", false);
assertEscapeJava("backslash", "\\\\", "\\", false);
assertEscapeJava("single quote should not be escaped", "'", "'", false);
assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r", false);
assertEscapeJava("\u1234", "\u1234", false);
assertEscapeJava("\u0234", "\u0234", false);
assertEscapeJava("\u00EF", "\u00ef", false);
assertEscapeJava("\\u0001", "\u0001", false);
assertEscapeJava("Should use capitalized unicode hex", "\\u001A", "\u001a", false);
assertEscapeJava("He didn't say, \\\"stop!\\\"", "He didn't say, \"stop!\"", false);
assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\u00A0",
"This space is non-breaking:\u00a0", false);
assertEscapeJava("\uABCD\u1234\u012C", "\uABCD\u1234\u012C", false);
// 对slash的escape
assertEscapeJava("He didn't say, /stop!/", "He didn't say, /stop!/", false);
// 不需要escape的字符串,应该返回原字符串,以提高效率
assertEscapeJava("hello, i'm baobao", "hello, i'm baobao", false);
}
@Test
public void escapeJavaStrict() throws IOException {
assertEquals(null, StringEscapeUtil.escapeJava(null));
try {
StringEscapeUtil.escapeJava(null, null);
fail();
} catch (IllegalArgumentException e) {
}
try {
StringEscapeUtil.escapeJava("", null);
fail();
} catch (IllegalArgumentException e) {
}
assertEscapeJava("empty string", "", "", true);
assertEscapeJava("foo", "foo", true);
assertEscapeJava("tab", "\\t", "\t", true);
assertEscapeJava("backslash", "\\\\", "\\", true);
assertEscapeJava("single quote should not be escaped", "'", "'", true);
assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r", true);
assertEscapeJava("\\u1234", "\u1234", true);
assertEscapeJava("\\u0234", "\u0234", true);
assertEscapeJava("\u00EF", "\u00ef", true);
assertEscapeJava("\\u0001", "\u0001", true);
assertEscapeJava("Should use capitalized unicode hex", "\\u001A", "\u001a", true);
assertEscapeJava("He didn't say, \\\"stop!\\\"", "He didn't say, \"stop!\"", true);
assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\u00A0",
"This space is non-breaking:\u00a0", true);
assertEscapeJava("\\uABCD\\u1234\\u012C", "\uABCD\u1234\u012C", true);
// 不需要escape的字符串,应该返回原字符串,以提高效率
assertEscapeJava("hello, i'm baobao", "hello, i'm baobao", true);
}
private void assertEscapeJava(String escaped, String original, boolean strict) throws IOException {
assertEscapeJava(null, escaped, original, strict);
}
private void assertEscapeJava(String message, String expected, String original, boolean strict) throws IOException {
String converted = strict ? StringEscapeUtil.escapeJava(original, true) : StringEscapeUtil.escapeJava(original);
message = "escapeJava(String) failed" + (message == null ? "" : ": " + message);
assertEquals(message, expected, converted);
// 如果converted和original相等的话,它们应该是同一个对象
if (original != null && original.equals(converted)) {
assertSame(original, converted);
}
StringWriter out = new StringWriter();
if (strict) {
StringEscapeUtil.escapeJava(original, out, true);
} else {
StringEscapeUtil.escapeJava(original, out);
}
assertEquals(expected, out.toString());
}
@Test
public void unescapeJava() throws IOException {
assertEquals(null, StringEscapeUtil.unescapeJava(null));
try {
StringEscapeUtil.unescapeJava(null, null);
fail();
} catch (IllegalArgumentException e) {
}
try {
StringEscapeUtil.unescapeJava("", null);
fail();
} catch (IllegalArgumentException e) {
}
assertUnescapeJava("\\u02-3", "\\u02-3");
assertUnescapeJava("", "");
assertUnescapeJava("test", "test");
assertUnescapeJava("\ntest\b", "\\ntest\\b");
assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
assertUnescapeJava("\\", "\\");
// foo
assertUnescapeJava("lowercase unicode", "\uABCDx", "\\uabcdx");
assertUnescapeJava("uppercase unicode", "\uABCDx", "\\uABCDx");
assertUnescapeJava("unicode as final character", "\uABCD", "\\uabcd");
// 不需要unescape的字符串,应该返回原字符串,以提高效率
assertUnescapeJava("hello, i'm baobao", "hello, i'm baobao");
}
private void assertUnescapeJava(String unescaped, String original) throws IOException {
assertUnescapeJava(null, unescaped, original);
}
private void assertUnescapeJava(String message, String unescaped, String original) throws IOException {
String expected = unescaped;
String actual = StringEscapeUtil.unescapeJava(original);
assertEquals("unescape(String) failed" + (message == null ? "" : ": " + message) + ": expected '"
+ StringEscapeUtil.escapeJava(expected) // we escape this so we can see it in the error message
+ "' actual '" + StringEscapeUtil.escapeJava(actual) + "'", expected, actual);
// 如果actual和original相等的话,它们应该是同一个对象
if (original != null && original.equals(actual)) {
assertSame(original, actual);
}
StringWriter out = new StringWriter();
StringEscapeUtil.unescapeJava(original, out);
assertEquals(unescaped, out.toString());
}
@Test
public void escapeJavaScript() throws IOException {
assertEquals(null, StringEscapeUtil.escapeJavaScript(null));
try {
StringEscapeUtil.escapeJavaScript(null, null);
fail();
} catch (IllegalArgumentException e) {
}
try {
StringEscapeUtil.escapeJavaScript("", null);
fail();
} catch (IllegalArgumentException e) {
}
assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtil.escapeJavaScript("He didn't say, \"stop!\""));
// 对slash的escape
assertEquals("He didn\\'t say, \\/stop!\\/", StringEscapeUtil.escapeJavaScript("He didn't say, /stop!/"));
// 不需要escape的字符串,应该返回原字符串,以提高效率
assertSame("hello, im baobao", StringEscapeUtil.escapeJavaScript("hello, im baobao"));
// 非strict
assertEquals("\u1234", StringEscapeUtil.escapeJavaScript("\u1234", false));
assertEquals("\u0234", StringEscapeUtil.escapeJavaScript("\u0234", false));
assertEquals("\u00EF", StringEscapeUtil.escapeJavaScript("\u00ef", false));
assertEquals("\\u0001", StringEscapeUtil.escapeJavaScript("\u0001", false));
assertEquals("Should use capitalized unicode hex", "\\u001A",
StringEscapeUtil.escapeJavaScript("\u001a", false));
// strict
assertEquals("\\u1234", StringEscapeUtil.escapeJavaScript("\u1234", true));
assertEquals("\\u0234", StringEscapeUtil.escapeJavaScript("\u0234", true));
assertEquals("\u00EF", StringEscapeUtil.escapeJavaScript("\u00ef", true));
assertEquals("\\u0001", StringEscapeUtil.escapeJavaScript("\u0001", true));
assertEquals("Should use capitalized unicode hex", "\\u001A", StringEscapeUtil.escapeJavaScript("\u001a", true));
}
/* ==================================================================== */
/* 测试HTML和XML。 */
/* ==================================================================== */
private String[][] HTML_ESCAPES = {
{ "no escaping", "plain text", "plain text" },
{ "no escaping", "plain text", "plain text" },
{ "empty string", "", "" },
{ "null", null, null },
{ "ampersand", "bread & butter", "bread & butter" },
{ "quotes", ""bread" & butter", "\"bread\" & butter" },
{ "final character only", "greater than >", "greater than >" },
{ "first character only", "< less than", "< less than" },
{ "apostrophe", "Huntington's chorea", "Huntington's chorea" },
{ "languages", "English,Français,\u65E5\u672C\u8A9E (nihongo)",
"English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)" },
{ "8-bit ascii doesn't number-escape", "~\u007F", "\u007E\u007F" },
{ "8-bit ascii does number-escape", "\u0080\u009F", "\u0080\u009F" },
{ "funny chars pass through OK", "Français", "Fran\u00E7ais" }, { "nbsp", " ", "\u00A0" },
{ "html versions", "Β", "\u0392" }, { "illegal entity", "&zzzz;", "&zzzz;" },
{ "illegal entity", "&", "&" }, { "illegal entity", "&;", "&;" },
{ "illegal entity", "&#", "" }, { "illegal entity", "&#;", "" },
{ "illegal entity", "&#abc;", "abc;" } };
private String[][] HTML_UNESCAPES = {
{ "no escaping", "plain text", "plain text" },
{ "no escaping", "plain text", "plain text" },
{ "empty string", "", "" },
{ "null", null, null },
{ "ampersand", "bread & butter", "bread & butter" },
{ "quotes", ""bread" & butter", "\"bread\" & butter" },
{ "final character only", "greater than >", "greater than >" },
{ "first character only", "< less than", "< less than" },
{ "apostrophe", "Huntington's chorea", "Huntington's chorea" },
{ "languages", "English,Français,\u65E5\u672C\u8A9E (nihongo)",
"English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)" },
{ "8-bit ascii doesn't number-escape", "~\u007F", "\u007E\u007F" },
{ "8-bit ascii does number-escape", "\u0080\u009F", "\u0080\u009F" },
{ "funny chars pass through OK", "Français", "Fran\u00E7ais" }, { "nbsp", " ", "\u00A0" },
{ "html versions", "Β", "\u0392" }, { "illegal entity", "&zzzz;", "&zzzz;" },
{ "illegal entity", "&", "&" }, { "illegal entity", "&;", "&;" }, { "illegal entity", "", "" },
{ "illegal entity", "", "" }, { "illegal entity", "abc;", "abc;" },
{ "number entity", "中", "中" }, { "illegal entity", "", "" },
{ "illegal entity", "", "" }, { "illegal entity", "zzz;", "zzz;" },
{ "number entity", "中", "中" }, { "number entity", "中", "中" }, };
@Test
public void escapeUnescapeHtml() throws IOException {
for (int i = 0; i < HTML_ESCAPES.length; ++i) {
String message = HTML_ESCAPES[i][0];
String expected = HTML_ESCAPES[i][1];
String original = HTML_ESCAPES[i][2];
assertEquals(message, expected, StringEscapeUtil.escapeHtml(original));
assertEscapeHtmlEntities(message, expected, original, true);
}
try {
StringEscapeUtil.escapeHtml("", null);
fail();
} catch (IllegalArgumentException e) {
}
for (int i = 0; i < HTML_UNESCAPES.length; ++i) {
String message = HTML_UNESCAPES[i][0];
String expected = HTML_UNESCAPES[i][2];
String original = HTML_UNESCAPES[i][1];
assertEquals(message, expected, StringEscapeUtil.unescapeHtml(original));
assertEscapeHtmlEntities(message, expected, original, false);
}
try {
StringEscapeUtil.unescapeHtml("", null);
fail();
} catch (IllegalArgumentException e) {
}
}
private void assertEscapeHtmlEntities(String message, String expected, String str, boolean escape)
throws IOException {
StringWriter out = new StringWriter();
if (escape) {
String result = StringEscapeUtil.escapeHtml(str);
assertEquals(message, expected, result);
// 如果输入输出字符串相等,则它们应该是同一个字符串,这样系统性能更好
if (result != null && result.equals(str)) {
assertSame(str, result);
}
StringEscapeUtil.escapeHtml(str, out);
} else {
String result = StringEscapeUtil.unescapeHtml(str);
assertEquals(message, expected, result);
// 如果输入输出字符串相等,则它们应该是同一个字符串,这样系统性能更好
if (result != null && result.equals(str)) {
assertSame(str, result);
}
StringEscapeUtil.unescapeHtml(str, out);
}
String result = out.toString();
assertEquals(message, expected, str == null && result.length() == 0 ? null : result);
}
@Test
public void escapeUnescapeXml() throws Exception {
assertEscapeXmlEntities("<abc>", "<abc>", true);
assertEscapeXmlEntities("<abc>", "<abc>", false);
assertEscapeXmlEntities("\u00A1", "\u00A1", true);
assertEscapeXmlEntities("\u00A0", "\u00A0", true);
assertEscapeXmlEntities("\u00A0", " ", false);
assertEscapeXmlEntities(" ", " ", false);
assertEscapeXmlEntities("ain't", "ain't", false);
assertEscapeXmlEntities("ain't", "ain't", true);
assertEscapeXmlEntities("", "", true);
assertEscapeXmlEntities(null, null, true);
assertEscapeXmlEntities(null, null, false);
try {
StringEscapeUtil.escapeXml("", null);
fail();
} catch (IllegalArgumentException e) {
}
try {
StringEscapeUtil.unescapeXml("", null);
fail();
} catch (IllegalArgumentException e) {
}
}
private void assertEscapeXmlEntities(String expected, String str, boolean escape) throws IOException {
StringWriter out = new StringWriter();
if (escape) {
String result = StringEscapeUtil.escapeXml(str);
assertEquals(expected, result);
// 如果输入输出字符串相等,则它们应该是同一个字符串,这样系统性能更好
if (result != null && result.equals(str)) {
assertSame(str, result);
}
StringEscapeUtil.escapeXml(str, out);
} else {
String result = StringEscapeUtil.unescapeXml(str);
assertEquals(expected, result);
// 如果输入输出字符串相等,则它们应该是同一个字符串,这样系统性能更好
if (result != null && result.equals(str)) {
assertSame(str, result);
}
StringEscapeUtil.unescapeXml(str, out);
}
String result = out.toString();
assertEquals(expected, str == null && result.length() == 0 ? null : result);
}
/* ==================================================================== */
/* 测试一般的entities。 */
/* ==================================================================== */
@Test
public void escapeEntity() throws IOException {
assertEscapeEntities("&foo;", "\u00A1", true);
assertEscapeEntities("x&foo;", "x\u00A1", true);
assertEscapeEntities("&foo;x", "\u00A1x", true);
assertEscapeEntities("x&foo;x", "x\u00A1x", true);
assertEscapeEntities("&foo;&bar;", "\u00A1\u00A2", true);
try {
StringEscapeUtil.escapeEntities(entities, "", null);
fail();
} catch (IllegalArgumentException e) {
}
}
@Test
public void unescapeNamedEntity() throws IOException {
assertEscapeEntities("\u00A1", "&foo;", false);
assertEscapeEntities("x\u00A1", "x&foo;", false);
assertEscapeEntities("\u00A1x", "&foo;x", false);
assertEscapeEntities("x\u00A1x", "x&foo;x", false);
assertEscapeEntities("\u00A1\u00A2", "&foo;&bar;", false);
try {
StringEscapeUtil.unescapeEntities(entities, "", null);
fail();
} catch (IllegalArgumentException e) {
}
}
@Test
public void unescapeUnicodeEntity() throws IOException {
assertEscapeEntities("\u00A1", "¡", false);
assertEscapeEntities("x中x", "x中x", false);
entities = null;
assertEscapeEntities("x中x", "x中x", false);
}
@Test
public void unescapeUnknownEntity() throws IOException {
assertEscapeEntities("&zzzz;", "&zzzz;", false);
assertEscapeEntities("&", "&", false);
assertEscapeEntities("&;", "&;", false);
assertEscapeEntities("", "", false);
assertEscapeEntities("", "", false);
assertEscapeEntities("abc;", "abc;", false);
}
private void assertEscapeEntities(String expected, String str, boolean escape) throws IOException {
StringWriter out = new StringWriter();
if (escape) {
StringEscapeUtil.escapeEntities(entities, str, out);
} else {
StringEscapeUtil.unescapeEntities(entities, str, out);
}
assertEquals(expected, out.toString());
}
@Test
public void testUnEscapeNullEntities() {
assertEquals("中华人民共和国",
StringEscapeUtil.unescapeEntities(null, "中华人民共和国"));
assertEquals("&<", StringEscapeUtil.unescapeEntities(null, "&<"));
}
/* ==================================================================== */
/* 测试SQL。 */
/* 参考:http://www.jguru.com/faq/view.jsp?EID=8881 */
/* ==================================================================== */
@Test
public void escapeSql() throws Exception {
assertEscapeSql("don''t stop", "don't stop");
assertEscapeSql("", "");
assertEscapeSql(null, null);
try {
StringEscapeUtil.escapeSql("", null);
fail();
} catch (IllegalArgumentException e) {
}
}
private void assertEscapeSql(String expected, String str) throws IOException {
StringWriter out = new StringWriter();
StringEscapeUtil.escapeSql(str, out);
assertEquals(expected, StringEscapeUtil.escapeSql(str));
assertEquals(expected == null ? "" : expected, out.toString());
}
/* ==================================================================== */
/* URL/URI encoding/decoding。 */
/* 根据RFC2396:http://www.ietf.org/rfc/rfc2396.txt */
/* ==================================================================== */
@Test
public void escapeURLStrict() throws Exception {
String unreserved = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
assertSame(unreserved, StringEscapeUtil.escapeURL(unreserved));
// 测试所有ISO-8859-1字符
StringBuilder buffer = new StringBuilder(256);
StringBuilder expectedBuffer = new StringBuilder(256 * 3);
for (int i = 0; i < 256; i++) {
buffer.append((char) i);
if (i == ' ') {
expectedBuffer.append('+');
} else if (unreserved.indexOf(i) == -1) {
new Formatter(expectedBuffer).format("%%%02X", i);
} else {
expectedBuffer.append((char) i);
}
}
String str = buffer.toString();
String expectedStr = expectedBuffer.toString();
assertEquals(expectedStr, StringEscapeUtil.escapeURL(str, "8859_1"));
// 测试writer
StringWriter writer = new StringWriter();
StringEscapeUtil.escapeURL(str, "8859_1", writer);
assertEquals(expectedStr, writer.toString());
// 测试中文
assertEquals("%D6%D0%BB%AA%C8%CB%C3%F1%B9%B2%BA%CD%B9%FA", StringEscapeUtil.escapeURL("中华人民共和国", "GBK"));
// 中文writer
writer = new StringWriter();
StringEscapeUtil.escapeURL("中华人民共和国", "GBK", writer);
assertEquals("%D6%D0%BB%AA%C8%CB%C3%F1%B9%B2%BA%CD%B9%FA", writer.toString());
}
@Test
public void escapeURLLoose() throws Exception {
String reserved = ";/?:@&=+$,";
assertEquals("%3B%2F%3F%3A%40%26%3D%2B%24%2C", StringEscapeUtil.escapeURL(reserved, "8859_1", false));
// 测试所有ISO-8859-1字符
StringBuilder buffer = new StringBuilder(256);
StringBuilder expectedBuffer = new StringBuilder(256 * 3);
for (int i = 0; i < 256; i++) {
buffer.append((char) i);
if (i == ' ') {
expectedBuffer.append('+');
} else if (reserved.indexOf(i) == -1 && i > 32) {
expectedBuffer.append((char) i);
} else {
new Formatter(expectedBuffer).format("%%%02X", i);
}
}
String str = buffer.toString();
String expectedStr = expectedBuffer.toString();
assertEquals(expectedStr, StringEscapeUtil.escapeURL(str, "8859_1", false));
// 测试writer
StringWriter writer = new StringWriter();
StringEscapeUtil.escapeURL(str, "8859_1", writer, false);
assertEquals(expectedStr, writer.toString());
// 测试中文和全角空格
str = "中华人民共和国";
assertSame(str, StringEscapeUtil.escapeURL(str, "GBK", false));
str = "中华人民共和国\u3000";
assertEquals("中华人民共和国%A1%A1", StringEscapeUtil.escapeURL(str, "GBK", false));
// 中文writer
writer = new StringWriter();
StringEscapeUtil.escapeURL("中华人民共和国", "GBK", writer, false);
assertEquals("中华人民共和国", writer.toString());
}
@Test
public void escapeURLEncoding() {
LocaleUtil.setContext(Locale.CHINA, "GBK");
assertEquals("%D6%D0%BB%AA%C8%CB%C3%F1%B9%B2%BA%CD%B9%FA", StringEscapeUtil.escapeURL("中华人民共和国"));
LocaleUtil.setContext(Locale.US, "8859_1");
assertEquals("%3F%3F%3F%3F%3F%3F%3F", StringEscapeUtil.escapeURL("中华人民共和国"));
LocaleUtil.resetContext();
}
@Test
public void unescapeURL() throws Exception {
assertEquals(null, StringEscapeUtil.unescapeURL(null));
try {
StringEscapeUtil.unescapeURL("test", null, null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("The Appendable must not be null"));
}
}
@Test
public void unescapeURLStrict() throws Exception {
String unreserved = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
String escaped = StringEscapeUtil.escapeURL(unreserved);
assertSame(unreserved, StringEscapeUtil.unescapeURL(escaped));
// 测试所有ISO-8859-1字符
StringBuilder buffer = new StringBuilder(256);
StringBuilder expectedBuffer = new StringBuilder(256 * 3);
for (int i = 0; i < 256; i++) {
buffer.append((char) i);
if (i == ' ') {
expectedBuffer.append('+');
} else if (unreserved.indexOf(i) == -1) {
new Formatter(expectedBuffer).format("%%%02X", i);
} else {
expectedBuffer.append((char) i);
}
}
String str = buffer.toString();
String expectedStr = expectedBuffer.toString();
escaped = StringEscapeUtil.escapeURL(str, "8859_1");
assertEquals(expectedStr, escaped);
assertEquals(str, StringEscapeUtil.unescapeURL(escaped, "8859_1"));
// 测试writer
StringWriter writer = new StringWriter();
StringEscapeUtil.unescapeURL(escaped, "8859_1", writer);
assertEquals(str, writer.toString());
// 测试中文
escaped = StringEscapeUtil.escapeURL("中华人民共和国", "GBK");
assertEquals("中华人民共和国", StringEscapeUtil.unescapeURL(escaped, "GBK"));
// 中文writer
writer = new StringWriter();
StringEscapeUtil.unescapeURL(escaped, "GBK", writer);
assertEquals("中华人民共和国", writer.toString());
// 错误的编码
str = "abc%xx%20%1";
assertEquals("abc%xx %1", StringEscapeUtil.unescapeURL(str));
str = "abc%xx%1%";
assertSame(str, StringEscapeUtil.unescapeURL(str));
}
@Test
public void unescapeURLLoose() throws Exception {
String reserved = ";/?:@&=+$,";
String escaped = StringEscapeUtil.escapeURL(reserved, "8859_1", false);
assertEquals(reserved, StringEscapeUtil.unescapeURL(escaped, "8859_1"));
// 测试所有ISO-8859-1字符
StringBuilder buffer = new StringBuilder(256);
StringBuilder expectedBuffer = new StringBuilder(256 * 3);
for (int i = 0; i < 256; i++) {
buffer.append((char) i);
if (i == ' ') {
expectedBuffer.append('+');
} else if (reserved.indexOf(i) == -1 && i > 32) {
expectedBuffer.append((char) i);
} else {
new Formatter(expectedBuffer).format("%%%02X", i);
}
}
String str = buffer.toString();
String expectedStr = expectedBuffer.toString();
escaped = StringEscapeUtil.escapeURL(str, "8859_1", false);
assertEquals(expectedStr, escaped);
assertEquals(str, StringEscapeUtil.unescapeURL(escaped, "8859_1"));
// 测试writer
StringWriter writer = new StringWriter();
escaped = StringEscapeUtil.escapeURL(str, "8859_1", false);
StringEscapeUtil.unescapeURL(escaped, "8859_1", writer);
assertEquals(str, writer.toString());
// 测试中文和全角空格
str = "中华人民共和国";
assertSame(str, StringEscapeUtil.unescapeURL("中华人民共和国", "GBK"));
str = "中华人民共和国\u3000";
assertEquals(str, StringEscapeUtil.unescapeURL("中华人民共和国%A1%A1", "GBK"));
// 中文writer
writer = new StringWriter();
StringEscapeUtil.unescapeURL("中华人民共和国", "GBK", writer);
assertEquals("中华人民共和国", writer.toString());
}
@Test
public void unescapeURLEncoding() {
LocaleUtil.setContext(Locale.CHINA, "GBK");
assertEquals("中华人民共和国", StringEscapeUtil.unescapeURL("%D6%D0%BB%AA%C8%CB%C3%F1%B9%B2%BA%CD%B9%FA"));
LocaleUtil.setContext(Locale.US, "8859_1");
assertEquals("\u00D6\u00D0\u00BB\u00AA\u00C8\u00CB\u00C3\u00F1\u00B9\u00B2\u00BA\u00CD\u00B9\u00FA",
StringEscapeUtil.unescapeURL("%D6%D0%BB%AA%C8%CB%C3%F1%B9%B2%BA%CD%B9%FA"));
LocaleUtil.resetContext();
}
@Test
public void unescapeURL_rawBytes() throws Exception {
LocaleUtil.setContext(Locale.CHINA, "GBK");
String escaped = StringEscapeUtil.escapeURL("Justin\u00b7Bieber");
assertEquals("Justin\u00b7Bieber", StringEscapeUtil.unescapeURL(escaped));
assertEquals("中华民国100年", StringEscapeUtil.unescapeURL(reencode("中华民国100年", "GBK"), "GBK"));
// 混合中/英文、编码/未编码
assertEquals("中华abc 人民共和国abc 人", StringEscapeUtil.unescapeURL("中华abc+\310%CB民共和国abc+\310%CB", "GBK"));
assertSame("abc中华", StringEscapeUtil.unescapeURL("abc中华", "GBK"));
assertSame("ab中华c", StringEscapeUtil.unescapeURL("ab中华c", "GBK"));
assertSame("中华abc", StringEscapeUtil.unescapeURL("中华abc", "GBK"));
assertSame("中abc华", StringEscapeUtil.unescapeURL("中abc华", "GBK"));
assertEquals("abc中华", StringEscapeUtil.unescapeURL(reencode("abc中", "GBK") + "华", "GBK"));
assertEquals("中华abc", StringEscapeUtil.unescapeURL(reencode("中", "GBK") + "华abc", "GBK"));
LocaleUtil.resetContext();
}
private String reencode(String str, String charset) throws Exception {
return new String(str.getBytes(charset), "8859_1");
}
}