http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/json/CommonParserTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/json/CommonParserTest.java b/juneau-core-test/src/test/java/org/apache/juneau/json/CommonParserTest.java new file mode 100755 index 0000000..f621811 --- /dev/null +++ b/juneau-core-test/src/test/java/org/apache/juneau/json/CommonParserTest.java @@ -0,0 +1,182 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you 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 org.apache.juneau.json; + +import static org.apache.juneau.BeanContext.*; +import static org.apache.juneau.serializer.SerializerContext.*; +import static org.junit.Assert.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.annotation.*; +import org.apache.juneau.parser.*; +import org.junit.*; + +@SuppressWarnings({"rawtypes","serial","javadoc"}) +public class CommonParserTest { + + //==================================================================================================== + // testFromSerializer + //==================================================================================================== + @Test + public void testFromSerializer() throws Exception { + ReaderParser p = JsonParser.DEFAULT.clone().setClassLoader(getClass().getClassLoader()).addToDictionary(A1.class); + + Map m = null; + m = (Map)p.parse("{a:1}", Object.class); + assertEquals(1, m.get("a")); + m = (Map)p.parse("{a:1,b:\"foo bar\"}", Object.class); + assertEquals(1, m.get("a")); + assertEquals("foo bar", m.get("b")); + m = (Map)p.parse("{a:1,b:\"foo bar\",c:false}", Object.class); + assertEquals(1, m.get("a")); + assertEquals(false, m.get("c")); + m = (Map)p.parse(" { a : 1 , b : 'foo' , c : false } ", Object.class); + assertEquals(1, m.get("a")); + assertEquals("foo", m.get("b")); + assertEquals(false, m.get("c")); + + m = (Map)p.parse("{x:\"org.apache.juneau.test.Person\",addresses:[{x:\"org.apache.juneau.test.Address\",city:\"city A\",state:\"state A\",street:\"street A\",zip:12345}]}", Object.class); + assertEquals("org.apache.juneau.test.Person", m.get("x")); + List l = (List)m.get("addresses"); + assertNotNull(l); + m = (Map)l.get(0); + assertNotNull(m); + assertEquals("org.apache.juneau.test.Address", m.get("x")); + assertEquals("city A", m.get("city")); + assertEquals("state A", m.get("state")); + assertEquals("street A", m.get("street")); + assertEquals(12345, m.get("zip")); + + ObjectList jl = (ObjectList)p.parse("[{attribute:'value'},{attribute:'value'}]", Object.class); + assertEquals("value", jl.getObjectMap(0).getString("attribute")); + assertEquals("value", jl.getObjectMap(1).getString("attribute")); + + // Verify that all the following return null. + assertNull(p.parse((CharSequence)null, Object.class)); + assertNull(p.parse("", Object.class)); + assertNull(p.parse(" ", Object.class)); + assertNull(p.parse(" \t", Object.class)); + assertNull(p.parse(" /*foo*/", Object.class)); + assertNull(p.parse(" /*foo*/ ", Object.class)); + assertNull(p.parse(" //foo ", Object.class)); + + try { + jl = (ObjectList)p.parse("[{attribute:'value'},{attribute:'value'}]", Object.class); + assertEquals("value", jl.getObjectMap(0).getString("attribute")); + assertEquals("value", jl.getObjectMap(1).getString("attribute")); + } catch (Exception e) { + fail(e.getLocalizedMessage()); + } + + A1 b = new A1(); + A2 tl = new A2(); + tl.add(new A3("name0","value0")); + tl.add(new A3("name1","value1")); + b.list = tl; + String json = new JsonSerializer().setProperty(SERIALIZER_addBeanTypeProperties, true).addToDictionary(A1.class).serialize(b); + b = (A1)p.parse(json, Object.class); + assertEquals("value1", b.list.get(1).value); + + json = JsonSerializer.DEFAULT.serialize(b); + b = p.parse(json, A1.class); + assertEquals("value1", b.list.get(1).value); + } + + @Bean(typeName="A1") + public static class A1 { + public A2 list; + } + + public static class A2 extends LinkedList<A3> { + } + + public static class A3 { + public String name, value; + public A3(){} + public A3(String name, String value) { + this.name = name; + this.value = value; + } + } + + //==================================================================================================== + // Correct handling of unknown properties. + //==================================================================================================== + @Test + public void testCorrectHandlingOfUnknownProperties() throws Exception { + ReaderParser p = new JsonParser().setProperty(BEAN_ignoreUnknownBeanProperties, true); + B b; + + String in = "{a:1,unknown:3,b:2}"; + b = p.parse(in, B.class); + assertEquals(b.a, 1); + assertEquals(b.b, 2); + + try { + p = new JsonParser(); + p.parse(in, B.class); + fail("Exception expected"); + } catch (ParseException e) {} + } + + public static class B { + public int a, b; + } + + //==================================================================================================== + // Writing to Collection properties with no setters. + //==================================================================================================== + @Test + public void testCollectionPropertiesWithNoSetters() throws Exception { + JsonParser p = JsonParser.DEFAULT; + String json = "{ints:[1,2,3],beans:[{a:1,b:2}]}"; + C t = p.parse(json, C.class); + assertEquals(t.getInts().size(), 3); + assertEquals(t.getBeans().get(0).b, 2); + } + + public static class C { + private Collection<Integer> ints = new LinkedList<Integer>(); + private List<B> beans = new LinkedList<B>(); + public Collection<Integer> getInts() { + return ints; + } + public List<B> getBeans() { + return beans; + } + } + + //==================================================================================================== + // Parser listeners. + //==================================================================================================== + @Test + public void testParserListeners() throws Exception { + final List<String> events = new LinkedList<String>(); + JsonParser p = new JsonParser().setProperty(BEAN_ignoreUnknownBeanProperties, true); + p.addListener( + new ParserListener() { + @Override /* ParserListener */ + public <T> void onUnknownProperty(String propertyName, Class<T> beanClass, T bean, int line, int col) { + events.add(propertyName + "," + line + "," + col); + } + } + ); + + String json = "{a:1,unknownProperty:\"/foo\",b:2}"; + p.parse(json, B.class); + assertEquals(1, events.size()); + assertEquals("unknownProperty,1,5", events.get(0)); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/json/CommonTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/json/CommonTest.java b/juneau-core-test/src/test/java/org/apache/juneau/json/CommonTest.java new file mode 100755 index 0000000..c443e31 --- /dev/null +++ b/juneau-core-test/src/test/java/org/apache/juneau/json/CommonTest.java @@ -0,0 +1,501 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you 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 org.apache.juneau.json; + +import static org.apache.juneau.BeanContext.*; +import static org.apache.juneau.TestUtils.*; +import static org.apache.juneau.serializer.SerializerContext.*; +import static org.junit.Assert.*; + +import java.net.*; +import java.net.URI; +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.annotation.*; +import org.apache.juneau.serializer.*; +import org.apache.juneau.testbeans.*; +import org.junit.*; + +@SuppressWarnings({"serial","javadoc"}) +public class CommonTest { + + //==================================================================================================== + // Trim nulls from beans + //==================================================================================================== + @Test + public void testTrimNullsFromBeans() throws Exception { + JsonSerializer s = new JsonSerializer.Simple(); + JsonParser p = JsonParser.DEFAULT; + A t1 = A.create(), t2; + + s.setProperty(SERIALIZER_trimNullProperties, false); + String r = s.serialize(t1); + assertEquals("{s1:null,s2:'s2'}", r); + t2 = p.parse(r, A.class); + assertEqualObjects(t1, t2); + + s.setProperty(SERIALIZER_trimNullProperties, true); + r = s.serialize(t1); + assertEquals("{s2:'s2'}", r); + t2 = p.parse(r, A.class); + assertEqualObjects(t1, t2); + } + + public static class A { + public String s1, s2; + + public static A create() { + A t = new A(); + t.s2 = "s2"; + return t; + } + } + + //==================================================================================================== + // Trim empty maps + //==================================================================================================== + @Test + public void testTrimEmptyMaps() throws Exception { + JsonSerializer s = new JsonSerializer.Simple(); + JsonParser p = JsonParser.DEFAULT; + B t1 = B.create(), t2; + String r; + + s.setProperty(SERIALIZER_trimEmptyMaps, false); + r = s.serialize(t1); + assertEquals("{f1:{},f2:{f2a:null,f2b:{s2:'s2'}}}", r); + t2 = p.parse(r, B.class); + assertEqualObjects(t1, t2); + + s.setProperty(SERIALIZER_trimEmptyMaps, true); + r = s.serialize(t1); + assertEquals("{f2:{f2a:null,f2b:{s2:'s2'}}}", r); + t2 = p.parse(r, B.class); + assertNull(t2.f1); + } + + public static class B { + public TreeMap<String,A> f1, f2; + + public static B create() { + B t = new B(); + t.f1 = new TreeMap<String,A>(); + t.f2 = new TreeMap<String,A>(){{put("f2a",null);put("f2b",A.create());}}; + return t; + } + } + + //==================================================================================================== + // Trim empty lists + //==================================================================================================== + @Test + public void testTrimEmptyLists() throws Exception { + JsonSerializer s = new JsonSerializer.Simple(); + JsonParser p = JsonParser.DEFAULT; + C t1 = C.create(), t2; + String r; + + s.setProperty(SERIALIZER_trimEmptyCollections, false); + r = s.serialize(t1); + assertEquals("{f1:[],f2:[null,{s2:'s2'}]}", r); + t2 = p.parse(r, C.class); + assertEqualObjects(t1, t2); + + s.setProperty(SERIALIZER_trimEmptyCollections, true); + r = s.serialize(t1); + assertEquals("{f2:[null,{s2:'s2'}]}", r); + t2 = p.parse(r, C.class); + assertNull(t2.f1); + } + + public static class C { + public List<A> f1, f2; + + public static C create() { + C t = new C(); + t.f1 = new LinkedList<A>(); + t.f2 = new LinkedList<A>(){{add(null);add(A.create());}}; + return t; + } + } + + //==================================================================================================== + // Trim empty arrays + //==================================================================================================== + @Test + public void testTrimEmptyArrays() throws Exception { + JsonSerializer s = new JsonSerializer.Simple(); + JsonParser p = JsonParser.DEFAULT; + D t1 = D.create(), t2; + String r; + + s.setProperty(SERIALIZER_trimEmptyCollections, false); + r = s.serialize(t1); + assertEquals("{f1:[],f2:[null,{s2:'s2'}]}", r); + t2 = p.parse(r, D.class); + assertEqualObjects(t1, t2); + + s.setProperty(SERIALIZER_trimEmptyCollections, true); + r = s.serialize(t1); + assertEquals("{f2:[null,{s2:'s2'}]}", r); + t2 = p.parse(r, D.class); + assertNull(t2.f1); + } + + public static class D { + public A[] f1, f2; + + public static D create() { + D t = new D(); + t.f1 = new A[]{}; + t.f2 = new A[]{null, A.create()}; + return t; + } + } + + //==================================================================================================== + // @BeanProperty.properties annotation. + //==================================================================================================== + @Test + public void testBeanPropertyProperies() throws Exception { + JsonSerializer s = JsonSerializer.DEFAULT_LAX; + E1 t = new E1(); + String r; + + r = s.serialize(t); + assertEquals("{x1:{f1:1},x2:{f1:1},x3:[{f1:1}],x4:[{f1:1}],x5:[{f1:1}],x6:[{f1:1}]}", r); + r = s.getSchemaSerializer().serialize(t); + assertTrue(r.indexOf("f2") == -1); + } + + public static class E1 { + @BeanProperty(properties="f1") public E2 x1 = new E2(); + @BeanProperty(properties="f1") public Map<String,Integer> x2 = new LinkedHashMap<String,Integer>() {{ + put("f1",1); put("f2",2); + }}; + @BeanProperty(properties="f1") public E2[] x3 = {new E2()}; + @BeanProperty(properties="f1") public List<E2> x4 = new LinkedList<E2>() {{ + add(new E2()); + }}; + @BeanProperty(properties="f1") public ObjectMap[] x5 = {new ObjectMap().append("f1",1).append("f2",2)}; + @BeanProperty(properties="f1") public List<ObjectMap> x6 = new LinkedList<ObjectMap>() {{ + add(new ObjectMap().append("f1",1).append("f2",2)); + }}; + } + + public static class E2 { + public int f1 = 1; + public int f2 = 2; + } + + //==================================================================================================== + // @BeanProperty.properties annotation on list of beans. + //==================================================================================================== + @Test + public void testBeanPropertyProperiesOnListOfBeans() throws Exception { + JsonSerializer s = JsonSerializer.DEFAULT_LAX; + List<F> l = new LinkedList<F>(); + F t = new F(); + t.x1.add(new F()); + l.add(t); + String json = s.serialize(l); + assertEquals("[{x1:[{x2:2}],x2:2}]", json); + } + + public static class F { + @BeanProperty(properties="x2") public List<F> x1 = new LinkedList<F>(); + public int x2 = 2; + } + + //==================================================================================================== + // Test that URLs and URIs are serialized and parsed correctly. + //==================================================================================================== + @Test + public void testURIAttr() throws Exception { + JsonSerializer s = JsonSerializer.DEFAULT_LAX; + JsonParser p = JsonParser.DEFAULT; + + G t = new G(); + t.uri = new URI("http://uri"); + t.f1 = new URI("http://f1"); + t.f2 = new URL("http://f2"); + + String json = s.serialize(t); + t = p.parse(json, G.class); + assertEquals("http://uri", t.uri.toString()); + assertEquals("http://f1", t.f1.toString()); + assertEquals("http://f2", t.f2.toString()); + } + + public static class G { + public URI uri; + public URI f1; + public URL f2; + } + + //==================================================================================================== + // Test URIs with URI_CONTEXT and URI_AUTHORITY + //==================================================================================================== + @Test + public void testUris() throws Exception { + WriterSerializer s = new JsonSerializer.Simple(); + TestURI t = new TestURI(); + String r; + String expected = ""; + + s.setProperty(SERIALIZER_relativeUriBase, null); + r = s.serialize(t); + expected = "{" + +"f0:'f0/x0'," + +"f1:'f1/x1'," + +"f2:'/f2/x2'," + +"f3:'http://www.apache.org/f3/x3'," + +"f4:'f4/x4'," + +"f5:'/f5/x5'," + +"f6:'http://www.apache.org/f6/x6'," + +"f7:'http://www.apache.org/f7/x7'," + +"f8:'f8/x8'," + +"f9:'f9/x9'," + +"fa:'http://www.apache.org/fa/xa#MY_LABEL'," + +"fb:'http://www.apache.org/fb/xb?label=MY_LABEL&foo=bar'," + +"fc:'http://www.apache.org/fc/xc?foo=bar&label=MY_LABEL'," + +"fd:'http://www.apache.org/fd/xd?label2=MY_LABEL&foo=bar'," + +"fe:'http://www.apache.org/fe/xe?foo=bar&label2=MY_LABEL'" + +"}"; + assertEquals(expected, r); + + s.setProperty(SERIALIZER_relativeUriBase, ""); // Same as null. + r = s.serialize(t); + assertEquals(expected, r); + + s.setProperty(SERIALIZER_relativeUriBase, "/cr"); + r = s.serialize(t); + expected = "{" + +"f0:'/cr/f0/x0'," + +"f1:'/cr/f1/x1'," + +"f2:'/f2/x2'," + +"f3:'http://www.apache.org/f3/x3'," + +"f4:'/cr/f4/x4'," + +"f5:'/f5/x5'," + +"f6:'http://www.apache.org/f6/x6'," + +"f7:'http://www.apache.org/f7/x7'," + +"f8:'/cr/f8/x8'," + +"f9:'/cr/f9/x9'," + +"fa:'http://www.apache.org/fa/xa#MY_LABEL'," + +"fb:'http://www.apache.org/fb/xb?label=MY_LABEL&foo=bar'," + +"fc:'http://www.apache.org/fc/xc?foo=bar&label=MY_LABEL'," + +"fd:'http://www.apache.org/fd/xd?label2=MY_LABEL&foo=bar'," + +"fe:'http://www.apache.org/fe/xe?foo=bar&label2=MY_LABEL'" + +"}"; + assertEquals(expected, r); + + s.setProperty(SERIALIZER_relativeUriBase, "/cr/"); // Same as above + r = s.serialize(t); + assertEquals(expected, r); + + s.setProperty(SERIALIZER_relativeUriBase, "/"); + r = s.serialize(t); + expected = "{" + +"f0:'/f0/x0'," + +"f1:'/f1/x1'," + +"f2:'/f2/x2'," + +"f3:'http://www.apache.org/f3/x3'," + +"f4:'/f4/x4'," + +"f5:'/f5/x5'," + +"f6:'http://www.apache.org/f6/x6'," + +"f7:'http://www.apache.org/f7/x7'," + +"f8:'/f8/x8'," + +"f9:'/f9/x9'," + +"fa:'http://www.apache.org/fa/xa#MY_LABEL'," + +"fb:'http://www.apache.org/fb/xb?label=MY_LABEL&foo=bar'," + +"fc:'http://www.apache.org/fc/xc?foo=bar&label=MY_LABEL'," + +"fd:'http://www.apache.org/fd/xd?label2=MY_LABEL&foo=bar'," + +"fe:'http://www.apache.org/fe/xe?foo=bar&label2=MY_LABEL'" + +"}"; + assertEquals(expected, r); + + s.setProperty(SERIALIZER_relativeUriBase, null); + + s.setProperty(SERIALIZER_absolutePathUriBase, "http://foo"); + r = s.serialize(t); + expected = "{" + +"f0:'f0/x0'," + +"f1:'f1/x1'," + +"f2:'http://foo/f2/x2'," + +"f3:'http://www.apache.org/f3/x3'," + +"f4:'f4/x4'," + +"f5:'http://foo/f5/x5'," + +"f6:'http://www.apache.org/f6/x6'," + +"f7:'http://www.apache.org/f7/x7'," + +"f8:'f8/x8'," + +"f9:'f9/x9'," + +"fa:'http://www.apache.org/fa/xa#MY_LABEL'," + +"fb:'http://www.apache.org/fb/xb?label=MY_LABEL&foo=bar'," + +"fc:'http://www.apache.org/fc/xc?foo=bar&label=MY_LABEL'," + +"fd:'http://www.apache.org/fd/xd?label2=MY_LABEL&foo=bar'," + +"fe:'http://www.apache.org/fe/xe?foo=bar&label2=MY_LABEL'" + +"}"; + assertEquals(expected, r); + + s.setProperty(SERIALIZER_absolutePathUriBase, "http://foo/"); + r = s.serialize(t); + assertEquals(expected, r); + + s.setProperty(SERIALIZER_absolutePathUriBase, ""); // Same as null. + r = s.serialize(t); + expected = "{" + +"f0:'f0/x0'," + +"f1:'f1/x1'," + +"f2:'/f2/x2'," + +"f3:'http://www.apache.org/f3/x3'," + +"f4:'f4/x4'," + +"f5:'/f5/x5'," + +"f6:'http://www.apache.org/f6/x6'," + +"f7:'http://www.apache.org/f7/x7'," + +"f8:'f8/x8'," + +"f9:'f9/x9'," + +"fa:'http://www.apache.org/fa/xa#MY_LABEL'," + +"fb:'http://www.apache.org/fb/xb?label=MY_LABEL&foo=bar'," + +"fc:'http://www.apache.org/fc/xc?foo=bar&label=MY_LABEL'," + +"fd:'http://www.apache.org/fd/xd?label2=MY_LABEL&foo=bar'," + +"fe:'http://www.apache.org/fe/xe?foo=bar&label2=MY_LABEL'" + +"}"; + assertEquals(expected, r); + } + + //==================================================================================================== + // Validate that you cannot update properties on locked serializer. + //==================================================================================================== + @Test + public void testLockedSerializer() throws Exception { + JsonSerializer s = new JsonSerializer().lock(); + try { + s.setProperty(JsonSerializerContext.JSON_simpleMode, true); + fail("Locked exception not thrown"); + } catch (LockedException e) {} + try { + s.setProperty(SerializerContext.SERIALIZER_addBeanTypeProperties, true); + fail("Locked exception not thrown"); + } catch (LockedException e) {} + try { + s.setProperty(BeanContext.BEAN_beanMapPutReturnsOldValue, true); + fail("Locked exception not thrown"); + } catch (LockedException e) {} + } + + //==================================================================================================== + // Recursion + //==================================================================================================== + @Test + public void testRecursion() throws Exception { + JsonSerializer s = new JsonSerializer.Simple(); + + R1 r1 = new R1(); + R2 r2 = new R2(); + R3 r3 = new R3(); + r1.r2 = r2; + r2.r3 = r3; + r3.r1 = r1; + + // No recursion detection + try { + s.serialize(r1); + fail("Exception expected!"); + } catch (Exception e) { + String msg = e.getLocalizedMessage(); + assertTrue(msg.contains("It's recommended you use the SerializerContext.SERIALIZER_detectRecursions setting to help locate the loop.")); + } + + // Recursion detection, no ignore + s.setProperty(SERIALIZER_detectRecursions, true); + try { + s.serialize(r1); + fail("Exception expected!"); + } catch (Exception e) { + String msg = e.getLocalizedMessage(); + assertTrue(msg.contains("[0]root:org.apache.juneau.json.CommonTest$R1")); + assertTrue(msg.contains("->[1]r2:org.apache.juneau.json.CommonTest$R2")); + assertTrue(msg.contains("->[2]r3:org.apache.juneau.json.CommonTest$R3")); + assertTrue(msg.contains("->[3]r1:org.apache.juneau.json.CommonTest$R1")); + } + + s.setProperty(SERIALIZER_ignoreRecursions, true); + assertEquals("{name:'foo',r2:{name:'bar',r3:{name:'baz'}}}", s.serialize(r1)); + + // Make sure this doesn't blow up. + s.getSchemaSerializer().serialize(r1); + } + + public static class R1 { + public String name = "foo"; + public R2 r2; + } + public static class R2 { + public String name = "bar"; + public R3 r3; + } + public static class R3 { + public String name = "baz"; + public R1 r1; + } + + //==================================================================================================== + // Basic bean + //==================================================================================================== + @Test + public void testBasicBean() throws Exception { + JsonSerializer s = new JsonSerializer.Simple().setProperty(SERIALIZER_trimNullProperties, false).setProperty(BEAN_sortProperties, true); + + J a = new J(); + a.setF1("J"); + a.setF2(100); + a.setF3(true); + assertEquals("C1", "{f1:'J',f2:100,f3:true}", s.serialize(a)); + } + + public static class J { + private String f1 = null; + private int f2 = -1; + private boolean f3 = false; + + public String getF1() { + return this.f1; + } + + public void setF1(String f1) { + this.f1 = f1; + } + + public int getF2() { + return this.f2; + } + + public void setF2(int f2) { + this.f2 = f2; + } + + public boolean isF3() { + return this.f3; + } + + public void setF3(boolean f3) { + this.f3 = f3; + } + + @Override /* Object */ + public String toString() { + return ("J(f1: " + this.getF1() + ", f2: " + this.getF2() + ")"); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserEdgeCasesTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserEdgeCasesTest.java b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserEdgeCasesTest.java new file mode 100644 index 0000000..a293831 --- /dev/null +++ b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserEdgeCasesTest.java @@ -0,0 +1,626 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you 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 org.apache.juneau.json; + +import static org.junit.Assert.*; + +import java.io.*; +import java.util.*; + +import org.apache.juneau.internal.*; +import org.apache.juneau.parser.*; +import org.junit.*; +import org.junit.runner.*; +import org.junit.runners.*; + +@RunWith(Parameterized.class) +@SuppressWarnings({"javadoc"}) +public class JsonParserEdgeCasesTest { + + @Parameterized.Parameters + public static Collection<Object[]> getPairs() { + return Arrays.asList(new Object[][] { + { 0, "is_structure_500_nested_arrays", StringUtils.repeat(500, "[") + StringUtils.repeat(500, "]"), null }, + { 1, "ix_object_key_lone_2nd_surrogate", "7B225C7544464141223A307D"/*{"buDFAA":0}*/, null }, + { 2, "ix_string_1st_surrogate_but_2nd_missing", "5B225C7544414441225D"/*["buDADA"]*/, null }, + { 3, "ix_string_1st_valid_surrogate_2nd_invalid", "5B225C75443838385C7531323334225D"/*["buD888bu1234"]*/, null }, + { 4, "ix_string_incomplete_surrogate_and_escape_valid", "5B225C75443830305C6E225D"/*["buD800\n"]*/, null }, + { 5, "ix_string_incomplete_surrogate_pair", "5B225C754464316561225D"/*["buDd1ea"]*/, null }, + { 6, "ix_string_incomplete_surrogates_escape_valid", "5B225C75443830305C75443830305C6E225D"/*["buD800buD800\n"]*/, null }, + { 7, "ix_string_invalid_lonely_surrogate", "5B225C7564383030225D"/*["bud800"]*/, null }, + { 8, "ix_string_invalid_surrogate", "5B225C7564383030616263225D"/*["bud800abc"]*/, null }, + { 9, "ix_string_inverted_surrogates_U+1D11E", "5B225C75446431655C7544383334225D"/*["buDd1ebuD834"]*/, null }, + { 10, "ix_string_lone_second_surrogate", "5B225C7544464141225D"/*["buDFAA"]*/, null }, + { 11, "ix_string_not_in_unicode_range", "5B22F4BFBFBF225D"/*["[fffd][fffd][fffd][fffd]"]*/, "I/O exception occurred. exception=MalformedInputException" }, + { 12, "ix_string_truncated-utf-8", "5B22E0FF225D"/*["[fffd][fffd]"]*/, "I/O exception occurred. exception=MalformedInputException" }, + { 13, "ix_string_unicode_U+10FFFE_nonchar", "5B225C75444246465C7544464645225D"/*["buDBFFbuDFFE"]*/, null }, + { 14, "ix_string_unicode_U+1FFFE_nonchar", "5B225C75443833465C7544464645225D"/*["buD83FbuDFFE"]*/, null }, + { 15, "ix_string_unicode_U+FDD0_nonchar", "5B225C7546444430225D"/*["buFDD0"]*/, null }, + { 16, "ix_string_unicode_U+FFFE_nonchar", "5B225C7546464645225D"/*["buFFFE"]*/, null }, + { 17, "ix_string_UTF-16LE_with_BOM", "FFFE5B002200E90022005D00"/*[fffd][fffd][[0]"[0][fffd][0]"[0]][0]*/, null }, + { 18, "ix_string_UTF-8_invalid_sequence", "5B22E697A5D188FA225D"/*["[65e5][448][fffd]"]*/, null }, + { 19, "ix_structure_UTF-8_BOM_empty_object", "EFBBBF7B7D"/*[feff]{}*/, "Unrecognized syntax" }, + { 20, "n_array_1_true_without_comma", "[1 true]", "Expected ',' or ']'" }, + { 21, "n_array_colon_instead_of_comma", "[\"\": 1]", "Expected ',' or ']'" }, + { 22, "n_array_comma_after_close", "[\"\"],", "Remainder after parse: ','" }, + { 23, "n_array_comma_and_number", "[,1]", "Missing value detected" }, + { 24, "n_array_double_comma", "[1,,2]", "Missing value detected" }, + { 25, "n_array_double_extra_comma", "[\"x\",,]", null }, + { 26, "n_array_extra_close", "[\"x\"]]", "Remainder after parse: ']'" }, + { 27, "n_array_extra_comma", "[\"\",]", "Unexpected trailing comma in array" }, + { 28, "n_array_incomplete", "[\"x\"", "Expected ',' or ']'" }, + { 29, "n_array_incomplete_invalid_value", "[x", "Unrecognized syntax" }, + { 30, "n_array_inner_array_no_comma", "[3[4]]", "Expected ',' or ']'" }, + { 31, "n_array_items_separated_by_semicolon", "[1:2]", "Expected ',' or ']'" }, + { 32, "n_array_just_comma", "[,]", null }, + { 33, "n_array_just_minus", "[-]", "Invalid number" }, + { 34, "n_array_missing_value", "[ , \"\"]", "Missing value detected" }, + { 35, "n_array_number_and_comma", "[1,]", "Unexpected trailing comma in array" }, + { 36, "n_array_number_and_several_commas", "[1,,]", null }, + { 37, "n_array_star_inside", "[*]", "Unrecognized syntax" }, + { 38, "n_array_unclosed", "[\"\"", "Expected ',' or ']'" }, + { 39, "n_array_unclosed_trailing_comma", "[1,", "Unexpected trailing comma in array" }, + { 40, "n_array_unclosed_with_object_inside", "[{}", "Expected ',' or ']'" }, + { 41, "n_incomplete_false", "[fals]", "Unrecognized syntax" }, + { 42, "n_incomplete_null", "[nul]", "Unrecognized syntax" }, + { 43, "n_incomplete_true", "[tru]", "Unrecognized syntax" }, + { 44, "n_number_++", "[++1234]", "Unrecognized syntax" }, + { 45, "n_number_+1", "[+1]", "Unrecognized syntax" }, + { 46, "n_number_+Inf", "[+Inf]", "Unrecognized syntax" }, + { 47, "n_number_-01", "[-01]", "Invalid JSON number" }, + { 48, "n_number_-1.0.", "[-1.0.]", "Invalid number" }, + { 49, "n_number_-2.", "[-2.]", "Invalid JSON number" }, + { 50, "n_number_-NaN", "[-NaN]", null }, + { 51, "n_number_.-1", "[.-1]", "Invalid" }, + { 52, "n_number_.2e-3", "[.2e-3]", "Invalid JSON number" }, + { 53, "n_number_0.1.2", "[0.1.2]", "Invalid number" }, + { 54, "n_number_0.3e+", "[0.3e+]", "Invalid number" }, + { 55, "n_number_0.3e", "[0.3e]", "Invalid number" }, + { 56, "n_number_0.e1", "[0.e1]", "Invalid JSON number" }, + { 57, "n_number_0_capital_E+", "[0E+]", "Invalid number" }, + { 58, "n_number_0_capital_E", "[0E]", "Invalid number" }, + { 59, "n_number_0e+", "[0e+]", "Invalid number" }, + { 60, "n_number_0e", "[0e]", "Invalid number" }, + { 61, "n_number_1.0e+", "[1.0e+]", "Invalid number" }, + { 62, "n_number_1.0e-", "[1.0e-]", "Invalid number" }, + { 63, "n_number_1.0e", "[1.0e]", "Invalid number" }, + { 64, "n_number_1_000", "[1 000.0]", "Expected ',' or ']'" }, + { 65, "n_number_1eE2", "[1eE2]", "Invalid number" }, + { 66, "n_number_2.e+3", "[2.e+3]", "Invalid JSON number" }, + { 67, "n_number_2.e-3", "[2.e-3]", "Invalid JSON number" }, + { 68, "n_number_2.e3", "[2.e3]", "Invalid JSON number" }, + { 69, "n_number_9.e+", "[9.e+]", null }, + { 70, "n_number_expression", "[1+2]", "Invalid number" }, + { 71, "n_number_hex_1_digit", "[0x1]", "Invalid JSON number" }, + { 72, "n_number_hex_2_digits", "[0x42]", "Invalid JSON number" }, + { 73, "n_number_Inf", "[Inf]", "Unrecognized syntax" }, + { 74, "n_number_infinity", "[Infinity]", "Unrecognized syntax" }, + { 75, "n_number_invalid+-", "[0e+-1]", "Invalid number" }, + { 76, "n_number_invalid-negative-real", "[-123.123foo]", "Expected ',' or ']'" }, + { 77, "n_number_minus_infinity", "[-Infinity]", null }, + { 78, "n_number_minus_sign_with_trailing_garbage", "[-foo]", "Invalid number" }, + { 79, "n_number_minus_space_1", "[- 1]", null }, + { 80, "n_number_NaN", "[NaN]", "Unrecognized syntax" }, + { 81, "n_number_neg_int_starting_with_zero", "[-012]", "Invalid JSON number" }, + { 82, "n_number_neg_real_without_int_part", "[-.123]", "Invalid JSON number" }, + { 83, "n_number_neg_with_garbage_at_end", "[-1x]", "Invalid number" }, + { 84, "n_number_real_garbage_after_e", "[1ea]", "Invalid number" }, + { 85, "n_number_real_without_fractional_part", "[1.]", "Invalid" }, + { 86, "n_number_starting_with_dot", "[.123]", "Invalid JSON number" }, + { 87, "n_number_U+FF11_fullwidth_digit_one", "[ï¼]", "Unrecognized syntax" }, + { 88, "n_number_with_alpha", "[1.2a-3]", "Invalid number" }, + { 89, "n_number_with_alpha_char", "[1.8011670033376514H-308]", "Expected ',' or ']'" }, + { 90, "n_number_with_leading_zero", "[012]", "Invalid JSON number" }, + { 91, "n_object_bad_value", "[\"x\", truth]", "Unrecognized syntax" }, + { 92, "n_object_comma_instead_of_colon", "{\"x\", null}", "Could not find ':'" }, + { 93, "n_object_double_colon", "{\"x\"::\"b\"}", "Unrecognized syntax" }, + { 94, "n_object_garbage_at_end", "{\"a\":\"a\" 123}", "Could not find '}'" }, + { 95, "n_object_key_with_single_quotes", "{key: 'value'}", "Unquoted attribute detected" }, + { 96, "n_object_missing_colon", "{\"a\" b}", "Could not find ':'" }, + { 97, "n_object_missing_key", "{:\"b\"}", "Unquoted attribute detected" }, + { 98, "n_object_missing_semicolon", "{\"a\" \"b\"}", "Could not find ':'" }, + { 99, "n_object_missing_value", "{\"a\":", "Unrecognized syntax" }, + { 100, "n_object_no-colon", "{\"a\"", "Could not find ':'" }, + { 101, "n_object_non_string_key", "{1:1}", "Unquoted attribute detected" }, + { 102, "n_object_non_string_key_but_huge_number_instead", "{9999E9999:1}", "Unquoted attribute detected" }, + { 103, "n_object_repeated_null_null", "{null:null,null:null}", "Unquoted attribute detected" }, + { 104, "n_object_several_trailing_commas", "{\"id\":0,,,,,}", null }, + { 105, "n_object_single_quote", "{'a':0}", "Invalid quote character" }, + { 106, "n_object_trailing_comma", "{\"id\":0,}", "Unexpected '}' found" }, + { 107, "n_object_trailing_comment", "{\"a\":\"b\"}/**/", "Javascript comment detected" }, + { 108, "n_object_trailing_comment_open", "{\"a\":\"b\"}/**//", null }, + { 109, "n_object_trailing_comment_slash_open", "{\"a\":\"b\"}//", "Javascript comment detected" }, + { 110, "n_object_trailing_comment_slash_open_incomplete", "{\"a\":\"b\"}/", null }, + { 111, "n_object_two_commas_in_a_row", "{\"a\":\"b\",,\"c\":\"d\"}", null }, + { 112, "n_object_unquoted_key", "{a: \"b\"}", "Unquoted attribute detected" }, + { 113, "n_object_unterminated-value", "{\"a\":\"a", null }, + { 114, "n_object_with_single_string", "{ \"foo\" : \"bar\", \"a\" }", "Could not find ':'" }, + { 115, "n_object_with_trailing_garbage", "{\"a\":\"b\"}#", "Remainder after parse" }, + { 116, "n_single_space", "", "Empty input" }, + { 117, "n_string_single_doublequote", "\"", null }, + { 118, "n_string_single_quote", "['single quote']", "Invalid quote character" }, + { 119, "n_string_single_string_no_double_quotes", "abc", "Unrecognized syntax" }, + { 120, "n_string_with_trailing_garbage", "\"\"x", "Remainder after parse" }, + { 121, "n_structure_<.>", "<.>", "Unrecognized syntax" }, + { 122, "n_structure_<null>", "[<null>]", "Unrecognized syntax" }, + { 123, "n_structure_array_trailing_garbage", "[1]x", "Remainder after parse" }, + { 124, "n_structure_array_with_extra_array_close", "[1]]", "Remainder after parse" }, + { 125, "n_structure_array_with_unclosed_string", "[\"asd]", null }, + { 126, "n_structure_capitalized_True", "[True]", "Unrecognized syntax" }, + { 127, "n_structure_close_unopened_array", "1]", "Remainder after parse" }, + { 128, "n_structure_comma_instead_of_closing_brace", "{\"x\": true,", null }, + { 129, "n_structure_double_array", "[][]", "Remainder after parse" }, + { 130, "n_structure_end_array", "]", null }, + { 131, "n_structure_lone-open-bracket", "[", "Expected one of the following characters: {,[," }, + { 132, "n_structure_no_data", "", "Empty input" }, + { 133, "n_structure_null-byte-outside-string", "[ ]", "Unrecognized syntax" }, + { 134, "n_structure_number_with_trailing_garbage", "2@", "Remainder after parse" }, + { 135, "n_structure_object_followed_by_closing_object", "{}}", "Remainder after parse" }, + { 136, "n_structure_object_unclosed_no_value", "{\"\":", "Unrecognized syntax" }, + { 137, "n_structure_object_with_comment", "{\"a\":/*comment*/\"b\"}", "Javascript comment detected" }, + { 138, "n_structure_object_with_trailing_garbage", "{\"a\": true} \"x\"", "Remainder after parse" }, + { 139, "n_structure_open_array_apostrophe", "['", null }, + { 140, "n_structure_open_array_comma", "[,", null }, + { 141, "n_structure_open_array_open_object", "[{", null }, + { 142, "n_structure_open_array_open_string", "[\"a", null }, + { 143, "n_structure_open_array_string", "[\"a\"", "Expected ',' or ']'" }, + { 144, "n_structure_open_object", "{", null }, + { 145, "n_structure_open_object_close_array", "{]", null }, + { 146, "n_structure_open_object_comma", "{,", null }, + { 147, "n_structure_open_object_open_array", "{[", null }, + { 148, "n_structure_open_object_open_string", "{\"a", null }, + { 149, "n_structure_open_object_string_with_apostrophes", "{'a'", null }, + { 150, "n_structure_single_star", "*", "Unrecognized syntax" }, + { 151, "n_structure_trailing_#", "{\"a\":\"b\"}#{}", "Remainder after parse" }, + { 152, "n_structure_unclosed_array", "[1", "Expected ',' or ']" }, + { 153, "n_structure_unclosed_array_partial_null", "[ false, nul", "Unrecognized syntax" }, + { 154, "n_structure_unclosed_array_unfinished_false", "[ true, fals", "Unrecognized syntax" }, + { 155, "n_structure_unclosed_array_unfinished_true", "[ false, tru", "Unrecognized syntax" }, + { 156, "n_structure_unclosed_object", "{\"asd\":\"asd\"", "Could not find '}'" }, + { 157, "ns_structure_100000_opening_arrays", StringUtils.repeat(100000, "["), "Depth too deep" }, + { 158, "ns_structure_open_array_object", StringUtils.repeat(50000, "[{\"\":"), "Depth too deep" }, + { 159, "nx_array_a_invalid_utf8", "5B61E55D"/*[a[fffd]]*/, null }, + { 160, "nx_array_invalid_utf8", "5BFF5D"/*[[fffd]]*/, null }, + { 161, "nx_array_newlines_unclosed", "5B2261222C0A340A2C312C"/*["a",[a]4[a],1,*/, null }, + { 162, "nx_array_spaces_vertical_tab_formfeed", "5B220B61225C665D"/*["[b]a"\f]*/, null }, + { 163, "nx_array_unclosed_with_new_lines", "5B312C0A310A2C31"/*[1,[a]1[a],1*/, null }, + { 164, "nx_multidigit_number_then_00", "31323300"/*123[0]*/, null }, + { 165, "nx_number_invalid-utf-8-in-bigger-int", "5B313233E55D"/*[123[fffd]]*/, null }, + { 166, "nx_number_invalid-utf-8-in-exponent", "5B316531E55D"/*[1e1[fffd]]*/, null }, + { 167, "nx_number_invalid-utf-8-in-int", "5B30E55D0A"/*[0[fffd]][a]*/, null }, + { 168, "nx_number_real_with_invalid_utf8_after_e", "5B3165E55D"/*[1e[fffd]]*/, null }, + { 169, "nx_object_bracket_key", "7B5B3A202278227D0A"/*{[: "x"}[a]*/, null }, + { 170, "nx_object_emoji", "7BF09F87A8F09F87AD7D"/*{[d83c][dde8][d83c][dded]}*/, null }, + { 171, "nx_object_pi_in_key_and_trailing_comma", "7B22B9223A2230222C7D"/*{"[fffd]":"0",}*/, null }, + { 172, "nx_string_1_surrogate_then_escape u", "5B225C75443830305C75225D"/*["buD800bu"]*/, "Invalid Unicode escape sequence in string" }, + { 173, "nx_string_1_surrogate_then_escape u1", "5B225C75443830305C7531225D"/*["buD800bu1"]*/, "Invalid Unicode escape sequence in string" }, + { 174, "nx_string_1_surrogate_then_escape u1x", "5B225C75443830305C753178225D"/*["buD800bu1x"]*/, "Invalid Unicode escape sequence in string" }, + { 175, "nx_string_1_surrogate_then_escape", "5B225C75443830305C225D"/*["buD800\"]*/, null }, + { 176, "nx_string_accentuated_char_no_quotes", "5BC3A95D"/*[[e9]]*/, "Unrecognized syntax" }, + { 177, "nx_string_backslash_00", "5B225C00225D"/*["\[0]"]*/, null }, + { 178, "nx_string_escape_x", "5B225C783030225D"/*["\x00"]*/, "Invalid escape sequence in string" }, + { 179, "nx_string_escaped_backslash_bad", "5B225C5C5C225D"/*["\\\"]*/, null }, + { 180, "nx_string_escaped_ctrl_char_tab", "5B225C09225D"/*["\[9]"]*/, null }, + { 181, "nx_string_escaped_emoji", "5B225CF09F8C80225D"/*["\[d83c][df00]"]*/, "Invalid escape sequence in string" }, + { 182, "nx_string_incomplete_escape", "5B225C225D"/*["\"]*/, null }, + { 183, "nx_string_incomplete_escaped_character", "5B225C75303041225D"/*["bu00A"]*/, "Invalid Unicode escape sequence in string" }, + { 184, "nx_string_incomplete_surrogate", "5B225C75443833345C754464225D"/*["buD834buDd"]*/, "Invalid Unicode escape sequence in string" }, + { 185, "nx_string_incomplete_surrogate_escape_invalid", "5B225C75443830305C75443830305C78225D"/*["buD800buD800\x"]*/, "Invalid escape sequence" }, + { 186, "nx_string_invalid-utf-8-in-escape", "5B225C75E5225D"/*["bu[fffd]"]*/, null }, + { 187, "nx_string_invalid_backslash_esc", "5B225C61225D"/*["\a"]*/, "Invalid escape sequence" }, + { 188, "nx_string_invalid_unicode_escape", "5B225C7571717171225D"/*["buqqqq"]*/, "Invalid Unicode escape sequence in string" }, + { 189, "nx_string_invalid_utf-8", "5B22FF225D"/*["[fffd]"]*/, "MalformedInputException" }, + { 190, "nx_string_invalid_utf8_after_escape", "5B225CE5225D"/*["\[fffd]"]*/, null }, + { 191, "nx_string_iso_latin_1", "5B22E9225D"/*["[fffd]"]*/, "MalformedInputException" }, + { 192, "nx_string_leading_uescaped_thinspace", "5B5C753030323022617364225D"/*[bu0020"asd"]*/, "Unrecognized syntax" }, + { 193, "nx_string_lone_utf8_continuation_byte", "5B2281225D"/*["[fffd]"]*/, "MalformedInputException" }, + { 194, "nx_string_no_quotes_with_bad_escape", "5B5C6E5D"/*[\n]*/, "Unrecognized syntax" }, + { 195, "nx_string_overlong_sequence_2_bytes", "5B22C0AF225D"/*["[fffd][fffd]"]*/, "MalformedInputException" }, + { 196, "nx_string_overlong_sequence_6_bytes", "5B22FC83BFBFBFBF225D"/*["[fffd][fffd][fffd][fffd][fffd][fffd]"]*/, "MalformedInputException" }, + { 197, "nx_string_overlong_sequence_6_bytes_null", "5B22FC8080808080225D"/*["[fffd][fffd][fffd][fffd][fffd][fffd]"]*/, "MalformedInputException" }, + { 198, "nx_string_start_escape_unclosed", "5B225C"/*["\*/, null }, + { 199, "nx_string_unescaped_crtl_char", "5B22610061225D"/*["a[0]a"]*/, null }, + { 200, "nx_string_unescaped_newline", "5B226E65770A6C696E65225D"/*["new[a]line"]*/, null }, + { 201, "nx_string_unescaped_tab", "5B2209225D"/*["[9]"]*/, null }, + { 202, "nx_string_unicode_CapitalU", "225C554136364422"/*"\UA66D"*/, "Invalid escape sequence" }, + { 203, "ix_string_UTF8_surrogate_U+D800", "5B22EDA080225D"/*["[fffd]"]*/, null }, // Succeeds on Java 8, fails on Java 6 & 7. + { 204, "nx_structure_ascii-unicode-identifier", "61C3A5"/*a[e5]*/, "Unrecognized syntax" }, + { 205, "nx_structure_incomplete_UTF8_BOM", "EFBB7B7D"/*[fffd]{}*/, null }, + { 206, "nx_structure_lone-invalid-utf-8", "E5"/*[fffd]*/, null }, + { 207, "nx_structure_open_open", "5B225C7B5B225C7B5B225C7B5B225C7B"/*["\{["\{["\{["\{*/, "Invalid escape sequence" }, + { 208, "nx_structure_single_point", "E9"/*[fffd]*/, null }, + { 209, "nx_structure_U+2060_word_joined", "5BE281A05D"/*[[2060]]*/, "Unrecognized syntax" }, + { 210, "nx_structure_uescaped_LF_before_string", "5B5C753030304122225D"/*[bu000A""]*/, "Unrecognized syntax" }, + { 211, "nx_structure_unicode-identifier", "C3A5"/*[e5]*/, "Unrecognized syntax" }, + { 212, "nx_structure_UTF8_BOM_no_data", "EFBBBF"/*[feff]*/, "Unrecognized syntax" }, + { 213, "nx_structure_whitespace_formfeed", "5B0C5D"/*[[c]]*/, "Unrecognized syntax" }, + { 214, "nx_structure_whitespace_U+2060_word_joiner", "5BE281A05D"/*[[2060]]*/, "Unrecognized syntax" }, + { 215, "y_array_arraysWithSpaces", "[[] ]", null }, + { 216, "y_array_empty-string", "[\"\"]", null }, + { 217, "y_array_empty", "[]", null }, + { 218, "y_array_ending_with_newline", "[\"a\"]", null }, + { 219, "y_array_false", "[false]", null }, + { 220, "y_array_heterogeneous", "[null, 1, \"1\", {}]", null }, + { 221, "y_array_null", "[null]", null }, + { 222, "y_array_with_leading_space", "[1]", null }, + { 223, "y_array_with_several_null", "[1,null,null,null,2]", null }, + { 224, "y_array_with_trailing_space", "[2]", null }, + { 225, "y_number", "[123e65]", null }, + { 226, "y_number_0e+1", "[0e+1]", null }, + { 227, "y_number_0e1", "[0e1]", null }, + { 228, "y_number_after_space", "[ 4]", null }, + { 229, "y_number_double_close_to_zero", "[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]", null }, + { 230, "y_number_double_huge_neg_exp", "[123.456e-789]", null }, + { 231, "y_number_huge_exp", "[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]", null }, + { 232, "y_number_int_with_exp", "[20e1]", null }, + { 233, "y_number_minus_zero", "[-0]", null }, + { 234, "y_number_neg_int_huge_exp", "[-1e+9999]", null }, + { 235, "y_number_negative_int", "[-123]", null }, + { 236, "y_number_negative_one", "[-1]", null }, + { 237, "y_number_negative_zero", "[-0]", null }, + { 238, "y_number_pos_double_huge_exp", "[1.5e+9999]", null }, + { 239, "y_number_real_capital_e", "[1E22]", null }, + { 240, "y_number_real_capital_e_neg_exp", "[1E-2]", null }, + { 241, "y_number_real_capital_e_pos_exp", "[1E+2]", null }, + { 242, "y_number_real_exponent", "[123e45]", null }, + { 243, "y_number_real_fraction_exponent", "[123.456e78]", null }, + { 244, "y_number_real_neg_exp", "[1e-2]", null }, + { 245, "y_number_real_neg_overflow", "[-123123e100000]", null }, + { 246, "y_number_real_pos_exponent", "[1e+2]", null }, + { 247, "y_number_real_pos_overflow", "[123123e100000]", null }, + { 248, "y_number_real_underflow", "[123e-10000000]", null }, + { 249, "y_number_simple_int", "[123]", null }, + { 250, "y_number_simple_real", "[123.456789]", null }, + { 251, "y_number_too_big_neg_int", "[-123123123123123123123123123123]", null }, + { 252, "y_number_too_big_pos_int", "[100000000000000000000]", null }, + { 253, "y_number_very_big_negative_int", "[-237462374673276894279832749832423479823246327846]", null }, + { 254, "y_object", "{\"asd\":\"sdf\", \"dfg\":\"fgh\"}", null }, + { 255, "y_object_basic", "{\"asd\":\"sdf\"}", null }, + { 256, "y_object_duplicated_key", "{\"a\":\"b\",\"a\":\"c\"}", null }, + { 257, "y_object_duplicated_key_and_value", "{\"a\":\"b\",\"a\":\"b\"}", null }, + { 258, "y_object_empty", "{}", null }, + { 259, "y_object_empty_key", "{\"\":0}", null }, + { 260, "y_object_extreme_numbers", "{ \"min\": -1.0e+28, \"max\": 1.0e+28 }", null }, + { 261, "y_object_long_strings", "{\"x\":[{\"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}], \"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}", null }, + { 262, "y_object_simple", "{\"a\":[]}", null }, + { 263, "y_string_comments", "[\"a/*b*/c/*d//e\"]", null }, + { 264, "y_string_in_array", "[\"asd\"]", null }, + { 265, "y_string_in_array_with_leading_space", "[ \"asd\"]", null }, + { 266, "y_string_simple_ascii", "[\"asd \"]", null }, + { 267, "y_string_space", "\" \"", null }, + { 268, "y_structure_lonely_false", "false", null }, + { 269, "y_structure_lonely_int", "42", null }, + { 270, "y_structure_lonely_negative_real", "-0.1", null }, + { 271, "y_structure_lonely_null", "null", null }, + { 272, "y_structure_lonely_string", "\"asd\"", null }, + { 273, "y_structure_lonely_true", "true", null }, + { 274, "y_structure_string_empty", "\"\"", null }, + { 275, "y_structure_true_in_array", "[true]", null }, + { 276, "y_structure_whitespace_array", "[]", null }, + { 277, "yx_array_with_1_and_newline", "5B310A5D"/*[1[a]]*/, null }, + { 278, "yx_object_escaped_null_in_key", "7B22666F6F5C7530303030626172223A2034327D"/*{"foobu0000bar": 42}*/, null }, + { 279, "yx_object_string_unicode", "7B227469746C65223A225C75303431665C75303433655C75303433625C75303434325C75303433655C75303434305C7530343330205C75303431375C75303433355C75303433635C75303433625C75303433355C75303433615C75303433655C75303433665C753034333022207D"/*{"title":"bu041fbu043ebu043bbu0442bu043ebu0440bu0430 bu0417bu0435bu043cbu043bbu0435bu043abu043ebu043fbu0430" }*/, null }, + { 280, "yx_object_with_newlines", "7B0A2261223A202262220A7D"/*{[a]"a": "b"[a]}*/, null }, + { 281, "yx_string_1_2_3_bytes_UTF-8_sequences", "5B225C75303036305C75303132615C7531324142225D"/*["bu0060bu012abu12AB"]*/, null }, + { 282, "yx_string_accepted_surrogate_pair", "5B225C75443830315C7564633337225D"/*["buD801budc37"]*/, null }, + { 283, "yx_string_accepted_surrogate_pairs", "5B225C75643833645C75646533395C75643833645C7564633864225D"/*["bud83dbude39bud83dbudc8d"]*/, null }, + { 284, "yx_string_allowed_escapes", "5B225C225C5C5C2F5C625C665C6E5C725C74225D"/*["\"\\\/\b\f\n\r\t"]*/, null }, + { 285, "yx_string_backslash_and_u_escaped_zero", "5B225C5C7530303030225D"/*["\bu0000"]*/, null }, + { 286, "yx_string_backslash_doublequotes", "5B225C22225D"/*["\""]*/, null }, + { 287, "yx_string_double_escape_a", "5B225C5C61225D"/*["\\a"]*/, null }, + { 288, "yx_string_double_escape_n", "5B225C5C6E225D"/*["\\n"]*/, null }, + { 289, "yx_string_escaped_control_character", "5B225C7530303132225D"/*["bu0012"]*/, null }, + { 290, "yx_string_escaped_noncharacter", "5B225C7546464646225D"/*["buFFFF"]*/, null }, + { 291, "yx_string_last_surrogates_1_and_2", "5B225C75444246465C7544464646225D"/*["buDBFFbuDFFF"]*/, null }, + { 292, "yx_string_nbsp_uescaped", "5B226E65775C75303041306C696E65225D"/*["newbu00A0line"]*/, null }, + { 293, "yx_string_nonCharacterInUTF-8_U+10FFFF", "5B22F48FBFBF225D"/*["[dbff][dfff]"]*/, null }, + { 294, "yx_string_nonCharacterInUTF-8_U+1FFFF", "5B22F09BBFBF225D"/*["[d82f][dfff]"]*/, null }, + { 295, "yx_string_nonCharacterInUTF-8_U+FFFF", "5B22EFBFBF225D"/*["[ffff]"]*/, null }, + { 296, "yx_string_null_escape", "5B225C7530303030225D"/*["bu0000"]*/, null }, + { 297, "yx_string_one-byte-utf-8", "5B225C7530303263225D"/*["bu002c"]*/, null }, + { 298, "yx_string_pi", "5B22CF80225D"/*["[3c0]"]*/, null }, + { 299, "yx_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF", "5B225C75443833345C7544643165225D"/*["buD834buDd1e"]*/, null }, + { 300, "yx_string_three-byte-utf-8", "5B225C7530383231225D"/*["bu0821"]*/, null }, + { 301, "yx_string_two-byte-utf-8", "5B225C7530313233225D"/*["bu0123"]*/, null }, + { 302, "yx_string_u+2028_line_sep", "5B22E280A8225D"/*["[2028]"]*/, null }, + { 303, "yx_string_u+2029_par_sep", "5B22E280A9225D"/*["[2029]"]*/, null }, + { 304, "yx_string_uEscape", "5B225C75303036315C75333061665C75333045415C7533306239225D"/*["bu0061bu30afbu30EAbu30b9"]*/, null }, + { 305, "yx_string_uescaped_newline", "5B226E65775C75303030416C696E65225D"/*["newbu000Aline"]*/, null }, + { 306, "yx_string_unescaped_char_delete", "5B227F225D"/*["[7f]"]*/, null }, + { 307, "yx_string_unicode", "5B225C7541363644225D"/*["buA66D"]*/, null }, + { 308, "yx_string_unicode_2", "5B22E28D82E388B4E28D82225D"/*["[2342][3234][2342]"]*/, null }, + { 309, "yx_string_unicode_escaped_double_quote", "5B225C7530303232225D"/*["bu0022"]*/, null }, + { 310, "yx_string_unicode_U+200B_ZERO_WIDTH_SPACE", "5B225C7532303042225D"/*["bu200B"]*/, null }, + { 311, "yx_string_unicode_U+2064_invisible_plus", "5B225C7532303634225D"/*["bu2064"]*/, null }, + { 312, "yx_string_unicodeEscapedBackslash", "5B225C7530303543225D"/*["bu005C"]*/, null }, + { 313, "yx_string_utf16BE_no_BOM", "005B002200E90022005D"/*[0][[0]"[0][fffd][0]"[0]]*/, null }, + { 314, "yx_string_utf16LE_no_BOM", "5B002200E90022005D00"/*[[0]"[0][fffd][0]"[0]][0]*/, null }, + { 315, "yx_string_utf8", "5B22E282ACF09D849E225D"/*["[20ac][d834][dd1e]"]*/, null }, + { 316, "yx_string_with_del_character", "5B22617F61225D"/*["a[7f]a"]*/, null }, + { 317, "yx_structure_trailing_newline", "5B2261225D0A"/*["a"][a]*/, null }, + }); + } + + private final String name, errorText, jsonReadable; + private final Object json; + private final char expected; + public boolean debug = false; + + public JsonParserEdgeCasesTest(Integer testNum, String name, String json, String errorText) throws Exception { + this.name = name; + this.json = name.charAt(1) == 'x' ? StringUtils.fromHex(json) : json; + this.jsonReadable = name.charAt(1) == 'x' ? StringUtils.fromHexToUTF8(json) : json; + this.expected = name.charAt(0); + this.errorText = errorText; + } + + @Test + public void testStrict() throws Exception { + Parser p = JsonParser.DEFAULT_STRICT; + if (name.contains("utf16LE")) + p = p.clone().setProperty(ParserContext.PARSER_inputStreamCharset, "UTF-16LE"); + else if (name.contains("utf16BE")) + p = p.clone().setProperty(ParserContext.PARSER_inputStreamCharset, "UTF-16BE"); + + // 'y' tests should always succeed. + if (expected == 'y') { + p.parse(json, Object.class); + + // 'n' tests should always fail. + } else if (expected == 'n') { + try { + p.parse(json, Object.class); + fail("ParseException expected. Test="+name+", Input=" + jsonReadable); + } catch (ParseException e) { + if (errorText != null) + assertTrue("Got ParseException but didn't contain expected text '"+errorText+"'. Test="+name+", Input=" + jsonReadable + ", Message=" + e.getRootCause().getMessage(), e.getRootCause().getMessage().contains(errorText)); + } catch (AssertionError e) { + throw e; + } catch (Throwable t) { + fail("Expected ParseException. Test="+name+", Input=" + jsonReadable + ", Exception=" + t.getClass().getName() + "," +t.getLocalizedMessage()); + } + + // 'i' tests may or may not fail, but should through a ParseException and not kill the JVM. + } else if (expected == 'i') { + try { + p.parse(json, Object.class); + } catch (ParseException e) { + if (errorText != null) + assertTrue("Got ParseException but didn't contain expected text '"+errorText+"'. Test="+name+", Input=" + jsonReadable + ", Message=" + e.getRootCause().getMessage(), e.getRootCause().getMessage().contains(errorText)); + } catch (Throwable t) { + fail("Expected ParseException. Test="+name+", Input=" + jsonReadable + ", Exception=" + t.getClass().getName() + "," +t.getLocalizedMessage()); + } + } + } + + @Test + public void testLax() throws Exception { + Parser p = JsonParser.DEFAULT; + if (name.contains("utf16LE")) + p = p.clone().setProperty(ParserContext.PARSER_inputStreamCharset, "UTF-16LE"); + else if (name.contains("utf16BE")) + p = p.clone().setProperty(ParserContext.PARSER_inputStreamCharset, "UTF-16BE"); + + // 'y' tests should always succeed. + if (expected == 'y') { + p.parse(json, Object.class); + + // 'n' tests may or may not fail for lax parser. + } else if (expected == 'n') { + try { + p.parse(json, Object.class); + //fail("ParseException expected. Test="+name+", Input=" + json); + } catch (ParseException e) { + if (errorText != null) + assertTrue("Got ParseException but didn't contain expected text '"+errorText+"'. Test="+name+", Input=" + jsonReadable + ", Message=" + e.getRootCause().getMessage(), e.getRootCause().getMessage().contains(errorText)); + } catch (AssertionError e) { + throw e; + } catch (Throwable t) { + fail("Expected ParseException. Test="+name+", Input=" + jsonReadable + ", Exception=" + t.getClass().getName() + "," +t.getLocalizedMessage()); + } + + // 'i' tests may or may not fail, but should through a ParseException and not kill the JVM. + } else if (expected == 'i') { + try { + p.parse(json, Object.class); + } catch (ParseException e) { + if (errorText != null) + assertTrue("Got ParseException but didn't contain expected text '"+errorText+"'. Test="+name+", Input=" + jsonReadable + ", Message=" + e.getRootCause().getMessage(), e.getRootCause().getMessage().contains(errorText)); + } catch (Throwable t) { + fail("Expected ParseException. Test="+name+", Input=" + jsonReadable + ", Exception=" + t.getClass().getName() + "," +t.getLocalizedMessage()); + } + } + } + + + public static void main(String[] generateParams) throws Exception { + File f = new File("src/test/resources/org/apache/juneau/json/jsonTestSuite"); + int i = 0; + String pattern = "\n\t\t'{' {0}, \"{1}\", {2}, {3} '}',"; + StringBuilder sb = new StringBuilder(); + for (File fc : f.listFiles()) { + String n = fc.getName(); + if (n.endsWith(".json")) { + n = n.replaceAll("\\.json", ""); + String contents = specials.get(n); + if (contents == null) { + if (n.charAt(1) == 'x') + contents = '"' + StringUtils.toHex(IOUtils.readBytes(fc)) + '"' + "/*" + StringUtils.decodeHex(IOUtils.read(fc)).replaceAll("\\\\u", "bu") + "*/"; + else + contents = '"' + IOUtils.read(fc).replaceAll("\"", "\\\\\"").trim() + '"'; + } + String errorText = errors.get(n); + if (errorText != null) + errorText = '"' + errorText + '"'; + sb.append(java.text.MessageFormat.format(pattern, i++, fc.getName().replace(".json", ""), contents, errorText)); + } + } + System.err.println(sb); + } + + public static final Map<String,String> specials = new HashMap<String,String>(); + static { + specials.put("is_structure_500_nested_arrays", "StringUtils.repeat(500, \"[\") + StringUtils.repeat(500, \"]\")"); + specials.put("ns_structure_100000_opening_arrays", "StringUtils.repeat(100000, \"[\")"); + specials.put("ns_structure_open_array_object", "StringUtils.repeat(50000, \"[{\\\"\\\":\")"); + } + + public static final Map<String,String> errors = new HashMap<String,String>(); + static { + errors.put(/*11*/ "ix_string_not_in_unicode_range", "I/O exception occurred. exception=MalformedInputException"); + errors.put(/*12*/ "ix_string_truncated-utf-8", "I/O exception occurred. exception=MalformedInputException"); + errors.put(/*19*/ "ix_structure_UTF-8_BOM_empty_object", "Unrecognized syntax"); + errors.put(/*20*/ "n_array_1_true_without_comma", "Expected ',' or ']'"); + errors.put(/*21*/ "n_array_colon_instead_of_comma", "Expected ',' or ']'"); + errors.put(/*22*/ "n_array_comma_after_close", "Remainder after parse: ','"); + errors.put(/*23*/ "n_array_comma_and_number", "Missing value detected"); + errors.put(/*24*/ "n_array_double_comma", "Missing value detected"); + errors.put(/*26*/ "n_array_extra_close", "Remainder after parse: ']'"); + errors.put(/*27*/ "n_array_extra_comma", "Unexpected trailing comma in array"); + errors.put(/*28*/ "n_array_incomplete", "Expected ',' or ']'"); + errors.put(/*29*/ "n_array_incomplete_invalid_value", "Unrecognized syntax"); + errors.put(/*30*/ "n_array_inner_array_no_comma", "Expected ',' or ']'"); + errors.put(/*31*/ "n_array_items_separated_by_semicolon", "Expected ',' or ']'"); + errors.put(/*33*/ "n_array_just_minus", "Invalid number"); + errors.put(/*34*/ "n_array_missing_value", "Missing value detected"); + errors.put(/*35*/ "n_array_number_and_comma", "Unexpected trailing comma in array"); + errors.put(/*37*/ "n_array_star_inside", "Unrecognized syntax"); + errors.put(/*38*/ "n_array_unclosed", "Expected ',' or ']'"); + errors.put(/*39*/ "n_array_unclosed_trailing_comma", "Unexpected trailing comma in array"); + errors.put(/*40*/ "n_array_unclosed_with_object_inside", "Expected ',' or ']'"); + errors.put(/*41*/ "n_incomplete_false", "Unrecognized syntax"); + errors.put(/*42*/ "n_incomplete_null", "Unrecognized syntax"); + errors.put(/*43*/ "n_incomplete_true", "Unrecognized syntax"); + errors.put(/*44*/ "n_number_++", "Unrecognized syntax"); + errors.put(/*45*/ "n_number_+1", "Unrecognized syntax"); + errors.put(/*46*/ "n_number_+Inf", "Unrecognized syntax"); + errors.put(/*47*/ "n_number_-01", "Invalid JSON number"); + errors.put(/*48*/ "n_number_-1.0.", "Invalid number"); + errors.put(/*49*/ "n_number_-2.", "Invalid JSON number"); + errors.put(/*51*/ "n_number_.-1", "Invalid"); + errors.put(/*52*/ "n_number_.2e-3", "Invalid JSON number"); + errors.put(/*53*/ "n_number_0.1.2", "Invalid number"); + errors.put(/*54*/ "n_number_0.3e+", "Invalid number"); + errors.put(/*55*/ "n_number_0.3e", "Invalid number"); + errors.put(/*56*/ "n_number_0.e1", "Invalid JSON number"); + errors.put(/*57*/ "n_number_0_capital_E+", "Invalid number"); + errors.put(/*58*/ "n_number_0_capital_E", "Invalid number"); + errors.put(/*59*/ "n_number_0e+", "Invalid number"); + errors.put(/*60*/ "n_number_0e", "Invalid number"); + errors.put(/*61*/ "n_number_1.0e+", "Invalid number"); + errors.put(/*62*/ "n_number_1.0e-", "Invalid number"); + errors.put(/*63*/ "n_number_1.0e", "Invalid number"); + errors.put(/*64*/ "n_number_1_000", "Expected ',' or ']'"); + errors.put(/*65*/ "n_number_1eE2", "Invalid number"); + errors.put(/*66*/ "n_number_2.e+3", "Invalid JSON number"); + errors.put(/*67*/ "n_number_2.e-3", "Invalid JSON number"); + errors.put(/*68*/ "n_number_2.e3", "Invalid JSON number"); + errors.put(/*70*/ "n_number_expression", "Invalid number"); + errors.put(/*71*/ "n_number_hex_1_digit", "Invalid JSON number"); + errors.put(/*72*/ "n_number_hex_2_digits", "Invalid JSON number"); + errors.put(/*73*/ "n_number_Inf", "Unrecognized syntax"); + errors.put(/*74*/ "n_number_infinity", "Unrecognized syntax"); + errors.put(/*75*/ "n_number_invalid+-", "Invalid number"); + errors.put(/*76*/ "n_number_invalid-negative-real", "Expected ',' or ']'"); + errors.put(/*78*/ "n_number_minus_sign_with_trailing_garbage", "Invalid number"); + errors.put(/*80*/ "n_number_NaN", "Unrecognized syntax"); + errors.put(/*81*/ "n_number_neg_int_starting_with_zero", "Invalid JSON number"); + errors.put(/*82*/ "n_number_neg_real_without_int_part", "Invalid JSON number"); + errors.put(/*83*/ "n_number_neg_with_garbage_at_end", "Invalid number"); + errors.put(/*84*/ "n_number_real_garbage_after_e", "Invalid number"); + errors.put(/*85*/ "n_number_real_without_fractional_part", "Invalid"); + errors.put(/*86*/ "n_number_starting_with_dot", "Invalid JSON number"); + errors.put(/*87*/ "n_number_U+FF11_fullwidth_digit_one", "Unrecognized syntax"); + errors.put(/*88*/ "n_number_with_alpha", "Invalid number"); + errors.put(/*89*/ "n_number_with_alpha_char", "Expected ',' or ']'"); + errors.put(/*90*/ "n_number_with_leading_zero", "Invalid JSON number"); + errors.put(/*91*/ "n_object_bad_value", "Unrecognized syntax"); + errors.put(/*92*/ "n_object_comma_instead_of_colon", "Could not find ':'"); + errors.put(/*93*/ "n_object_double_colon", "Unrecognized syntax"); + errors.put(/*94*/ "n_object_garbage_at_end", "Could not find '}'"); + errors.put(/*95*/ "n_object_key_with_single_quotes", "Unquoted attribute detected"); + errors.put(/*96*/ "n_object_missing_colon", "Could not find ':'"); + errors.put(/*97*/ "n_object_missing_key", "Unquoted attribute detected"); + errors.put(/*98*/ "n_object_missing_semicolon", "Could not find ':'"); + errors.put(/*99*/ "n_object_missing_value", "Unrecognized syntax"); + errors.put(/*100*/ "n_object_no-colon", "Could not find ':'"); + errors.put(/*101*/ "n_object_non_string_key", "Unquoted attribute detected"); + errors.put(/*102*/ "n_object_non_string_key_but_huge_number_instead", "Unquoted attribute detected"); + errors.put(/*103*/ "n_object_repeated_null_null", "Unquoted attribute detected"); + errors.put(/*105*/ "n_object_single_quote", "Invalid quote character"); + errors.put(/*106*/ "n_object_trailing_comma", "Unexpected '}' found"); + errors.put(/*107*/ "n_object_trailing_comment", "Javascript comment detected"); + errors.put(/*109*/ "n_object_trailing_comment_slash_open", "Javascript comment detected"); + errors.put(/*112*/ "n_object_unquoted_key", "Unquoted attribute detected"); + errors.put(/*114*/ "n_object_with_single_string", "Could not find ':'"); + errors.put(/*115*/ "n_object_with_trailing_garbage", "Remainder after parse"); + errors.put(/*116*/ "n_single_space", "Empty input"); + errors.put(/*118*/ "n_string_single_quote", "Invalid quote character"); + errors.put(/*119*/ "n_string_single_string_no_double_quotes", "Unrecognized syntax"); + errors.put(/*120*/ "n_string_with_trailing_garbage", "Remainder after parse"); + errors.put(/*121*/ "n_structure_<.>", "Unrecognized syntax"); + errors.put(/*122*/ "n_structure_<null>", "Unrecognized syntax"); + errors.put(/*123*/ "n_structure_array_trailing_garbage", "Remainder after parse"); + errors.put(/*124*/ "n_structure_array_with_extra_array_close", "Remainder after parse"); + errors.put(/*126*/ "n_structure_capitalized_True", "Unrecognized syntax"); + errors.put(/*127*/ "n_structure_close_unopened_array", "Remainder after parse"); + errors.put(/*129*/ "n_structure_double_array", "Remainder after parse"); + errors.put(/*131*/ "n_structure_lone-open-bracket", "Expected one of the following characters: {,[,"); + errors.put(/*132*/ "n_structure_no_data", "Empty input"); + errors.put(/*133*/ "n_structure_null-byte-outside-string", "Unrecognized syntax"); + errors.put(/*134*/ "n_structure_number_with_trailing_garbage", "Remainder after parse"); + errors.put(/*135*/ "n_structure_object_followed_by_closing_object", "Remainder after parse"); + errors.put(/*136*/ "n_structure_object_unclosed_no_value", "Unrecognized syntax"); + errors.put(/*137*/ "n_structure_object_with_comment", "Javascript comment detected"); + errors.put(/*138*/ "n_structure_object_with_trailing_garbage", "Remainder after parse"); + errors.put(/*143*/ "n_structure_open_array_string", "Expected ',' or ']'"); + errors.put(/*150*/ "n_structure_single_star", "Unrecognized syntax"); + errors.put(/*151*/ "n_structure_trailing_#", "Remainder after parse"); + errors.put(/*152*/ "n_structure_unclosed_array", "Expected ',' or ']"); + errors.put(/*153*/ "n_structure_unclosed_array_partial_null", "Unrecognized syntax"); + errors.put(/*154*/ "n_structure_unclosed_array_unfinished_false", "Unrecognized syntax"); + errors.put(/*155*/ "n_structure_unclosed_array_unfinished_true", "Unrecognized syntax"); + errors.put(/*156*/ "n_structure_unclosed_object", "Could not find '}'"); + errors.put(/*157*/ "ns_structure_100000_opening_arrays", "Depth too deep"); + errors.put(/*158*/ "ns_structure_open_array_object", "Depth too deep"); + errors.put(/*172*/ "nx_string_1_surrogate_then_escape u", "Invalid Unicode escape sequence in string"); + errors.put(/*173*/ "nx_string_1_surrogate_then_escape u1", "Invalid Unicode escape sequence in string"); + errors.put(/*174*/ "nx_string_1_surrogate_then_escape u1x", "Invalid Unicode escape sequence in string"); + errors.put(/*176*/ "nx_string_accentuated_char_no_quotes", "Unrecognized syntax"); + errors.put(/*178*/ "nx_string_escape_x", "Invalid escape sequence in string"); + errors.put(/*181*/ "nx_string_escaped_emoji", "Invalid escape sequence in string"); + errors.put(/*183*/ "nx_string_incomplete_escaped_character", "Invalid Unicode escape sequence in string"); + errors.put(/*184*/ "nx_string_incomplete_surrogate", "Invalid Unicode escape sequence in string"); + errors.put(/*185*/ "nx_string_incomplete_surrogate_escape_invalid", "Invalid escape sequence"); + errors.put(/*187*/ "nx_string_invalid_backslash_esc", "Invalid escape sequence"); + errors.put(/*188*/ "nx_string_invalid_unicode_escape", "Invalid Unicode escape sequence in string"); + errors.put(/*189*/ "nx_string_invalid_utf-8", "MalformedInputException"); + errors.put(/*191*/ "nx_string_iso_latin_1", "MalformedInputException"); + errors.put(/*192*/ "nx_string_leading_uescaped_thinspace", "Unrecognized syntax"); + errors.put(/*193*/ "nx_string_lone_utf8_continuation_byte", "MalformedInputException"); + errors.put(/*194*/ "nx_string_no_quotes_with_bad_escape", "Unrecognized syntax"); + errors.put(/*195*/ "nx_string_overlong_sequence_2_bytes", "MalformedInputException"); + errors.put(/*196*/ "nx_string_overlong_sequence_6_bytes", "MalformedInputException"); + errors.put(/*197*/ "nx_string_overlong_sequence_6_bytes_null", "MalformedInputException"); + errors.put(/*202*/ "nx_string_unicode_CapitalU", "Invalid escape sequence"); + errors.put(/*203*/ "nx_string_UTF8_surrogate_U+D800", "MalformedInputException"); + errors.put(/*204*/ "nx_structure_ascii-unicode-identifier", "Unrecognized syntax"); + errors.put(/*207*/ "nx_structure_open_open", "Invalid escape sequence"); + errors.put(/*209*/ "nx_structure_U+2060_word_joined", "Unrecognized syntax"); + errors.put(/*210*/ "nx_structure_uescaped_LF_before_string", "Unrecognized syntax"); + errors.put(/*211*/ "nx_structure_unicode-identifier", "Unrecognized syntax"); + errors.put(/*212*/ "nx_structure_UTF8_BOM_no_data", "Unrecognized syntax"); + errors.put(/*213*/ "nx_structure_whitespace_formfeed", "Unrecognized syntax"); + errors.put(/*214*/ "nx_structure_whitespace_U+2060_word_joiner", "Unrecognized syntax"); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java new file mode 100755 index 0000000..fc61db3 --- /dev/null +++ b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonParserTest.java @@ -0,0 +1,325 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you 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 org.apache.juneau.json; + +import static org.junit.Assert.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.serializer.*; +import org.junit.*; + +@SuppressWarnings({"javadoc"}) +public class JsonParserTest { + + private static final JsonParser p = JsonParser.DEFAULT; + private static final JsonParser sp = JsonParser.DEFAULT_STRICT; + + + //==================================================================================================== + // Test invalid input + //==================================================================================================== + @Test + public void testInvalidJson() { + try { + p.parse("{\na:1,\nb:xxx\n}", Object.class); + fail("Exception expected."); + } catch (ParseException e) {} + } + + @Test + public void testNonExistentAttribute() throws Exception { + String json = "{foo:,bar:}"; + ObjectMap m = p.parse(json, ObjectMap.class); + assertEquals("{foo:null,bar:null}", m.toString()); + } + + @Test + public void testNonStringAsString() throws Exception { + String json = "123"; + String s; + + // Strict mode does not allow unquoted values. + try { + sp.parse(json, String.class); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Did not find quote character")); + } + + s = p.parse(json, String.class); + assertEquals("123", s); + + json = " 123 "; + // Strict mode does not allow unquoted values. + try { + sp.parse(json, String.class); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Did not find quote character")); + } + + s = p.parse(json, String.class); + assertEquals("123", s); + + json = "{\"fa\":123}"; + try { + sp.parse(json, A.class); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Did not find quote character")); + } + + A a = p.parse(json, A.class); + assertEquals("123", a.fa); + + json = " { \"fa\" : 123 } "; + try { + sp.parse(json, A.class); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Did not find quote character")); + } + + a = p.parse(json, A.class); + assertEquals("123", a.fa); + + json = "'123'"; + try { + sp.parse(json, String.class); + fail("Exception expected"); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Invalid quote character")); + } + } + + public static class A { + public String fa; + } + + @Test + public void testStrictMode() throws Exception { + JsonParser p = sp; + + // Missing attribute values. + String json = "{\"foo\":,\"bar\":}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'Object',line:1,column:7}. Missing value detected.", e.getRootCause().getMessage()); + } + + // Single quoted values. + json = "{\"foo\":'bar'}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'Object',line:1,column:8}. Invalid quote character \"'\" being used.", e.getRootCause().getMessage()); + } + + // Single quoted attribute name. + json = "{'foo':\"bar\"}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'ObjectMap<String,Object>',line:1,column:2}. Invalid quote character \"'\" being used.", e.getRootCause().getMessage()); + } + + // Unquoted attribute name. + json = "{foo:\"bar\"}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'ObjectMap<String,Object>',line:1,column:1}. Unquoted attribute detected.", e.getRootCause().getMessage()); + } + + // Concatenated string + json = "{\"foo\":\"bar\"+\"baz\"}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'Object',line:1,column:12}. String concatenation detected.", e.getRootCause().getMessage()); + } + + // Concatenated string 2 + json = "{\"foo\":\"bar\" + \"baz\"}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'Object',line:1,column:13}. String concatenation detected.", e.getRootCause().getMessage()); + } + + json = "{\"foo\":/*comment*/\"bar\"}"; + try { + p.parse(json, ObjectMap.class); + fail("Exception expected"); + } catch (ParseException e) { + assertEquals("Parse exception occurred at {currentClass:'ObjectMap<String,Object>',line:1,column:8}. Javascript comment detected.", e.getRootCause().getMessage()); + } + } + + /** + * JSON numbers and booleans should be representable as strings and converted accordingly. + */ + @Test + public void testPrimitivesAsStrings() throws Exception { + String json; + ReaderParser p = JsonParser.DEFAULT; + WriterSerializer s = JsonSerializer.DEFAULT_LAX; + + json = "{f1:'1',f2:'1',f3:'true',f4:'true',f5:'1',f6:'1',f7:'1',f8:'1',f9:'1',f10:'1'}"; + B b = p.parse(json, B.class); + assertEquals("{f1:1,f2:1,f3:true,f4:true,f5:1.0,f6:1.0,f7:1,f8:1,f9:1,f10:1}", s.toString(b)); + + json = "{f1:'',f2:'',f3:'',f4:'',f5:'',f6:'',f7:'',f8:'',f9:'',f10:''}"; + b = p.parse(json, B.class); + assertEquals("{f1:0,f2:0,f3:false,f4:false,f5:0.0,f6:0.0,f7:0,f8:0,f9:0,f10:0}", s.toString(b)); + } + + public static class B { + public int f1; + public Integer f2; + public boolean f3; + public Boolean f4; + public float f5; + public Float f6; + public long f7; + public Long f8; + public byte f9; + public Byte f10; + } + + //==================================================================================================== + // testInvalidJsonNumbers + // Lax parser allows octal and hexadecimal numbers. Strict parser does not. + //==================================================================================================== + @Test + public void testInvalidJsonNumbers() throws Exception { + JsonParser p1 = JsonParser.DEFAULT; + JsonParser p2 = JsonParser.DEFAULT_STRICT; + Number r; + + // Lax allows blank strings interpreted as 0, strict does not. + String s = "\"\""; + r = p1.parse(s, Number.class); + assertEquals(0, r.intValue()); + assertTrue(r instanceof Integer); + try { + r = p2.parse(s, Number.class); + fail("Exception expected"); + } catch (ParseException e) { + assertTrue(e.getMessage().contains("Invalid JSON number")); + } + + // Either should allow 0 or -0. + s = "0"; + r = p1.parse(s, Number.class); + assertEquals(0, r.intValue()); + assertTrue(r instanceof Integer); + r = p2.parse(s, Number.class); + assertEquals(0, r.intValue()); + assertTrue(r instanceof Integer); + + s = "-0"; + r = p1.parse(s, Number.class); + assertEquals(0, r.intValue()); + assertTrue(r instanceof Integer); + r = p2.parse(s, Number.class); + assertEquals(0, r.intValue()); + assertTrue(r instanceof Integer); + + // Lax allows 0123 and -0123, strict does not. + s = "0123"; + r = p1.parse(s, Number.class); + assertEquals(0123, r.intValue()); + assertTrue(r instanceof Integer); + try { + r = p2.parse(s, Number.class); + fail("Exception expected"); + } catch (ParseException e) { + assertTrue(e.getMessage().contains("Invalid JSON number")); + } + s = "-0123"; + r = p1.parse(s, Number.class); + assertEquals(-0123, r.intValue()); + assertTrue(r instanceof Integer); + try { + r = p2.parse(s, Number.class); + fail("Exception expected"); + } catch (ParseException e) { + assertTrue(e.getMessage().contains("Invalid JSON number")); + } + + // Lax allows 0x123 and -0x123, strict does not. + s = "0x123"; + r = p1.parse(s, Number.class); + assertEquals(0x123, r.intValue()); + assertTrue(r instanceof Integer); + try { + r = p2.parse(s, Number.class); + fail("Exception expected"); + } catch (ParseException e) { + assertTrue(e.getMessage().contains("Invalid JSON number")); + } + s = "-0x123"; + r = p1.parse(s, Number.class); + assertEquals(-0x123, r.intValue()); + assertTrue(r instanceof Integer); + try { + r = p2.parse(s, Number.class); + fail("Exception expected"); + } catch (ParseException e) { + assertTrue(e.getMessage().contains("Invalid JSON number")); + } + } + + //==================================================================================================== + // testUnquotedStrings + // Lax parser allows unquoted strings if POJO can be converted from a string. + //==================================================================================================== + @Test + public void testUnquotedStrings() throws Exception { + JsonParser p1 = JsonParser.DEFAULT; + JsonParser p2 = JsonParser.DEFAULT_STRICT; + + String s = "foobar"; + C c = p1.parse(s, C.class); + assertEquals("f=foobar", c.toString()); + + try { + p2.parse(s, C.class); + fail("Exception expected"); + } catch (ParseException e) { + // OK + } + } + + public static class C { + String f; + public static C valueOf(String s) { + C c = new C(); + c.f = s; + return c; + } + @Override /* Object */ + public String toString() { + return "f="+f; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/e4dfdf81/juneau-core-test/src/test/java/org/apache/juneau/json/JsonSchemaTest.java ---------------------------------------------------------------------- diff --git a/juneau-core-test/src/test/java/org/apache/juneau/json/JsonSchemaTest.java b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonSchemaTest.java new file mode 100755 index 0000000..2567e44 --- /dev/null +++ b/juneau-core-test/src/test/java/org/apache/juneau/json/JsonSchemaTest.java @@ -0,0 +1,45 @@ +// *************************************************************************************************************************** +// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * +// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * +// * to you 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 org.apache.juneau.json; + +import static org.junit.Assert.*; + +import org.junit.*; + +@SuppressWarnings("javadoc") +public class JsonSchemaTest { + + //==================================================================================================== + // Primitive objects + //==================================================================================================== + @Test + public void testBasic() throws Exception { + + JsonSchemaSerializer s = JsonSerializer.DEFAULT_LAX.getSchemaSerializer(); + + Object o = new String(); + assertEquals("{type:'string',description:'java.lang.String'}", s.serialize(o)); + + o = new Integer(123); + assertEquals("{type:'number',description:'java.lang.Integer'}", s.serialize(o)); + + o = new Float(123); + assertEquals("{type:'number',description:'java.lang.Float'}", s.serialize(o)); + + o = new Double(123); + assertEquals("{type:'number',description:'java.lang.Double'}", s.serialize(o)); + + o = Boolean.TRUE; + assertEquals("{type:'boolean',description:'java.lang.Boolean'}", s.serialize(o)); + } +} \ No newline at end of file
