| package main; |
| |
| import java.io.*; |
| |
| import org.codehaus.jackson.*; |
| |
| import java.util.Random; |
| |
| /** |
| * Set of basic unit tests for verifying that the string |
| * generation, including character escaping, works as expected. |
| */ |
| public class TestStringGeneration |
| extends BaseTest |
| { |
| final static String[] SAMPLES = new String[] { |
| "\"test\"", |
| "\n", "\\n", "\r\n", "a\\b", "tab:\nok?", |
| "a\tb\tc\n\fdef\t \tg\"\"\"h\"\\ijklmn\b", |
| "\"\"\"", "\\r)'\"", |
| "Longer text & other stuff:\twith some\r\n\r\n random linefeeds etc added in to cause some \"special\" handling \\\\ to occur...\n" |
| }; |
| |
| public void testBasicEscaping() |
| throws Exception |
| { |
| doTestBasicEscaping(false); |
| doTestBasicEscaping(true); |
| } |
| |
| public void testLongerRandomSingleChunk() |
| throws Exception |
| { |
| /* Let's first generate 100k of pseudo-random characters, favoring |
| * 7-bit ascii range |
| */ |
| for (int round = 0; round < 80; ++round) { |
| String content = generateRandom(75000+round); |
| doTestLongerRandom(content, false); |
| doTestLongerRandom(content, true); |
| } |
| } |
| |
| public void testLongerRandomMultiChunk() |
| throws Exception |
| { |
| /* Let's first generate 100k of pseudo-random characters, favoring |
| * 7-bit ascii range |
| */ |
| for (int round = 0; round < 70; ++round) { |
| String content = generateRandom(73000+round); |
| doTestLongerRandomMulti(content, false, round); |
| doTestLongerRandomMulti(content, true, round); |
| } |
| } |
| |
| /* |
| /////////////////////////////////////////////////////////////// |
| // Internal methods |
| /////////////////////////////////////////////////////////////// |
| */ |
| |
| private String generateRandom(int len) |
| { |
| StringBuilder sb = new StringBuilder(len+1000); // pad for surrogates |
| Random r = new Random(len); |
| for (int i = 0; i < len; ++i) { |
| if (r.nextBoolean()) { // non-ascii |
| int value = r.nextInt() & 0xFFFF; |
| // Otherwise easy, except that need to ensure that |
| // surrogates are properly paired: and, also |
| // their values do not exceed 0x10FFFF |
| if (value >= 0xD800 && value <= 0xDFFF) { |
| // Let's discard first value, then, and produce valid pair |
| int fullValue = (r.nextInt() & 0xFFFFF); |
| sb.append((char) (0xD800 + (fullValue >> 10))); |
| value = 0xDC00 + (fullValue & 0x3FF); |
| } |
| sb.append((char) value); |
| } else { // ascii |
| sb.append((char) (r.nextInt() & 0x7F)); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| private void doTestBasicEscaping(boolean charArray) |
| throws Exception |
| { |
| for (int i = 0; i < SAMPLES.length; ++i) { |
| String VALUE = SAMPLES[i]; |
| StringWriter sw = new StringWriter(); |
| JsonGenerator gen = new JsonFactory().createJsonGenerator(sw); |
| gen.writeStartArray(); |
| if (charArray) { |
| char[] buf = new char[VALUE.length() + i]; |
| VALUE.getChars(0, VALUE.length(), buf, i); |
| gen.writeString(buf, i, VALUE.length()); |
| } else { |
| gen.writeString(VALUE); |
| } |
| gen.writeEndArray(); |
| gen.close(); |
| String docStr = sw.toString(); |
| JsonParser jp = createParserUsingReader(docStr); |
| assertEquals(JsonToken.START_ARRAY, jp.nextToken()); |
| JsonToken t = jp.nextToken(); |
| assertEquals(JsonToken.VALUE_STRING, t); |
| assertEquals(VALUE, jp.getText()); |
| assertEquals(JsonToken.END_ARRAY, jp.nextToken()); |
| assertEquals(null, jp.nextToken()); |
| jp.close(); |
| } |
| } |
| |
| private void doTestLongerRandom(String text, boolean charArray) |
| throws Exception |
| { |
| ByteArrayOutputStream bow = new ByteArrayOutputStream(text.length()); |
| JsonGenerator gen = new JsonFactory().createJsonGenerator(bow, JsonFactory.Encoding.UTF8); |
| gen.writeStartArray(); |
| if (charArray) { |
| char[] buf = new char[text.length()]; |
| text.getChars(0, text.length(), buf, 0); |
| gen.writeString(buf, 0, text.length()); |
| } else { |
| gen.writeString(text); |
| } |
| gen.writeEndArray(); |
| gen.close(); |
| byte[] docData = bow.toByteArray(); |
| JsonParser jp = new JsonFactory().createJsonParser(new ByteArrayInputStream(docData)); |
| assertEquals(JsonToken.START_ARRAY, jp.nextToken()); |
| JsonToken t = jp.nextToken(); |
| assertEquals(JsonToken.VALUE_STRING, t); |
| String act = jp.getText(); |
| if (!text.equals(act)) { |
| if (text.length() != act.length()) { |
| fail("Expected string length "+text.length()+", actual "+act.length()); |
| } |
| int i = 0; |
| for (int len = text.length(); i < len; ++i) { |
| if (text.charAt(i) != act.charAt(i)) { |
| break; |
| } |
| } |
| fail("Strings differ at position #"+i+" (len "+text.length()+"): expected char 0x"+Integer.toHexString(text.charAt(i))+", actual 0x"+Integer.toHexString(act.charAt(i))); |
| } |
| assertEquals(JsonToken.END_ARRAY, jp.nextToken()); |
| assertEquals(null, jp.nextToken()); |
| jp.close(); |
| } |
| |
| private void doTestLongerRandomMulti(String text, boolean charArray, int round) |
| throws Exception |
| { |
| ByteArrayOutputStream bow = new ByteArrayOutputStream(text.length()); |
| JsonGenerator gen = new JsonFactory().createJsonGenerator(bow, JsonFactory.Encoding.UTF8); |
| gen.writeStartArray(); |
| |
| gen.writeString(text); |
| gen.writeEndArray(); |
| gen.close(); |
| |
| gen = new JsonFactory().createJsonGenerator(bow, JsonFactory.Encoding.UTF8); |
| gen.writeStartArray(); |
| gen.writeStartArray(); |
| |
| Random rnd = new Random(text.length()); |
| int offset = 0; |
| |
| while (offset < text.length()) { |
| int shift = 1 + ((rnd.nextInt() & 0xFFFFF) % 12); // 1 - 12 |
| int len = (1 << shift) + shift; // up to 4k |
| if ((offset + len) >= text.length()) { |
| len = text.length() - offset; |
| } else { |
| // Need to avoid splitting surrogates though |
| char c = text.charAt(offset+len-1); |
| if (c >= 0xD800 && c < 0xDC00) { |
| ++len; |
| } |
| } |
| if (charArray) { |
| char[] buf = new char[len]; |
| text.getChars(offset, offset+len, buf, 0); |
| gen.writeString(buf, 0, len); |
| } else { |
| gen.writeString(text.substring(offset, offset+len)); |
| } |
| offset += len; |
| } |
| |
| gen.writeEndArray(); |
| gen.close(); |
| byte[] docData = bow.toByteArray(); |
| JsonParser jp = new JsonFactory().createJsonParser(new ByteArrayInputStream(docData)); |
| assertEquals(JsonToken.START_ARRAY, jp.nextToken()); |
| |
| offset = 0; |
| while (jp.nextToken() == JsonToken.VALUE_STRING) { |
| // Let's verify, piece by piece |
| String act = jp.getText(); |
| String exp = text.substring(offset, offset+act.length()); |
| if (!act.equals(exp)) { |
| fail("String segment ["+offset+" - "+(offset+act.length())+"[ different"); |
| } |
| offset += act.length(); |
| } |
| assertEquals(JsonToken.END_ARRAY, jp.getCurrentToken()); |
| jp.close(); |
| } |
| |
| } |