[Practicalxml-commits] SF.net SVN: practicalxml:[126] branches/dev-1.1/src
Brought to you by:
kdgregory
From: Auto-Generated S. C. M. <pra...@li...> - 2009-09-11 17:43:40
|
Revision: 126 http://practicalxml.svn.sourceforge.net/practicalxml/?rev=126&view=rev Author: kdgregory Date: 2009-09-11 17:43:24 +0000 (Fri, 11 Sep 2009) Log Message: ----------- implement JSON -> XML conversion Added Paths: ----------- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/JsonUtil.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonUtil.java Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java 2009-09-11 17:43:24 UTC (rev 126) @@ -0,0 +1,262 @@ +// Copyright 2008-2009 severally by the contributors +// +// 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 net.sf.practicalxml.converter.json; + +import org.w3c.dom.Element; + +import net.sf.practicalxml.DomUtil; +import net.sf.practicalxml.converter.ConversionException; + + +/** + * This class contains a hand-written recursive-descent parser for JSON + * strings. Instances are constructed around a source string, and used + * only once (thus thread-safety is not an issue). + * <p> + * See <a href="http://www.json.org/">json.org</a> for the JSON grammar. + * <p> + * The current implementation creates a child element for each element + * of an array, producing output similar to that from the Bean->XML + * conversion. + */ +public class Json2XmlConverter +{ + private String _src; // we pull substrings from the base string + private int _curPos; // position of current token (start of substring) + private int _nextPos; // position of next token (end of substring) + + + public Json2XmlConverter(String src) + { + _src = src; + } + + + /** + * Creates a new XML <code>Document</code> from the passed JSON string + * (which must contain an object definition and nothing else). The root + * element will be named "data". + */ + public Element convert() + { + Element root = DomUtil.newDocument("data"); + parse(root); + return root; + } + + +//---------------------------------------------------------------------------- +// Internals +//---------------------------------------------------------------------------- + + /** + * Top-level parser entry: expects the string to be a single object + * definition, without anything before or after the outer brace pair. + */ + private void parse(Element parent) + { + expect("{"); + parseObject(parent); + if (nextToken().length() > 0) + throw new ConversionException(commonExceptionText( + "unexpected content after closing brace")); + } + + + /** + * Called when the next token is expected to represent a value (of + * any type), to dispatch and append that value to the parent element. + * Returns the subsequent token. + */ + private String valueDispatch(String next, Element parent) + { + if (next.equals("{")) + parseObject(parent); + else if (next.equals("[")) + parseArray(parent); + else if (next.equals("\"")) + DomUtil.setText(parent, parseString()); + else + DomUtil.setText(parent, next); + + return nextToken(); + } + + + private void parseObject(Element parent) + { + String next = nextToken(); + if (atEndOfSequence(next, "}", false)) + return; + + while (true) + { + Element child = appendChild(parent, next); + expect(":"); + + next = valueDispatch(nextToken(), child); + if (atEndOfSequence(next, "}", true)) + return; + next = nextToken(); + } + } + + + private void parseArray(Element parent) + { + String next = nextToken(); + if (atEndOfSequence(next, "]", false)) + return; + + while (true) + { + Element child = DomUtil.appendChild(parent, "data"); + next = valueDispatch(next, child); + if (atEndOfSequence(next, "]", true)) + return; + next = nextToken(); + } + } + + + private String parseString() + { + try + { + for (_curPos = _nextPos ; _nextPos < _src.length() ; _nextPos++) + { + char c = _src.charAt(_nextPos); + if (c == '"') + return JsonUtil.unescape(_src.substring(_curPos, _nextPos++)); + if (c == '\\') + _nextPos++; + } + throw new ConversionException(commonExceptionText("unterminated string")); + } + catch (IllegalArgumentException ee) + { + throw new ConversionException(commonExceptionText("invalid string"), ee); + } + } + + + /** + * Reads the next token and verifies that it contains the expected value. + */ + private String expect(String expected) + { + String next = nextToken(); + if (next.equals(expected)) + return next; + + throw new ConversionException(commonExceptionText("unexpected token")); + } + + + /** + * Checks the next token (passed) to see if it represents the end of a + * sequence, a contination (","), or something unexpected. + */ + private boolean atEndOfSequence(String next, String expectedEnd, boolean throwIfSomethingElse) + { + if (next.equals(expectedEnd)) + return true; + else if (next.equals(",")) + return false; + else if (next.equals("")) + throw new ConversionException(commonExceptionText("unexpected end of input")); + else if (throwIfSomethingElse) + throw new ConversionException(commonExceptionText("unexpected token")); + return false; + } + + + /** + * Extracts the next token from the string, skipping any initial whitespace. + * Tokens consist of a set of specific single-character strings, or any other + * sequence of non-whitespace characters. + */ + private String nextToken() + { + final int len = _src.length(); + + _curPos = _nextPos; + while ((_curPos < len) && Character.isWhitespace(_src.charAt(_curPos))) + _curPos++; + + if (_curPos == len) + return ""; + + _nextPos = _curPos + 1; + if (!isDelimiter(_src.charAt(_curPos))) + { + while ((_nextPos < len) + && !Character.isWhitespace(_src.charAt(_nextPos)) + && !isDelimiter(_src.charAt(_nextPos))) + _nextPos++; + } + + return _src.substring(_curPos, _nextPos); + } + + + private boolean isDelimiter(char c) + { + switch (c) + { + case '{' : + case '}' : + case '[' : + case ']' : + case ':' : + case ',' : + case '"' : + return true; + default : + return false; + } + } + + + private String commonExceptionText(String preamble) + { + String excerpt = (_curPos + 20) > _src.length() + ? _src.substring(_curPos) + : _src.substring(_curPos, _curPos + 20) + "[...]"; + return preamble + " at position " + _curPos + ": \"" + excerpt + "\""; + } + + + /** + * A wrapper around DomUtil.appendChild() that applies some validation + * on the name, and replaces the DOM exception with ConversionException. + */ + private Element appendChild(Element parent, String name) + { + if (name.equals("")) + throw new ConversionException(commonExceptionText("unexpected end of input")); + if (isDelimiter(name.charAt(0))) + throw new ConversionException(commonExceptionText("invalid token")); + try + { + return DomUtil.appendChild(parent, name); + } + catch (Exception e) + { + throw new ConversionException(commonExceptionText("invalid element name"), e); + } + } + +} Property changes on: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/Json2XmlConverter.java ___________________________________________________________________ Added: svn:executable + * Added: branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/JsonUtil.java =================================================================== --- branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/JsonUtil.java (rev 0) +++ branches/dev-1.1/src/main/java/net/sf/practicalxml/converter/json/JsonUtil.java 2009-09-11 17:43:24 UTC (rev 126) @@ -0,0 +1,103 @@ +// Copyright 2008-2009 severally by the contributors +// +// 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 net.sf.practicalxml.converter.json; + +import net.sf.practicalxml.internal.StringUtils; + + +/** + * Static utility methods for working with JSON content. Mostly duplicates + * methods from Jakarta Commons. + */ +public class JsonUtil +{ + /** + * Unescapes a string, replacing "slash-sequences" by actual characters. + * Null is converted to empty string. + * + * @throws IllegalArgumentException on any failure + */ + public static String unescape(String src) + { + if (src == null) + return ""; + + StringBuffer buf = new StringBuffer(src.length()); + for (int ii = 0 ; ii < src.length() ; ) + { + char c = src.charAt(ii++); + if (c == '\\') + { + if (ii == src.length()) + throw new IllegalArgumentException("escape extends past end of string"); + c = src.charAt(ii++); + switch (c) + { + case '"' : + case '\\' : + case '/' : + // do nothing, simple escape + break; + case 'b' : + c = '\b'; + break; + case 'f' : + c = '\f'; + break; + case 'n' : + c = '\n'; + break; + case 'r' : + c = '\r'; + break; + case 't' : + c = '\t'; + break; + case 'U' : + case 'u' : + c = unescapeUnicode(src, ii); + ii += 4; + break; + default : + throw new IllegalArgumentException("invalid escape character: " + c); + } + } + buf.append(c); + } + return buf.toString(); + } + + +//---------------------------------------------------------------------------- +// Internals +//---------------------------------------------------------------------------- + + private static char unescapeUnicode(String src, int idx) + { + if (idx + 4 > src.length()) + throw new IllegalArgumentException("unicode escape extends past end of string"); + + int value = 0; + for (int ii = 0 ; ii < 4 ; ii++) + { + int digit = StringUtils.parseDigit(src.charAt(idx + ii), 16); + if (digit < 0) + throw new IllegalArgumentException( + "invalid unicode escape: " + src.substring(idx, idx + 4)); + value = value * 16 + digit; + } + return (char)value; + } +} Added: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java (rev 0) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java 2009-09-11 17:43:24 UTC (rev 126) @@ -0,0 +1,435 @@ +// Copyright 2008-2009 severally by the contributors +// +// 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 net.sf.practicalxml.converter.json; + +import org.w3c.dom.Element; + +import net.sf.practicalxml.DomUtil; +import net.sf.practicalxml.converter.AbstractConversionTestCase; +import net.sf.practicalxml.converter.ConversionException; + + +public class TestJson2XmlConverter +extends AbstractConversionTestCase +{ + public TestJson2XmlConverter(String testName) + { + super(testName); + } + + +//---------------------------------------------------------------------------- +// Test Cases +// ---- +// Note that in some place we call Node.getChildNodes(), in others we call +// DomUtil.getChildren. This is intentional: in the former case we want to +// ensure that the converter isn't inserting extraneous text, in the latter +// we want to ensure it isn't inserting extraneous elements (but we don't +// care how many nodes it uses to build the text content). +//---------------------------------------------------------------------------- + + public void testConvertEmpty() throws Exception + { + String src = "{}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(0, root.getChildNodes().getLength()); + } + + + public void testConvertEmptyWithWhitespace() throws Exception + { + String src = " {\t}\n"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(0, root.getChildNodes().getLength()); + } + + + public void testFailContentBeforeInitialBrace() throws Exception + { + String src = "test = {}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testFailContentAfterTerminalBrace() throws Exception + { + String src = "{};"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testFailMissingTerminalBrace() throws Exception + { + String src = " { "; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testConvertSingleElementNumeric() throws Exception + { + String src = "{foo: 123}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertEquals("123", DomUtil.getText(child)); + assertEquals(0, DomUtil.getChildren(child).size()); + } + + + public void testConvertSingleElementString() throws Exception + { + String src = "{foo: \"bar\"}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertEquals("bar", DomUtil.getText(child)); + assertEquals(0, DomUtil.getChildren(child).size()); + } + + + public void testConvertEmptyString() throws Exception + { + String src = "{foo: \"\"}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertEquals("", DomUtil.getText(child)); + assertEquals(0, DomUtil.getChildren(child).size()); + } + + + public void testConvertStringWithEmbeddedEscape() throws Exception + { + String src = "{foo: \"b\\\"\\u0061r\"}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertEquals("b\"ar", DomUtil.getText(child)); + assertEquals(0, DomUtil.getChildren(child).size()); + } + + + public void testFailUnterminatedString() throws Exception + { + String src = "{foo: \"bar}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testFailInvalidEscapeAtEndOfString() throws Exception + { + String src = "{foo: \"bar\\u123\"}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testConvertTwoElementNumeric() throws Exception + { + String src = "{foo: 123, bar: 456}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(2, root.getChildNodes().getLength()); + + Element child1 = (Element)root.getFirstChild(); + assertEquals("foo", child1.getNodeName()); + assertEquals("123", DomUtil.getText(child1)); + assertEquals(0, DomUtil.getChildren(child1).size()); + + Element child2 = (Element)child1.getNextSibling(); + assertEquals("bar", child2.getNodeName()); + assertEquals("456", DomUtil.getText(child2)); + assertEquals(0, DomUtil.getChildren(child2).size()); + } + + + public void testConvertTwoElementStringWithWhitespace() throws Exception + { + String src = "{foo : \"123\" , bar\t: \"456\" }"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(2, root.getChildNodes().getLength()); + + Element child1 = (Element)root.getFirstChild(); + assertEquals("foo", child1.getNodeName()); + assertEquals("123", DomUtil.getText(child1)); + assertEquals(0, DomUtil.getChildren(child1).size()); + + Element child2 = (Element)child1.getNextSibling(); + assertEquals("bar", child2.getNodeName()); + assertEquals("456", DomUtil.getText(child2)); + assertEquals(0, DomUtil.getChildren(child2).size()); + } + + + public void testFailObjectMissingCommaBetweenTerms() throws Exception + { + String src = "{foo: 123 bar: 456}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException e) + { + // success + } + } + + + public void testFailObjectMissingElement() throws Exception + { + String src = "{foo: 123, , bar: 456}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testConvertNested() throws Exception + { + String src = "{foo: {bar: 123, baz:456}}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(2, child.getChildNodes().getLength()); + + Element grandchild1 = (Element)child.getFirstChild(); + assertEquals("bar", grandchild1.getNodeName()); + assertEquals("123", DomUtil.getText(grandchild1)); + assertEquals(0, DomUtil.getChildren(grandchild1).size()); + + Element grandchild2 = (Element)grandchild1.getNextSibling(); + assertEquals("baz", grandchild2.getNodeName()); + assertEquals("456", DomUtil.getText(grandchild2)); + assertEquals(0, DomUtil.getChildren(grandchild2).size()); + } + + + public void testConvertNestedEmpty() throws Exception + { + String src = "{foo: {}}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(0, child.getChildNodes().getLength()); + } + + + public void testConvertEmptyArray() throws Exception + { + String src = "{foo: []}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(0, child.getChildNodes().getLength()); + } + + + public void testConvertSingleElementNumericArray() throws Exception + { + String src = "{foo: [123]}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(1, child.getChildNodes().getLength()); + + Element grandchild = (Element)child.getFirstChild(); + assertEquals("data", grandchild.getNodeName()); + assertEquals("123", DomUtil.getText(grandchild)); + assertEquals(0, DomUtil.getChildren(grandchild).size()); + } + + + public void testConvertMultiElementNumericArray() throws Exception + { + String src = "{foo: [123, 456]}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(2, child.getChildNodes().getLength()); + + Element grandchild1 = (Element)child.getFirstChild(); + assertEquals("data", grandchild1.getNodeName()); + assertEquals("123", DomUtil.getText(grandchild1)); + assertEquals(0, DomUtil.getChildren(grandchild1).size()); + + Element grandchild2 = (Element)grandchild1.getNextSibling(); + assertEquals("data", grandchild2.getNodeName()); + assertEquals("456", DomUtil.getText(grandchild2)); + assertEquals(0, DomUtil.getChildren(grandchild2).size()); + } + + + public void testConvertMultiElementMixedArray() throws Exception + { + String src = "{foo: [123, \"bar\", 456]}"; + + Element root = new Json2XmlConverter(src).convert(); + assertEquals("data", root.getNodeName()); + assertEquals(1, root.getChildNodes().getLength()); + + Element child = (Element)root.getFirstChild(); + assertEquals("foo", child.getNodeName()); + assertNull(DomUtil.getText(child)); + assertEquals(3, child.getChildNodes().getLength()); + + Element grandchild1 = (Element)child.getFirstChild(); + assertEquals("data", grandchild1.getNodeName()); + assertEquals("123", DomUtil.getText(grandchild1)); + assertEquals(0, DomUtil.getChildren(grandchild1).size()); + + Element grandchild2 = (Element)grandchild1.getNextSibling(); + assertEquals("data", grandchild2.getNodeName()); + assertEquals("bar", DomUtil.getText(grandchild2)); + assertEquals(0, DomUtil.getChildren(grandchild2).size()); + + Element grandchild3 = (Element)grandchild2.getNextSibling(); + assertEquals("data", grandchild3.getNodeName()); + assertEquals("456", DomUtil.getText(grandchild3)); + assertEquals(0, DomUtil.getChildren(grandchild3).size()); + } + + + public void testFailConvertUnterminatedArray() throws Exception + { + String src = "{foo: [123, 456"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } + + + public void testFailConvertArrayMissingElement() throws Exception + { + String src = "{foo: [123 , , 456]}"; + + try + { + new Json2XmlConverter(src).convert(); + fail(); + } + catch (ConversionException ee) + { + // success + } + } +} Property changes on: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJson2XmlConverter.java ___________________________________________________________________ Added: svn:executable + * Added: branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonUtil.java =================================================================== --- branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonUtil.java (rev 0) +++ branches/dev-1.1/src/test/java/net/sf/practicalxml/converter/json/TestJsonUtil.java 2009-09-11 17:43:24 UTC (rev 126) @@ -0,0 +1,118 @@ +// Copyright 2008-2009 severally by the contributors +// +// 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 net.sf.practicalxml.converter.json; + +import junit.framework.TestCase; + +public class TestJsonUtil extends TestCase +{ + public void testUnescapeNullAndEmpty() throws Exception + { + assertEquals("", JsonUtil.unescape(null)); + assertEquals("", JsonUtil.unescape("")); + } + + + public void testUnescapeNormalString() throws Exception + { + assertEquals("f", JsonUtil.unescape("f")); + assertEquals("fo", JsonUtil.unescape("fo")); + assertEquals("foo", JsonUtil.unescape("foo")); + } + + + public void testUnescapeSingleCharSlashes() throws Exception + { + assertEquals("\"", JsonUtil.unescape("\\\"")); + assertEquals("\\", JsonUtil.unescape("\\\\")); + assertEquals("/", JsonUtil.unescape("\\/")); + assertEquals("\b", JsonUtil.unescape("\\b")); + assertEquals("\f", JsonUtil.unescape("\\f")); + assertEquals("\n", JsonUtil.unescape("\\n")); + assertEquals("\r", JsonUtil.unescape("\\r")); + assertEquals("\t", JsonUtil.unescape("\\t")); + + // and a couple of tests to ensure that we don't overstep + assertEquals("ba\rbaz", JsonUtil.unescape("ba\\rbaz")); + assertEquals("\r\n", JsonUtil.unescape("\\r\\n")); + } + + + public void testUnescapeUnicode() throws Exception + { + assertEquals("A", JsonUtil.unescape("\\u0041")); + assertEquals("A", JsonUtil.unescape("\\U0041")); + + // verify that we correctly index subsequent chars + assertEquals("BAR", JsonUtil.unescape("B\\U0041R")); + } + + + public void testUnescapeFailEndOfString() throws Exception + { + try + { + JsonUtil.unescape("foo\\"); + fail("completed for escape at end of string"); + } + catch (IllegalArgumentException e) + { + // success + } + } + + + public void testUnescapeFailInvalidChar() throws Exception + { + try + { + JsonUtil.unescape("foo\\q"); + fail("completed for invalid escape sequence"); + } + catch (IllegalArgumentException e) + { + // success + } + } + + + public void testUnescapeFailIncompleteUnicodeEscape() throws Exception + { + try + { + JsonUtil.unescape("foo\\u12"); + fail("completed for invalid escape sequence"); + } + catch (IllegalArgumentException e) + { + // success + } + } + + + public void testUnescapeFailInvalidUnicodeEscape() throws Exception + { + try + { + JsonUtil.unescape("\\u0foo"); + fail("completed for invalid escape sequence"); + } + catch (IllegalArgumentException e) + { + // success + } + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |