http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/DTOs.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/DTOs.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/DTOs.java new file mode 100755 index 0000000..52cd76b --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/DTOs.java @@ -0,0 +1,140 @@ +// *************************************************************************************************************************** +// * 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.urlencoding; + +import java.util.*; + +import org.apache.juneau.annotation.*; +import org.apache.juneau.urlencoding.annotation.*; +import org.apache.juneau.utils.*; + +@SuppressWarnings("javadoc") +public class DTOs { + + @Bean(sort=true) + public static class A { + public String a; + public int b; + public boolean c; + + public static A create() { + A t = new A(); + t.a = "a"; + t.b = 1; + t.c = true; + return t; + } + + } + + @Bean(sort=true) + public static class B { + public String[] f01; + public List<String> f02; + public int[] f03; + public List<Integer> f04; + public String[][] f05; + public List<String[]> f06; + public A[] f07; + public List<A> f08; + public A[][] f09; + public List<List<A>> f10; + + private String[] f11; + private List<String> f12; + private int[] f13; + private List<Integer> f14; + private String[][] f15; + private List<String[]> f16; + private A[] f17; + private List<A> f18; + private A[][] f19; + private List<List<A>> f20; + + public String[] getF11() { return f11; } + public List<String> getF12() { return f12; } + public int[] getF13() { return f13; } + public List<Integer> getF14() { return f14; } + public String[][] getF15() { return f15; } + public List<String[]> getF16() { return f16; } + public A[] getF17() { return f17; } + public List<A> getF18() { return f18; } + public A[][] getF19() { return f19; } + public List<List<A>> getF20() { return f20; } + + public void setF11(String[] f11) { this.f11 = f11; } + public void setF12(List<String> f12) { this.f12 = f12; } + public void setF13(int[] f13) { this.f13 = f13; } + public void setF14(List<Integer> f14) { this.f14 = f14; } + public void setF15(String[][] f15) { this.f15 = f15; } + public void setF16(List<String[]> f16) { this.f16 = f16; } + public void setF17(A[] f17) { this.f17 = f17; } + public void setF18(List<A> f18) { this.f18 = f18; } + public void setF19(A[][] f19) { this.f19 = f19; } + public void setF20(List<List<A>> f20) { this.f20 = f20; } + + static B create() { + B t = new B(); + t.f01 = new String[]{"a","b"}; + t.f02 = new AList<String>().append("c").append("d"); + t.f03 = new int[]{1,2}; + t.f04 = new AList<Integer>().append(3).append(4); + t.f05 = new String[][]{{"e","f"},{"g","h"}}; + t.f06 = new AList<String[]>().append(new String[]{"i","j"}).append(new String[]{"k","l"}); + t.f07 = new A[]{A.create(),A.create()}; + t.f08 = new AList<A>().append(A.create()).append(A.create()); + t.f09 = new A[][]{{A.create()},{A.create()}}; + t.f10 = new AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create())); + t.setF11(new String[]{"a","b"}); + t.setF12(new AList<String>().append("c").append("d")); + t.setF13(new int[]{1,2}); + t.setF14(new AList<Integer>().append(3).append(4)); + t.setF15(new String[][]{{"e","f"},{"g","h"}}); + t.setF16(new AList<String[]>().append(new String[]{"i","j"}).append(new String[]{"k","l"})); + t.setF17(new A[]{A.create(),A.create()}); + t.setF18(new AList<A>().append(A.create()).append(A.create())); + t.setF19(new A[][]{{A.create()},{A.create()}}); + t.setF20(new AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create()))); + return t; + } + } + + @UrlEncoding(expandedParams=true) + @Bean(sort=true) + public static class C extends B { + static C create() { + C t = new C(); + t.f01 = new String[]{"a","b"}; + t.f02 = new AList<String>().append("c").append("d"); + t.f03 = new int[]{1,2}; + t.f04 = new AList<Integer>().append(3).append(4); + t.f05 = new String[][]{{"e","f"},{"g","h"}}; + t.f06 = new AList<String[]>().append(new String[]{"i","j"}).append(new String[]{"k","l"}); + t.f07 = new A[]{A.create(),A.create()}; + t.f08 = new AList<A>().append(A.create()).append(A.create()); + t.f09 = new A[][]{{A.create()},{A.create()}}; + t.f10 = new AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create())); + t.setF11(new String[]{"a","b"}); + t.setF12(new AList<String>().append("c").append("d")); + t.setF13(new int[]{1,2}); + t.setF14(new AList<Integer>().append(3).append(4)); + t.setF15(new String[][]{{"e","f"},{"g","h"}}); + t.setF16(new AList<String[]>().append(new String[]{"i","j"}).append(new String[]{"k","l"})); + t.setF17(new A[]{A.create(),A.create()}); + t.setF18(new AList<A>().append(A.create()).append(A.create())); + t.setF19(new A[][]{{A.create()},{A.create()}}); + t.setF20(new AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create()))); + return t; + } + } +}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java new file mode 100755 index 0000000..5e05128 --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserReaderTest.java @@ -0,0 +1,220 @@ +// *************************************************************************************************************************** +// * 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.urlencoding; + +import static org.junit.Assert.*; + +import java.io.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.apache.juneau.uon.*; +import org.junit.*; + +@SuppressWarnings({"javadoc","resource"}) +public class UonParserReaderTest { + + //==================================================================================================== + // Basic tests + //==================================================================================================== + @Test + public void testBasic() throws Exception { + + UonReader r; + String s, in; + r = r("f", true); + assertEquals('f', r.read()); + assertEquals(-1, r.read()); + + r = r("%66", true); + assertEquals('f', r.read()); + assertEquals(-1, r.read()); + + r = r("%7D", true); + assertEquals('}', r.read()); + assertEquals(-1, r.read()); + + r = r("%7D%7D", true); + assertEquals('}', r.read()); + assertEquals('}', r.read()); + assertEquals(-1, r.read()); + + r = r("%00%00", true); + r.mark(); + assertEquals(0, r.read()); + assertEquals(0, r.read()); + assertEquals("\u0000\u0000", r.getMarked()); + assertEquals(-1, r.read()); + + in = escape("\u0080"); + r = r(in, true); + assertEquals('\u0080', r.read()); + assertEquals(-1, r.read()); + + in = escape("\u0800"); + r = r(in, true); + assertEquals('\u0800', r.read()); + assertEquals(-1, r.read()); + + in = escape("\uffff"); + r = r(in, true); + assertEquals('\uffff', r.read()); + assertEquals(-1, r.read()); + + // 2-byte codepoint + s = "¢"; + r = r(escape(s), true); + assertEquals(s.codePointAt(0), r.read()); + assertEquals(-1, r.read()); + + // 3-byte codepoint + s = "â¬"; + r = r(escape(s), true); + assertEquals(s.codePointAt(0), r.readCodePoint()); + assertEquals(-1, r.read()); + + // 4-byte codepoint + s = "ð¤¢"; + r = r(escape(s), true); + assertEquals(s.codePointAt(0), r.readCodePoint()); + assertEquals(-1, r.read()); + + s = "ð¤¢ð¤¢"; + r = r(escape(s), true); + assertEquals(s.codePointAt(0), r.readCodePoint()); + assertEquals(s.codePointAt(2), r.readCodePoint()); + assertEquals(-1, r.read()); + + // Multiple codepoints + s = "¢â¬ð¤¢Â¢â¬ð¤¢"; + in = escape(s); + r = r(in, true); + assertEquals(s.codePointAt(0), r.readCodePoint()); + assertEquals(s.codePointAt(1), r.readCodePoint()); + assertEquals(s.codePointAt(2), r.readCodePoint()); + assertEquals(s.codePointAt(4), r.readCodePoint()); + assertEquals(s.codePointAt(5), r.readCodePoint()); + assertEquals(s.codePointAt(6), r.readCodePoint()); + assertEquals(-1, r.read()); + + // Multiple codepoints read in small chunks. + s = "¢â¬ð¤¢Â¢â¬ð¤¢"; + String s2; + int i; + in = escape(s); + r = r(in, true); + char[] buff = new char[2]; + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("â¬", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("ð¤¢", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("â¬", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("ð¤¢", s2); + i = r.read(buff, 0, buff.length); + assertEquals(-1, i); + + // Multiple codepoints read in slightly larger chunks. + s = "¢â¬ð¤¢Â¢â¬ð¤¢"; + in = escape(s); + r = r(in, true); + buff = new char[3]; + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢â¬", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("ð¤¢", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢â¬", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("ð¤¢", s2); + i = r.read(buff, 0, buff.length); + assertEquals(-1, i); + + s = "¢â¬ð¤¢Â¢â¬ð¤¢"; + in = escape(s); + r = r(in, true); + buff = new char[4]; + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢â¬ð¤¢", s2); + i = r.read(buff, 0, buff.length); + s2 = new String(buff, 0, i); + assertEquals("¢â¬ð¤¢", s2); + i = r.read(buff, 0, buff.length); + assertEquals(-1, i); + + // Reader that only returns 1 character at a time; + s = "x¢â¬ð¤¢x¢â¬ð¤¢"; + in = "x" + escape("¢â¬ð¤¢") + "x" + escape("¢â¬ð¤¢"); + r = new UonReader(new ParserPipe(new SlowStringReader(in)), true); + assertEquals(s.codePointAt(0), r.readCodePoint()); + assertEquals(s.codePointAt(1), r.readCodePoint()); + assertEquals(s.codePointAt(2), r.readCodePoint()); + assertEquals(s.codePointAt(3), r.readCodePoint()); + assertEquals(s.codePointAt(5), r.readCodePoint()); + assertEquals(s.codePointAt(6), r.readCodePoint()); + assertEquals(s.codePointAt(7), r.readCodePoint()); + assertEquals(s.codePointAt(8), r.readCodePoint()); + assertEquals(-1, r.readCodePoint()); + } + + private String escape(String s) throws UnsupportedEncodingException { + StringBuilder sb = new StringBuilder(); + byte[] b = s.getBytes("UTF-8"); + for (int i = 0; i < b.length; i++) + sb.append('%').append(TestUtils.toHex(b[i])); + return sb.toString(); + } + + private UonReader r(String in, boolean decodeChars) throws Exception { + return new UonReader(new ParserPipe(in), decodeChars); + } + + private static class SlowStringReader extends Reader { + + String s; + int i = 0; + + SlowStringReader(String s) { + this.s = s; + } + + @Override /* Reader */ + public int read(char[] cbuf, int off, int len) throws IOException { + if (i >= s.length()) + return -1; + cbuf[off] = s.charAt(i++); + return 1; + } + + @Override /* Reader */ + public void close() throws IOException { + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java new file mode 100755 index 0000000..8d91ede --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonParserTest.java @@ -0,0 +1,514 @@ +// *************************************************************************************************************************** +// * 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.urlencoding; + +import static org.junit.Assert.*; + +import java.util.*; + +import org.apache.juneau.parser.*; +import org.apache.juneau.uon.*; +import org.junit.*; + +@SuppressWarnings({"rawtypes","javadoc"}) +public class UonParserTest { + + static UonParser p = UonParser.DEFAULT; + static UonParser pe = UonParser.DEFAULT_DECODING; + + //==================================================================================================== + // Basic test + //==================================================================================================== + @Test + public void testBasic() throws Exception { + + String t; + Map m; + + // Simple string + // Top level + t = "a"; + assertEquals("a", p.parse(t, String.class)); + assertEquals("a", p.parse(t, Object.class)); + assertEquals("a", pe.parse(t, String.class)); + t = "'a'"; + assertEquals("a", p.parse(t, String.class)); + assertEquals("a", p.parse(t, Object.class)); + t = " 'a' "; + assertEquals("a", p.parse(t, String.class)); + + // 2nd level + t = "(a=a)"; + assertEquals("a", p.parse(t, Map.class).get("a")); + assertEquals("a", pe.parse(t, Map.class).get("a")); + + t = "('a'='a')"; + assertEquals("a", p.parse(t, Map.class).get("a")); + assertEquals("a", pe.parse(t, Map.class).get("a")); + + // Simple map + // Top level + t = "(a=b,c=123,d=false,e=true,f=null)"; + m = p.parse(t, Map.class); + assertEquals("b", m.get("a")); + assertTrue(m.get("c") instanceof Number); + assertEquals(123, m.get("c")); + assertTrue(m.get("d") instanceof Boolean); + assertEquals(Boolean.FALSE, m.get("d")); + assertTrue(m.get("e") instanceof Boolean); + assertEquals(Boolean.TRUE, m.get("e")); + m = pe.parse(t, Map.class); + assertNull(m.get("f")); + + t = "(a=true)"; + m = p.parse(t, HashMap.class, String.class, Boolean.class); + assertTrue(m.get("a") instanceof Boolean); + assertEquals("true", m.get("a").toString()); + + // null + // Top level + t = "null"; + assertNull(p.parse(t, Object.class)); + assertNull(pe.parse(t, Object.class)); + + // 2nd level + t = "(null=null)"; + m = p.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + m = pe.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + + t = " ( null = null ) "; + m = p.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + m = pe.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + + // 3rd level + t = "(null=(null=null))"; + m = p.parse(t, Map.class); + assertTrue(((Map)m.get(null)).containsKey(null)); + assertNull(((Map)m.get(null)).get(null)); + m = pe.parse(t, Map.class); + assertTrue(((Map)m.get(null)).containsKey(null)); + assertNull(((Map)m.get(null)).get(null)); + + // Empty array + // Top level + t = "@()"; + List l = (List)p.parse(t, Object.class); + assertTrue(l.isEmpty()); + t = " @( ) "; + l = p.parse(t, List.class); + assertTrue(l.isEmpty()); + + // 2nd level in map + t = "(x=@())"; + m = p.parse(t, HashMap.class, String.class, List.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + m = (Map)p.parse(t, Object.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + t = " ( x = @( ) )"; + m = p.parse(t, HashMap.class, String.class, List.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + + // Empty 2 dimensional array + t = "@(@())"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + t = " @( @( ) ) "; + l = p.parse(t, LinkedList.class, List.class); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + + // Array containing empty string + // Top level + t = "@('')"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + t = " @( '' ) "; + l = p.parse(t, List.class, String.class); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + + // 2nd level + t = "(''=@(''))"; + m = (Map)p.parse(t, Object.class); + assertEquals("", ((List)m.get("")).get(0)); + t = " ( '' = @( '' ) ) "; + m = p.parse(t, HashMap.class, String.class, List.class); + assertEquals("", ((List)m.get("")).get(0)); + + // Array containing 3 empty strings + t = "@('','','')"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + t = " @( '' , '' , '' ) "; + l = p.parse(t, List.class, Object.class); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + + // String containing \u0000 + // Top level + t = "'\u0000'"; + assertEquals("\u0000", p.parse(t, Object.class)); + t = " '\u0000' "; + assertEquals("\u0000", p.parse(t, String.class)); + assertEquals("\u0000", p.parse(t, Object.class)); + + // 2nd level + t = "('\u0000'='\u0000')"; + m = (Map)p.parse(t, Object.class); + assertTrue(m.size() == 1); + assertEquals("\u0000", m.get("\u0000")); + t = " ( '\u0000' = '\u0000' ) "; + m = p.parse(t, HashMap.class, String.class, String.class); + assertTrue(m.size() == 1); + assertEquals("\u0000", m.get("\u0000")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertTrue(m.size() == 1); + assertEquals("\u0000", m.get("\u0000")); + + // Boolean + // Top level + t = "false"; + Boolean b = (Boolean)p.parse(t, Object.class); + assertEquals(Boolean.FALSE, b); + b = p.parse(t, Boolean.class); + assertEquals(Boolean.FALSE, b); + t = " false "; + b = p.parse(t, Boolean.class); + assertEquals(Boolean.FALSE, b); + + // 2nd level + t = "(x=false)"; + m = (Map)p.parse(t, Object.class); + assertEquals(Boolean.FALSE, m.get("x")); + t = " ( x = false ) "; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals(Boolean.FALSE, m.get("x")); + + // Number + // Top level + t = "123"; + Integer i = (Integer)p.parse(t, Object.class); + assertEquals(123, i.intValue()); + i = p.parse(t, Integer.class); + assertEquals(123, i.intValue()); + Double d = p.parse(t, Double.class); + assertEquals(123, d.intValue()); + Float f = p.parse(t, Float.class); + assertEquals(123, f.intValue()); + t = " 123 "; + i = p.parse(t, Integer.class); + assertEquals(123, i.intValue()); + + // 2nd level + t = "(x=123)"; + m = (Map)p.parse(t, Object.class); + assertEquals(123, ((Integer)m.get("x")).intValue()); + t = " ( x = 123 ) "; + m = p.parse(t, HashMap.class, String.class, Number.class); + assertEquals(123, ((Integer)m.get("x")).intValue()); + m = p.parse(t, HashMap.class, String.class, Double.class); + assertEquals(123, ((Double)m.get("x")).intValue()); + + // Unencoded chars + // Top level + t = "x;/?:@-_.!*~'"; + assertEquals("x;/?:@-_.!*'", p.parse(t, Object.class)); + assertEquals("x;/?:@-_.!*'", pe.parse(t, Object.class)); + + // 2nd level + t = "(x;/?:@-_.!*~'=x;/?:@-_.!*~')"; + m = (Map)p.parse(t, Object.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + m = p.parse(t, HashMap.class, String.class, String.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + + // Encoded chars + // Top level + t = "x{}|\\^[]`<>#%\"&+"; + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, Object.class)); + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, String.class)); + try { + assertEquals("x{}|\\^[]`<>#%\"&+", pe.parse(t, Object.class)); + fail("Expected parse exception from invalid hex sequence."); + } catch (ParseException e) { + // Good. + } + t = "x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B"; + assertEquals("x{}|\\^[]`<>#%\"&+", pe.parse(t, Object.class)); + assertEquals("x{}|\\^[]`<>#%\"&+", pe.parse(t, String.class)); + + // 2nd level + t = "(x{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+)"; + m = (Map)p.parse(t, Object.class); + assertEquals("x{}|\\^[]`<>#%\"&+", m.get("x{}|\\^[]`<>#%\"&+")); + try { + m = (Map)pe.parse(t, Object.class); + fail("Expected parse exception from invalid hex sequence."); + } catch (ParseException e) { + // Good. + } + t = "(x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B=x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B)"; + m = (Map)pe.parse(t, Object.class); + assertEquals("x{}|\\^[]`<>#%\"&+", m.get("x{}|\\^[]`<>#%\"&+")); + + // Special chars + // Top level + t = "'x$,()~''"; + assertEquals("x$,()'", p.parse(t, Object.class)); + t = " 'x$,()~'' "; + assertEquals("x$,()'", p.parse(t, Object.class)); + + // 2nd level + t = "('x$,()~''='x$,()~'')"; + m = (Map)p.parse(t, Object.class); + assertEquals("x$,()'", m.get("x$,()'")); + t = " ( 'x$,()~'' = 'x$,()~'' ) "; + m = (Map)p.parse(t, Object.class); + assertEquals("x$,()'", m.get("x$,()'")); + + // Equals sign + // Gets encoded at top level, and encoded+escaped at 2nd level. + // Top level + t = "x="; + assertEquals("x=", p.parse(t, Object.class)); + t = "x%3D"; + assertEquals("x=", pe.parse(t, Object.class)); + + // 2nd level + t = "('x='='x=')"; + m = (Map)p.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + t = "('x='='x=')"; + m = (Map)p.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + t = " ( 'x=' = 'x=' ) "; + m = (Map)p.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + t = "('x='='x=')"; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("x=", m.get("x=")); + t = " ( 'x=' = 'x=' ) "; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("x=", m.get("x=")); + t = "('x%3D'='x%3D')"; + m = (Map)pe.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + t = " ( 'x%3D' = 'x%3D' ) "; + m = (Map)pe.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + + // String starting with parenthesis + // Top level + t = "'()'"; + assertEquals("()", p.parse(t, Object.class)); + assertEquals("()", p.parse(t, String.class)); + + t = " '()' "; + assertEquals("()", p.parse(t, Object.class)); + assertEquals("()", p.parse(t, String.class)); + + // 2nd level + t = "('()'='()')"; + m = (Map)p.parse(t, Object.class); + assertEquals("()", m.get("()")); + t = " ( '()' = '()' ) "; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("()", m.get("()")); + + // String starting with $ + // Top level + t = "$a"; + assertEquals("$a", p.parse(t, Object.class)); + t = "'$a'"; + assertEquals("$a", p.parse(t, Object.class)); + + // 2nd level + t = "($a=$a)"; + m = (Map)p.parse(t, Object.class); + assertEquals("$a", m.get("$a")); + t = " ( $a = $a ) "; + m = (Map)p.parse(t, Object.class); + assertEquals("$a", m.get("$a")); + t = "('$a'='$a')"; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("$a", m.get("$a")); + t = " ( '$a' = '$a' ) "; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("$a", m.get("$a")); + + // Blank string + // Top level + t = ""; + assertEquals("", p.parse(t, Object.class)); + assertEquals("", pe.parse(t, Object.class)); + + // 2nd level + t = "(=)"; + m = (Map)p.parse(t, Object.class); + assertEquals("", m.get("")); + t = "(''='')"; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("", m.get("")); + + // 3rd level + t = "(=(=))"; + m = (Map)p.parse(t, Object.class); + assertEquals("", ((Map)m.get("")).get("")); + t = " ( = ( = ) ) "; + m = p.parse(t, HashMap.class, String.class, HashMap.class); + assertEquals("", ((Map)m.get("")).get("")); + + // Newline character + // Top level + t = "'%0A'"; + assertEquals("\n", pe.parse(t, Object.class)); + assertEquals("%0A", p.parse(t, Object.class)); + + // 2nd level + t = "('%0A'='%0A')"; + m = (Map)pe.parse(t, Object.class); + assertEquals("\n", m.get("\n")); + m = (Map)p.parse(t, Object.class); + assertEquals("%0A", m.get("%0A")); + + // 3rd level + t = "('%0A'=('%0A'='%0A'))"; + m = (Map)pe.parse(t, Object.class); + assertEquals("\n", ((Map)m.get("\n")).get("\n")); + } + + //==================================================================================================== + // Unicode character test + //==================================================================================================== + @Test + public void testUnicodeChars() throws Exception { + String t; + Map m; + + // 2-byte UTF-8 character + // Top level + t = "¢"; + assertEquals("¢", p.parse(t, Object.class)); + assertEquals("¢", p.parse(t, String.class)); + t = "%C2%A2"; + assertEquals("¢", pe.parse(t, Object.class)); + assertEquals("¢", pe.parse(t, String.class)); + + // 2nd level + t = "(¢=¢)"; + m = (Map)p.parse(t, Object.class); + assertEquals("¢", m.get("¢")); + t = "(%C2%A2=%C2%A2)"; + m = (Map)pe.parse(t, Object.class); + assertEquals("¢", m.get("¢")); + + // 3rd level + t = "(¢=(¢=¢))"; + m = (Map)p.parse(t, Object.class); + assertEquals("¢", ((Map)m.get("¢")).get("¢")); + t = "(%C2%A2=(%C2%A2=%C2%A2))"; + m = (Map)pe.parse(t, Object.class); + assertEquals("¢", ((Map)m.get("¢")).get("¢")); + + // 3-byte UTF-8 character + // Top level + t = "â¬"; + assertEquals("â¬", p.parse(t, Object.class)); + assertEquals("â¬", p.parse(t, String.class)); + t = "%E2%82%AC"; + assertEquals("â¬", pe.parse(t, Object.class)); + assertEquals("â¬", pe.parse(t, String.class)); + + // 2nd level + t = "(â¬=â¬)"; + m = (Map)p.parse(t, Object.class); + assertEquals("â¬", m.get("â¬")); + t = "(%E2%82%AC=%E2%82%AC)"; + m = (Map)pe.parse(t, Object.class); + assertEquals("â¬", m.get("â¬")); + + // 3rd level + t = "(â¬=(â¬=â¬))"; + m = (Map)p.parse(t, Object.class); + assertEquals("â¬", ((Map)m.get("â¬")).get("â¬")); + t = "(%E2%82%AC=(%E2%82%AC=%E2%82%AC))"; + m = (Map)pe.parse(t, Object.class); + assertEquals("â¬", ((Map)m.get("â¬")).get("â¬")); + + // 4-byte UTF-8 character + // Top level + t = "ð¤¢"; + assertEquals("ð¤¢", p.parse(t, Object.class)); + assertEquals("ð¤¢", p.parse(t, String.class)); + t = "%F0%A4%AD%A2"; + assertEquals("ð¤¢", pe.parse(t, Object.class)); + assertEquals("ð¤¢", pe.parse(t, String.class)); + + // 2nd level + t = "(ð¤¢=ð¤¢)"; + m = (Map)p.parse(t, Object.class); + assertEquals("ð¤¢", m.get("ð¤¢")); + t = "(%F0%A4%AD%A2=%F0%A4%AD%A2)"; + m = (Map)pe.parse(t, Object.class); + assertEquals("ð¤¢", m.get("ð¤¢")); + + // 3rd level + t = "(ð¤¢=(ð¤¢=ð¤¢))"; + m = (Map)p.parse(t, Object.class); + assertEquals("ð¤¢", ((Map)m.get("ð¤¢")).get("ð¤¢")); + t = "(%F0%A4%AD%A2=(%F0%A4%AD%A2=%F0%A4%AD%A2))"; + m = (Map)pe.parse(t, Object.class); + assertEquals("ð¤¢", ((Map)m.get("ð¤¢")).get("ð¤¢")); + } + + //==================================================================================================== + // Test simple bean + //==================================================================================================== + @Test + public void testSimpleBean() throws Exception { + UonParser p = UonParser.DEFAULT; + A t; + + String s = "(f1=foo,f2=123)"; + t = p.parse(s, A.class); + assertEquals("foo", t.f1); + assertEquals(123, t.f2); + } + + public static class A { + public String f1; + public int f2; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java new file mode 100755 index 0000000..bf3bc75 --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UonSerializerTest.java @@ -0,0 +1,362 @@ +// *************************************************************************************************************************** +// * 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.urlencoding; + +import static org.junit.Assert.*; + +import org.apache.juneau.*; +import org.apache.juneau.uon.*; +import org.junit.*; + +@SuppressWarnings("javadoc") +public class UonSerializerTest { + + static UonSerializer s = UonSerializer.DEFAULT_ENCODING; + static UonSerializer su = UonSerializer.DEFAULT; + static UonSerializer sr = UonSerializer.DEFAULT_READABLE; + + + //==================================================================================================== + // Basic test + //==================================================================================================== + @Test + public void testBasic() throws Exception { + + Object t; + + // Simple string + // Top level + t = "a"; + assertEquals("a", s.serialize(t)); + assertEquals("a", su.serialize(t)); + assertEquals("a", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{a:'a'}"); + assertEquals("(a=a)", s.serialize(t)); + assertEquals("(a=a)", su.serialize(t)); + assertEquals("(\n\ta=a\n)", sr.serialize(t)); + + // Simple map + // Top level + t = new ObjectMap("{a:'b',c:123,d:false,e:true,f:null}"); + assertEquals("(a=b,c=123,d=false,e=true,f=null)", s.serialize(t)); + assertEquals("(a=b,c=123,d=false,e=true,f=null)", su.serialize(t)); + assertEquals("(\n\ta=b,\n\tc=123,\n\td=false,\n\te=true,\n\tf=null\n)", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{a:{a:'b',c:123,d:false,e:true,f:null}}"); + assertEquals("(a=(a=b,c=123,d=false,e=true,f=null))", s.serialize(t)); + assertEquals("(a=(a=b,c=123,d=false,e=true,f=null))", su.serialize(t)); + assertEquals("(\n\ta=(\n\t\ta=b,\n\t\tc=123,\n\t\td=false,\n\t\te=true,\n\t\tf=null\n\t)\n)", sr.serialize(t)); + + // Simple map with primitives as literals + t = new ObjectMap("{a:'b',c:'123',d:'false',e:'true',f:'null'}"); + assertEquals("(a=b,c='123',d='false',e='true',f='null')", s.serialize(t)); + assertEquals("(a=b,c='123',d='false',e='true',f='null')", su.serialize(t)); + assertEquals("(\n\ta=b,\n\tc='123',\n\td='false',\n\te='true',\n\tf='null'\n)", sr.serialize(t)); + + // null + // Note that serializeParams is always encoded. + // Top level + t = null; + assertEquals("null", s.serialize(t)); + assertEquals("null", su.serialize(t)); + assertEquals("null", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{null:null}"); + assertEquals("(null=null)", s.serialize(t)); + assertEquals("(null=null)", su.serialize(t)); + assertEquals("(\n\tnull=null\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{null:{null:null}}"); + assertEquals("(null=(null=null))", s.serialize(t)); + assertEquals("(null=(null=null))", su.serialize(t)); + assertEquals("(\n\tnull=(\n\t\tnull=null\n\t)\n)", sr.serialize(t)); + + // Empty array + // Top level + t = new String[0]; + assertEquals("@()", s.serialize(t)); + assertEquals("@()", su.serialize(t)); + assertEquals("@()", sr.serialize(t)); + + // 2nd level in map + t = new ObjectMap("{x:[]}"); + assertEquals("(x=@())", s.serialize(t)); + assertEquals("(x=@())", su.serialize(t)); + assertEquals("(\n\tx=@()\n)", sr.serialize(t)); + + // Empty 2 dimensional array + t = new String[1][0]; + assertEquals("@(@())", s.serialize(t)); + assertEquals("@(@())", su.serialize(t)); + assertEquals("@(\n\t@()\n)", sr.serialize(t)); + + // Array containing empty string + // Top level + t = new String[]{""}; + assertEquals("@('')", s.serialize(t)); + assertEquals("@('')", su.serialize(t)); + assertEquals("@(\n\t''\n)", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{x:['']}"); + assertEquals("(x=@(''))", s.serialize(t)); + assertEquals("(x=@(''))", su.serialize(t)); + assertEquals("(\n\tx=@(\n\t\t''\n\t)\n)", sr.serialize(t)); + + // Array containing 3 empty strings + t = new String[]{"","",""}; + assertEquals("@('','','')", s.serialize(t)); + assertEquals("@('','','')", su.serialize(t)); + assertEquals("@(\n\t'',\n\t'',\n\t''\n)", sr.serialize(t)); + + // String containing \u0000 + // Top level + t = "\u0000"; + assertEquals("%00", s.serialize(t)); + assertEquals("\u0000", su.serialize(t)); + assertEquals("\u0000", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'\u0000':'\u0000'}"); + assertEquals("(%00=%00)", s.serialize(t)); + assertEquals("(\u0000=\u0000)", su.serialize(t)); + assertEquals("(\n\t\u0000=\u0000\n)", sr.serialize(t)); + + // Boolean + // Top level + t = false; + assertEquals("false", s.serialize(t)); + assertEquals("false", su.serialize(t)); + assertEquals("false", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{x:false}"); + assertEquals("(x=false)", s.serialize(t)); + assertEquals("(x=false)", su.serialize(t)); + assertEquals("(\n\tx=false\n)", sr.serialize(t)); + + // Number + // Top level + t = 123; + assertEquals("123", s.serialize(t)); + assertEquals("123", su.serialize(t)); + assertEquals("123", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{x:123}"); + assertEquals("(x=123)", s.serialize(t)); + assertEquals("(x=123)", su.serialize(t)); + assertEquals("(\n\tx=123\n)", sr.serialize(t)); + + // Unencoded chars + // Top level + t = "x;/?:@-_.!*'"; + assertEquals("x;/?:@-_.!*~'", s.serialize(t)); + assertEquals("x;/?:@-_.!*~'", su.serialize(t)); + assertEquals("x;/?:@-_.!*~'", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{x:'x;/?:@-_.!*\\''}"); + assertEquals("(x=x;/?:@-_.!*~')", s.serialize(t)); + assertEquals("(x=x;/?:@-_.!*~')", su.serialize(t)); + assertEquals("(\n\tx=x;/?:@-_.!*~'\n)", sr.serialize(t)); + + // Encoded chars + // Top level + t = "x{}|\\^[]`<>#%\"&+"; + assertEquals("x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B", s.serialize(t)); + assertEquals("x{}|\\^[]`<>#%\"&+", su.serialize(t)); + assertEquals("x{}|\\^[]`<>#%\"&+", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'x{}|\\\\^[]`<>#%\"&+':'x{}|\\\\^[]`<>#%\"&+'}"); + assertEquals("(x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B=x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B)", s.serialize(t)); + assertEquals("(x{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+)", su.serialize(t)); + assertEquals("(\n\tx{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+\n)", sr.serialize(t)); + + // Escaped chars + // Top level + t = "x$,()~"; + assertEquals("'x$,()~~'", s.serialize(t)); + assertEquals("'x$,()~~'", su.serialize(t)); + assertEquals("'x$,()~~'", sr.serialize(t)); + + // 2nd level + // Note behavior on serializeParams() is different since 2nd-level is top level. + t = new ObjectMap("{'x$,()~':'x$,()~'}"); + assertEquals("('x$,()~~'='x$,()~~')", s.serialize(t)); + assertEquals("('x$,()~~'='x$,()~~')", su.serialize(t)); + assertEquals("(\n\t'x$,()~~'='x$,()~~'\n)", sr.serialize(t)); + + // 3rd level + // Note behavior on serializeParams(). + t = new ObjectMap("{'x$,()~':{'x$,()~':'x$,()~'}}"); + assertEquals("('x$,()~~'=('x$,()~~'='x$,()~~'))", s.serialize(t)); + assertEquals("('x$,()~~'=('x$,()~~'='x$,()~~'))", su.serialize(t)); + assertEquals("(\n\t'x$,()~~'=(\n\t\t'x$,()~~'='x$,()~~'\n\t)\n)", sr.serialize(t)); + + // Equals sign + // Gets encoded at top level, and encoded+escaped at 2nd level. + // Top level + t = "x="; + assertEquals("'x='", s.serialize(t)); + assertEquals("'x='", su.serialize(t)); + assertEquals("'x='", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'x=':'x='}"); + assertEquals("('x='='x=')", s.serialize(t)); + assertEquals("('x='='x=')", su.serialize(t)); + assertEquals("(\n\t'x='='x='\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'x=':{'x=':'x='}}"); + assertEquals("('x='=('x='='x='))", s.serialize(t)); + assertEquals("('x='=('x='='x='))", su.serialize(t)); + assertEquals("(\n\t'x='=(\n\t\t'x='='x='\n\t)\n)", sr.serialize(t)); + + // String starting with parenthesis + // Top level + t = "()"; + assertEquals("'()'", s.serialize(t)); + assertEquals("'()'", su.serialize(t)); + assertEquals("'()'", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'()':'()'}"); + assertEquals("('()'='()')", s.serialize(t)); + assertEquals("('()'='()')", su.serialize(t)); + assertEquals("(\n\t'()'='()'\n)", sr.serialize(t)); + + // String starting with $ + // Top level + t = "$a"; + assertEquals("$a", s.serialize(t)); + assertEquals("$a", su.serialize(t)); + assertEquals("$a", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{$a:'$a'}"); + assertEquals("($a=$a)", s.serialize(t)); + assertEquals("($a=$a)", su.serialize(t)); + assertEquals("(\n\t$a=$a\n)", sr.serialize(t)); + + // Blank string + // Top level + t = ""; + assertEquals("''", s.serialize(t)); + assertEquals("''", su.serialize(t)); + assertEquals("''", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'':''}"); + assertEquals("(''='')", s.serialize(t)); + assertEquals("(''='')", su.serialize(t)); + assertEquals("(\n\t''=''\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'':{'':''}}"); + assertEquals("(''=(''=''))", s.serialize(t)); + assertEquals("(''=(''=''))", su.serialize(t)); + assertEquals("(\n\t''=(\n\t\t''=''\n\t)\n)", sr.serialize(t)); + + // Newline character + // Top level + t = "\n"; + assertEquals("'%0A'", s.serialize(t)); + assertEquals("'\n'", su.serialize(t)); + assertEquals("'\n'", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'\n':'\n'}"); + assertEquals("('%0A'='%0A')", s.serialize(t)); + assertEquals("('\n'='\n')", su.serialize(t)); + assertEquals("(\n\t'\n'='\n'\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'\n':{'\n':'\n'}}"); + assertEquals("('%0A'=('%0A'='%0A'))", s.serialize(t)); + assertEquals("('\n'=('\n'='\n'))", su.serialize(t)); + assertEquals("(\n\t'\n'=(\n\t\t'\n'='\n'\n\t)\n)", sr.serialize(t)); + } + + //==================================================================================================== + // Unicode characters test + //==================================================================================================== + @Test + public void testUnicodeChars() throws Exception { + Object t; + + // 2-byte UTF-8 character + // Top level + t = "¢"; + assertEquals("%C2%A2", s.serialize(t)); + assertEquals("¢", su.serialize(t)); + assertEquals("¢", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'¢':'¢'}"); + assertEquals("(%C2%A2=%C2%A2)", s.serialize(t)); + assertEquals("(¢=¢)", su.serialize(t)); + assertEquals("(\n\t¢=¢\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'¢':{'¢':'¢'}}"); + assertEquals("(%C2%A2=(%C2%A2=%C2%A2))", s.serialize(t)); + assertEquals("(¢=(¢=¢))", su.serialize(t)); + assertEquals("(\n\t¢=(\n\t\t¢=¢\n\t)\n)", sr.serialize(t)); + + // 3-byte UTF-8 character + // Top level + t = "â¬"; + assertEquals("%E2%82%AC", s.serialize(t)); + assertEquals("â¬", su.serialize(t)); + assertEquals("â¬", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'â¬':'â¬'}"); + assertEquals("(%E2%82%AC=%E2%82%AC)", s.serialize(t)); + assertEquals("(â¬=â¬)", su.serialize(t)); + assertEquals("(\n\tâ¬=â¬\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'â¬':{'â¬':'â¬'}}"); + assertEquals("(%E2%82%AC=(%E2%82%AC=%E2%82%AC))", s.serialize(t)); + assertEquals("(â¬=(â¬=â¬))", su.serialize(t)); + assertEquals("(\n\tâ¬=(\n\t\tâ¬=â¬\n\t)\n)", sr.serialize(t)); + + // 4-byte UTF-8 character + // Top level + t = "ð¤¢"; + assertEquals("%F0%A4%AD%A2", s.serialize(t)); + assertEquals("ð¤¢", su.serialize(t)); + assertEquals("ð¤¢", sr.serialize(t)); + + // 2nd level + t = new ObjectMap("{'ð¤¢':'ð¤¢'}"); + assertEquals("(%F0%A4%AD%A2=%F0%A4%AD%A2)", s.serialize(t)); + assertEquals("(ð¤¢=ð¤¢)", su.serialize(t)); + assertEquals("(\n\tð¤¢=ð¤¢\n)", sr.serialize(t)); + + // 3rd level + t = new ObjectMap("{'ð¤¢':{'ð¤¢':'ð¤¢'}}"); + assertEquals("(%F0%A4%AD%A2=(%F0%A4%AD%A2=%F0%A4%AD%A2))", s.serialize(t)); + assertEquals("(ð¤¢=(ð¤¢=ð¤¢))", su.serialize(t)); + assertEquals("(\n\tð¤¢=(\n\t\tð¤¢=ð¤¢\n\t)\n)", sr.serialize(t)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingParserTest.java ---------------------------------------------------------------------- diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingParserTest.java new file mode 100755 index 0000000..141ea07 --- /dev/null +++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/urlencoding/UrlEncodingParserTest.java @@ -0,0 +1,952 @@ +// *************************************************************************************************************************** +// * 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.urlencoding; + +import static org.apache.juneau.TestUtils.*; +import static org.junit.Assert.*; + +import java.util.*; + +import org.apache.juneau.*; +import org.apache.juneau.parser.*; +import org.junit.*; + +@SuppressWarnings({"rawtypes","javadoc"}) +public class UrlEncodingParserTest { + + static UrlEncodingParser p = UrlEncodingParser.DEFAULT; + static BeanSession bs = p.getBeanContext().createSession(); + + //==================================================================================================== + // Basic test + //==================================================================================================== + @Test + public void testBasic() throws Exception { + + String t; + Map m; + List l; + + // Simple string + // Top level + t = "_value=a"; + assertEquals("a", p.parse(t, Object.class)); + assertEquals("a", p.parse(t, String.class)); + t = "_value='a'"; + assertEquals("a", p.parse(t, String.class)); + assertEquals("a", p.parse(t, Object.class)); + t = "_value= 'a' "; + assertEquals("a", p.parse(t, String.class)); + + t = "a"; + assertEquals("a", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("a", p.parse(PartType.HEADER, t, bs.string())); + t = "'a'"; + assertEquals("a", p.parse(PartType.HEADER, t, bs.string())); + assertEquals("a", p.parse(PartType.HEADER, t, bs.object())); + t = " 'a' "; + assertEquals("a", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?a=a"; + assertEquals("a", p.parse(t, Map.class).get("a")); + + // Simple map + // Top level + t = "?a=b&c=123&d=false&e=true&f=null"; + m = p.parse(t, Map.class); + assertEquals("b", m.get("a")); + assertTrue(m.get("c") instanceof Number); + assertEquals(123, m.get("c")); + assertTrue(m.get("d") instanceof Boolean); + assertEquals(Boolean.FALSE, m.get("d")); + assertTrue(m.get("e") instanceof Boolean); + assertEquals(Boolean.TRUE, m.get("e")); + assertNull(m.get("f")); + + t = "(a=b,c=123,d=false,e=true,f=%00)"; + m = p.parse(PartType.HEADER, t, bs.getClassMeta(Map.class)); + assertEquals("b", m.get("a")); + assertTrue(m.get("c") instanceof Number); + assertEquals(123, m.get("c")); + assertTrue(m.get("d") instanceof Boolean); + assertEquals(Boolean.FALSE, m.get("d")); + assertTrue(m.get("e") instanceof Boolean); + assertEquals(Boolean.TRUE, m.get("e")); + assertEquals("%00", m.get("f")); + + t = "(a=b,c=123,d=false,e=true,f=null)"; + m = p.parse(PartType.HEADER, t, bs.getClassMeta(Map.class)); + assertTrue(m.containsKey("f")); + assertNull(m.get("f")); + + t = "?a=true"; + m = p.parse(t, HashMap.class, String.class, Boolean.class); + assertTrue(m.get("a") instanceof Boolean); + assertEquals("true", m.get("a").toString()); + + // null + // Top level + t = "_value=null"; + assertNull(p.parse(t, Object.class)); + t = "null"; + assertNull(p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?null=null"; + m = p.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + + t = "?null=null"; + m = p.parse(t, Map.class); + assertTrue(m.containsKey(null)); + assertNull(m.get(null)); + + // 3rd level + t = "?null=(null=null)"; + m = p.parse(t, Map.class); + assertTrue(((Map)m.get(null)).containsKey(null)); + assertNull(((Map)m.get(null)).get(null)); + + // Empty array + // Top level + t = "@()"; + l = (List)p.parse(PartType.HEADER, t, bs.object()); + assertTrue(l.isEmpty()); + t = " @( ) "; + l = p.parse(PartType.HEADER, t, bs.getClassMeta(List.class)); + assertTrue(l.isEmpty()); + + // 2nd level in map + t = "?x=@()"; + m = p.parse(t, HashMap.class, String.class, List.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + m = (Map)p.parse(t, Object.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + t = "?x=@()"; + m = p.parse(t, HashMap.class, String.class, List.class); + assertTrue(m.containsKey("x")); + assertTrue(((List)m.get("x")).isEmpty()); + + // Empty 2 dimensional array + t = "_value=@(@())"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + t = "0=@()"; + l = p.parse(t, LinkedList.class, List.class); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + t = "@(@())"; + l = (List)p.parse(PartType.HEADER, t, bs.object()); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + t = "@(@())"; + l = (List)p.parse(PartType.HEADER, t, bs.getClassMeta(LinkedList.class, List.class)); + assertTrue(l.size() == 1); + l = (List)l.get(0); + assertTrue(l.isEmpty()); + + // Array containing empty string + // Top level + t = "_value=@('')"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + t = "0=''"; + l = p.parse(t, List.class, String.class); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + t = "@('')"; + l = (List)p.parse(PartType.HEADER, t, bs.object()); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + t = "@('')"; + l = (List)p.parse(PartType.HEADER, t, bs.getClassMeta(List.class, String.class)); + assertTrue(l.size() == 1); + assertEquals("", l.get(0)); + + // 2nd level + t = "?''=@('')"; + m = (Map)p.parse(t, Object.class); + assertEquals("", ((List)m.get("")).get(0)); + t = "?''=@('')"; + m = p.parse(t, HashMap.class, String.class, List.class); + assertEquals("", ((List)m.get("")).get(0)); + + // Array containing 3 empty strings + t = "_value=@('','','')"; + l = (List)p.parse(t, Object.class); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + t = "0=''&1=''&2=''"; + l = p.parse(t, List.class, Object.class); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + t = "@('','','')"; + l = (List)p.parse(PartType.HEADER, t, bs.object()); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + t = "@('','','')"; + l = (List)p.parse(PartType.HEADER, t, bs.getClassMeta(List.class, Object.class)); + assertTrue(l.size() == 3); + assertEquals("", l.get(0)); + assertEquals("", l.get(1)); + assertEquals("", l.get(2)); + + // String containing \u0000 + // Top level + t = "_value='\u0000'"; + assertEquals("\u0000", p.parse(t, Object.class)); + t = "_value='\u0000'"; + assertEquals("\u0000", p.parse(t, String.class)); + assertEquals("\u0000", p.parse(t, Object.class)); + t = "'\u0000'"; + assertEquals("\u0000", p.parse(PartType.HEADER, t, bs.object())); + t = "'\u0000'"; + assertEquals("\u0000", p.parse(PartType.HEADER, t, bs.string())); + assertEquals("\u0000", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?'\u0000'='\u0000'"; + m = (Map)p.parse(t, Object.class); + assertTrue(m.size() == 1); + assertEquals("\u0000", m.get("\u0000")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertTrue(m.size() == 1); + assertEquals("\u0000", m.get("\u0000")); + + // Boolean + // Top level + t = "_value=false"; + Boolean b = (Boolean)p.parse(t, Object.class); + assertEquals(Boolean.FALSE, b); + b = p.parse(t, Boolean.class); + assertEquals(Boolean.FALSE, b); + t = "_value=false"; + b = p.parse(t, Boolean.class); + assertEquals(Boolean.FALSE, b); + t = "false"; + b = (Boolean)p.parse(PartType.HEADER, t, bs.object()); + assertEquals(Boolean.FALSE, b); + b = p.parse(PartType.HEADER, t, bs.getClassMeta(Boolean.class)); + assertEquals(Boolean.FALSE, b); + t = "false"; + b = p.parse(PartType.HEADER, t, bs.getClassMeta(Boolean.class)); + assertEquals(Boolean.FALSE, b); + + // 2nd level + t = "?x=false"; + m = (Map)p.parse(t, Object.class); + assertEquals(Boolean.FALSE, m.get("x")); + t = "?x=false"; + m = p.parse(t, HashMap.class, String.class, Boolean.class); + assertEquals(Boolean.FALSE, m.get("x")); + + // Number + // Top level + t = "_value=123"; + Integer i = (Integer)p.parse(t, Object.class); + assertEquals(123, i.intValue()); + i = p.parse(t, Integer.class); + assertEquals(123, i.intValue()); + Double d = p.parse(t, Double.class); + assertEquals(123, d.intValue()); + Float f = p.parse(t, Float.class); + assertEquals(123, f.intValue()); + t = "_value=123"; + i = p.parse(t, Integer.class); + assertEquals(123, i.intValue()); + t = "123"; + i = (Integer)p.parse(PartType.HEADER, t, bs.object()); + assertEquals(123, i.intValue()); + i = p.parse(PartType.HEADER, t, bs.getClassMeta(Integer.class)); + assertEquals(123, i.intValue()); + d = p.parse(PartType.HEADER, t, bs.getClassMeta(Double.class)); + assertEquals(123, d.intValue()); + f = p.parse(PartType.HEADER, t, bs.getClassMeta(Float.class)); + assertEquals(123, f.intValue()); + t = "123"; + i = p.parse(PartType.HEADER, t, bs.getClassMeta(Integer.class)); + assertEquals(123, i.intValue()); + + // 2nd level + t = "?x=123"; + m = (Map)p.parse(t, Object.class); + assertEquals(123, ((Integer)m.get("x")).intValue()); + m = p.parse(t, HashMap.class, String.class, Double.class); + assertEquals(123, ((Double)m.get("x")).intValue()); + + // Unencoded chars + // Top level + t = "_value=x;/?:@-_.!*'"; + assertEquals("x;/?:@-_.!*'", p.parse(t, Object.class)); + t = "x;/?:@-_.!*'"; + assertEquals("x;/?:@-_.!*'", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?x;/?:@-_.!*'=x;/?:@-_.!*'"; + m = (Map)p.parse(t, Object.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + m = p.parse(t, HashMap.class, String.class, String.class); + assertEquals("x;/?:@-_.!*'", m.get("x;/?:@-_.!*'")); + + // Encoded chars + // Top level + t = "_value=x{}|\\^[]`<>#%\"&+"; + try { + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, Object.class)); + fail("Expected parse exception from invalid hex sequence."); + } catch (ParseException e) { + // Good. + } + t = "_value=x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B"; + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, Object.class)); + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(t, String.class)); + t = "x{}|\\^[]`<>#%\"&+"; + assertEquals("x{}|\\^[]`<>#%\"&+", p.parse(PartType.HEADER, t, bs.object())); + t = "x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B"; + assertEquals("x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?x{}|\\^[]`<>#%\"&+=x{}|\\^[]`<>#%\"&+"; + try { + m = (Map)p.parse(t, Object.class); + fail("Expected parse exception from invalid hex sequence."); + } catch (ParseException e) { + // Good. + } + t = "?x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B=x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B"; + m = (Map)p.parse(t, Object.class); + assertEquals("x{}|\\^[]`<>#%\"&+", m.get("x{}|\\^[]`<>#%\"&+")); + + // Special chars + // These characters are escaped and not encoded. + // Top level + t = "_value='x$,()'"; + assertEquals("x$,()", p.parse(t, Object.class)); + t = "'x$,()'"; + assertEquals("x$,()", p.parse(PartType.HEADER, t, bs.object())); + t = "_value='x~~$~~,~~(~~)'"; + assertEquals("x~$~,~(~)", p.parse(t, Object.class)); + t = "'x~~$~~,~~(~~)'"; + assertEquals("x~$~,~(~)", p.parse(PartType.HEADER, t, bs.object())); + + // At secondary levels, these characters are escaped and not encoded. + // 2nd level + t = "?'x$,()'='x$,()'"; + m = (Map)p.parse(t, Object.class); + assertEquals("x$,()", m.get("x$,()")); + t = "?'x~~$~~,~~(~~)'='x~~$~~,~~(~~)'"; + m = (Map)p.parse(t, Object.class); + assertEquals("x~$~,~(~)", m.get("x~$~,~(~)")); + + // Equals sign + // Gets encoded at top level, and encoded+escaped at 2nd level. + // Top level + t = "_value='x='"; + assertEquals("x=", p.parse(t, Object.class)); + t = "_value='x%3D'"; + assertEquals("x=", p.parse(t, Object.class)); + t = "'x='"; + assertEquals("x=", p.parse(PartType.HEADER, t, bs.object())); + t = "'x%3D'"; + assertEquals("x%3D", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?'x%3D'='x%3D'"; + m = (Map)p.parse(t, Object.class); + assertEquals("x=", m.get("x=")); + t = "?'x~~%3D'='x~~%3D'"; + m = (Map)p.parse(t, Object.class); + assertEquals("x~=", m.get("x~=")); + + // String starting with parenthesis + // Top level + t = "_value='()'"; + assertEquals("()", p.parse(t, Object.class)); + assertEquals("()", p.parse(t, String.class)); + t = "_value='()'"; + assertEquals("()", p.parse(t, Object.class)); + assertEquals("()", p.parse(t, String.class)); + t = "'()'"; + assertEquals("()", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("()", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?'()'='()'"; + m = (Map)p.parse(t, Object.class); + assertEquals("()", m.get("()")); + t = "?'()'='()'"; + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("()", m.get("()")); + + // String starting with $ + // Top level + t = "_value=$a"; + assertEquals("$a", p.parse(t, Object.class)); + t = "_value=$a"; + assertEquals("$a", p.parse(t, Object.class)); + t = "$a"; + assertEquals("$a", p.parse(PartType.HEADER, t, bs.object())); + t = "$a"; + assertEquals("$a", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?$a=$a"; + m = (Map)p.parse(t, Object.class); + assertEquals("$a", m.get("$a")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("$a", m.get("$a")); + + // Blank string + // Top level + t = "_value="; + assertEquals("", p.parse(t, Object.class)); + t = ""; + assertEquals("", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?="; + m = (Map)p.parse(t, Object.class); + assertEquals("", m.get("")); + m = p.parse(t, HashMap.class, String.class, Object.class); + assertEquals("", m.get("")); + + // 3rd level + t = "?=(=)"; + m = (Map)p.parse(t, Object.class); + assertEquals("", ((Map)m.get("")).get("")); + t = "?=(=)"; + m = p.parse(t, HashMap.class, String.class, HashMap.class); + assertEquals("", ((Map)m.get("")).get("")); + + // Newline character + // Top level + t = "_value='%0A'"; + assertEquals("\n", p.parse(t, Object.class)); + t = "'%0A'"; + assertEquals("%0A", p.parse(PartType.HEADER, t, bs.object())); + t = "'\n'"; + assertEquals("\n", p.parse(PartType.HEADER, t, bs.object())); + + // 2nd level + t = "?'%0A'='%0A'"; + m = (Map)p.parse(t, Object.class); + assertEquals("\n", m.get("\n")); + + // 3rd level + t = "?'%0A'=('%0A'='%0A')"; + m = (Map)p.parse(t, Object.class); + assertEquals("\n", ((Map)m.get("\n")).get("\n")); + } + + //==================================================================================================== + // Unicode character test + //==================================================================================================== + @Test + public void testUnicodeChars() throws Exception { + String t; + Map m; + + // 2-byte UTF-8 character + // Top level + t = "_value=¢"; + assertEquals("¢", p.parse(t, Object.class)); + assertEquals("¢", p.parse(t, String.class)); + t = "_value=%C2%A2"; + assertEquals("¢", p.parse(t, Object.class)); + assertEquals("¢", p.parse(t, String.class)); + t = "¢"; + assertEquals("¢", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("¢", p.parse(PartType.HEADER, t, bs.string())); + t = "%C2%A2"; + assertEquals("%C2%A2", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("%C2%A2", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?%C2%A2=%C2%A2"; + m = (Map)p.parse(t, Object.class); + assertEquals("¢", m.get("¢")); + + // 3rd level + t = "?%C2%A2=(%C2%A2=%C2%A2)"; + m = (Map)p.parse(t, Object.class); + assertEquals("¢", ((Map)m.get("¢")).get("¢")); + + // 3-byte UTF-8 character + // Top level + t = "_value=â¬"; + assertEquals("â¬", p.parse(t, Object.class)); + assertEquals("â¬", p.parse(t, String.class)); + t = "_value=%E2%82%AC"; + assertEquals("â¬", p.parse(t, Object.class)); + assertEquals("â¬", p.parse(t, String.class)); + t = "â¬"; + assertEquals("â¬", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("â¬", p.parse(PartType.HEADER, t, bs.string())); + t = "%E2%82%AC"; + assertEquals("%E2%82%AC", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("%E2%82%AC", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?%E2%82%AC=%E2%82%AC"; + m = (Map)p.parse(t, Object.class); + assertEquals("â¬", m.get("â¬")); + + // 3rd level + t = "?%E2%82%AC=(%E2%82%AC=%E2%82%AC)"; + m = (Map)p.parse(t, Object.class); + assertEquals("â¬", ((Map)m.get("â¬")).get("â¬")); + + // 4-byte UTF-8 character + // Top level + t = "_value=ð¤¢"; + assertEquals("ð¤¢", p.parse(t, Object.class)); + assertEquals("ð¤¢", p.parse(t, String.class)); + t = "_value=%F0%A4%AD%A2"; + assertEquals("ð¤¢", p.parse(t, Object.class)); + assertEquals("ð¤¢", p.parse(t, String.class)); + t = "ð¤¢"; + assertEquals("ð¤¢", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("ð¤¢", p.parse(PartType.HEADER, t, bs.string())); + t = "%F0%A4%AD%A2"; + assertEquals("%F0%A4%AD%A2", p.parse(PartType.HEADER, t, bs.object())); + assertEquals("%F0%A4%AD%A2", p.parse(PartType.HEADER, t, bs.string())); + + // 2nd level + t = "?%F0%A4%AD%A2=%F0%A4%AD%A2"; + m = (Map)p.parse(t, Object.class); + assertEquals("ð¤¢", m.get("ð¤¢")); + + // 3rd level + t = "?%F0%A4%AD%A2=(%F0%A4%AD%A2=%F0%A4%AD%A2)"; + m = (Map)p.parse(t, Object.class); + assertEquals("ð¤¢", ((Map)m.get("ð¤¢")).get("ð¤¢")); + } + + //==================================================================================================== + // Test simple bean + //==================================================================================================== + @Test + public void testSimpleBean() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + A t; + + String s = "?f1=foo&f2=123"; + t = p.parse(s, A.class); + assertEquals("foo", t.f1); + assertEquals(123, t.f2); + + s = "(f1=foo,f2=123)"; + t = p.parse(PartType.HEADER, s, bs.getClassMeta(A.class)); + assertEquals("foo", t.f1); + assertEquals(123, t.f2); + + s = "('f1'='foo','f2'=123)"; + t = p.parse(PartType.HEADER, s, bs.getClassMeta(A.class)); + assertEquals("foo", t.f1); + assertEquals(123, t.f2); + } + + public static class A { + public String f1; + public int f2; + } + + //==================================================================================================== + // Test URL-encoded strings with no-value parameters. + //==================================================================================================== + @Test + public void testNoValues() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + ObjectMap m; + + String s = "?f1"; + m = p.parse(s, ObjectMap.class); + assertTrue(m.containsKey("f1")); + assertNull(m.get("f1")); + s = "?f1=f2&f3"; + m = p.parse(s, ObjectMap.class); + assertEquals("f2", m.get("f1")); + assertTrue(m.containsKey("f3")); + assertNull(m.get("f3")); + } + + //==================================================================================================== + // Test URL-encoded strings parsed into plain-text values using UrlEncodingParser.parseIntoSimpleMap(). + //==================================================================================================== + @Test + public void testParseIntoSimpleMap() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + Map<String,String[]> m; + + String s = "?f1=,()=&f2a=$b(true)&f2b=true&f3a=$n(123)&f3b=123&f4=$s(foo)"; + m = p.parseIntoSimpleMap(s, null); + assertEquals(",()=", m.get("f1")[0]); + assertEquals("$b(true)", m.get("f2a")[0]); + assertEquals("true", m.get("f2b")[0]); + assertEquals("$n(123)", m.get("f3a")[0]); + assertEquals("123", m.get("f3b")[0]); + assertEquals("$s(foo)", m.get("f4")[0]); + + s = "f1=v1&="; + m = p.parseIntoSimpleMap(s, null); + assertEquals("v1", m.get("f1")[0]); + assertEquals("", m.get("")[0]); + + s = "f1=v1&f2&f3"; + m = p.parseIntoSimpleMap(s, null); + assertEquals("v1", m.get("f1")[0]); + assertTrue(m.containsKey("f2")); + assertTrue(m.containsKey("f3")); + assertNull(m.get("f2")); + assertNull(m.get("f3")); + } + + //==================================================================================================== + // Test parsing URL-encoded strings with multiple values. + //==================================================================================================== + @Test + public void testParseIntoSimpleMapMultiValues() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + Map<String,String[]> m; + + String s = "?f1&f1&f2&f2=abc&f2=def&f2"; + m = p.parseIntoSimpleMap(s, null); + assertObjectEquals("{f1:null,f2:['abc','def']}", m); + } + + @Test + public void testEmptyString() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + + String s = ""; + B b = p.parse(s, B.class); + assertEquals("f1", b.f1); + } + + public static class B { + public String f1 = "f1"; + } + + //==================================================================================================== + // Test comma-delimited list parameters. + //==================================================================================================== + @Test + public void testCommaDelimitedLists() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + + String s = "?f1=1,2,3&f2=a,b,c&f3=true,false&f4=&f5"; + C c = p.parse(s, C.class); + assertObjectEquals("{f1:[1,2,3],f2:['a','b','c'],f3:[true,false],f4:[]}", c); + } + + public static class C { + public int[] f1; + public String[] f2; + public boolean[] f3; + public String[] f4; + public String[] f5; + } + + //==================================================================================================== + // Test comma-delimited list parameters with special characters. + //==================================================================================================== + @Test + public void testCommaDelimitedListsWithSpecialChars() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + String s; + C1 c; + + // In the string below, the ~ character should not be interpreted as an escape. + s = "?f1=a~b,a~b"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['a~b','a~b']}", c); + + s = "?f1=@(a~b,a~b)"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['a~b','a~b']}", c); + + s = "?f1=@('a~b','a~b')"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['a~b','a~b']}", c); + + s = "?f1=@('a~b','a~b')"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['a~b','a~b']}", c); + + s = "?f1=@('a~b','a~b')"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['a~b','a~b']}", c); + + s = "?f1=~~,~~"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['~','~']}", c); + + s = "?f1=@(~~,~~)"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['~','~']}", c); + + s = "?f1=@(~~~~~~,~~~~~~)"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['~~~','~~~']}", c); + + s = "?f1=@('~~~~~~','~~~~~~')"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['~~~','~~~']}", c); + + // The ~ should be treated as an escape if followed by any of the following characters: '~ + s = "?f1=~'~~,~'~~"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['\\'~','\\'~']}", c); + + s = "?f1=@(~'~~,~'~~)"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['\\'~','\\'~']}", c); + + s = "?f1=@('~'~~','~'~~')"; + c = p.parse(s, C1.class); + assertObjectEquals("{f1:['\\'~','\\'~']}", c); + + s = "?a~b=a~b"; + ObjectMap m = p.parse(s, ObjectMap.class); + assertEquals("{'a~b':'a~b'}", m.toString()); + + s = "?'a~b'='a~b'"; + m = p.parse(s, ObjectMap.class); + assertEquals("{'a~b':'a~b'}", m.toString()); + + s = "?~~=~~"; + m = p.parse(s, ObjectMap.class); + assertEquals("{'~':'~'}", m.toString()); + + s = "?'~~'='~~'"; + m = p.parse(s, ObjectMap.class); + assertEquals("{'~':'~'}", m.toString()); + + s = "?~~~~~~=~~~~~~"; + m = p.parse(s, ObjectMap.class); + assertEquals("{'~~~':'~~~'}", m.toString()); + + s = "?'~~~~~~'='~~~~~~'"; + m = p.parse(s, ObjectMap.class); + assertEquals("{'~~~':'~~~'}", m.toString()); + } + + public static class C1 { + public String[] f1; + } + + //==================================================================================================== + // Test comma-delimited list parameters. + //==================================================================================================== + @Test + public void testWhitespace() throws Exception { + UrlEncodingParser p = UrlEncodingParser.DEFAULT; + String s; + ObjectMap m; + + s = "?f1=foo\n\t&f2=bar\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("{f1:'foo',f2:'bar'}", m.toString()); + + s = "?f1='\n\t'&f2='\n\t'"; + m = p.parse(s, ObjectMap.class); + assertEquals("\n\t", m.getString("f1")); + assertEquals("\n\t", m.getString("f2")); + + s = "?f1='\n\t'\n\t&f2='\n\t'\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("\n\t", m.getString("f1")); + assertEquals("\n\t", m.getString("f2")); + assertEquals("{f1:'\\n\\t',f2:'\\n\\t'}", m.toString()); // Note that JsonSerializer escapes newlines and tabs. + + s = "?f1='\n\t'\n\t&f2='\n\t'\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("\n\t", m.getString("f1")); + assertEquals("\n\t", m.getString("f2")); + assertEquals("{f1:'\\n\\t',f2:'\\n\\t'}", m.toString()); // Note that JsonSerializer escapes newlines and tabs. + + s = "?f1=(\n\tf1a=a,\n\tf1b=b\n\t)\n\t&f2=(\n\tf2a=a,\n\tf2b=b\n\t)\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("{f1:{f1a:'a',f1b:'b'},f2:{f2a:'a',f2b:'b'}}", m.toString()); // Note that JsonSerializer escapes newlines and tabs. + D d = p.parse(s, D.class); + assertObjectEquals("{f1:{f1a:'a',f1b:'b'},f2:{f2a:'a',f2b:'b'}}", d); // Note that JsonSerializer escapes newlines and tabs. + + s = "?f1=(\n\tf1a='\n\t',\n\tf1b='\n\t'\n\t)\n\t&f2=(\n\tf2a='\n\t',\n\tf2b='\n\t'\n\t)\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("{f1:{f1a:'\\n\\t',f1b:'\\n\\t'},f2:{f2a:'\\n\\t',f2b:'\\n\\t'}}", m.toString()); // Note that JsonSerializer escapes newlines and tabs. + d = p.parse(s, D.class); + assertObjectEquals("{f1:{f1a:'\\n\\t',f1b:'\\n\\t'},f2:{f2a:'\\n\\t',f2b:'\\n\\t'}}", d); // Note that JsonSerializer escapes newlines and tabs. + + s = "?f1=@(\n\tfoo,\n\tbar\n\t)\n\t&f2=@(\n\tfoo,\n\tbar\n\t)\n\t"; + m = p.parse(s, ObjectMap.class); + assertEquals("{f1:['foo','bar'],f2:['foo','bar']}", m.toString()); // Note that JsonSerializer escapes newlines and tabs. + + s = "f1=a,\n\tb,\n\tc\n\t&f2=1,\n\t2,\n\t3\n\t&f3=true,\n\tfalse\n\t"; + E e = p.parse(s, E.class); + assertObjectEquals("{f1:['a','b','c'],f2:[1,2,3],f3:[true,false]}", e); + + s = "f1=a%2C%0D%0Ab%2C%0D%0Ac%0D%0A&f2=1%2C%0D%0A2%2C%0D%0A3%0D%0A&f3=true%2C%0D%0Afalse%0D%0A"; + e = p.parse(s, E.class); + assertObjectEquals("{f1:['a','b','c'],f2:[1,2,3],f3:[true,false]}", e); + } + + public static class D { + public D1 f1; + public D2 f2; + } + + public static class D1 { + public String f1a, f1b; + } + + public static class D2 { + public String f2a, f2b; + } + + public static class E { + public String[] f1; + public int[] f2; + public boolean[] f3; + } + + //==================================================================================================== + // Multi-part parameters on beans via URLENC_expandedParams + //==================================================================================================== + @Test + public void testMultiPartParametersOnBeansViaProperty() throws Exception { + UrlEncodingParser p; + String in; + + p = new UrlEncodingParserBuilder().expandedParams(true).build(); + in = "" + + "f01=a&f01=b" + + "&f02=c&f02=d" + + "&f03=1&f03=2" + + "&f04=3&f04=4" + + "&f05=@(e,f)&f05=@(g,h)" + + "&f06=@(i,j)&f06=@(k,l)" + + "&f07=(a=a,b=1,c=true)&f07=(a=b,b=2,c=false)" + + "&f08=(a=a,b=1,c=true)&f08=(a=b,b=2,c=false)" + + "&f09=@((a=a,b=1,c=true))&f09=@((a=b,b=2,c=false))" + + "&f10=@((a=a,b=1,c=true))&f10=@((a=b,b=2,c=false))" + + "&f11=a&f11=b" + + "&f12=c&f12=d" + + "&f13=1&f13=2" + + "&f14=3&f14=4" + + "&f15=@(e,f)&f15=@(g,h)" + + "&f16=@(i,j)&f16=@(k,l)" + + "&f17=(a=a,b=1,c=true)&f17=(a=b,b=2,c=false)" + + "&f18=(a=a,b=1,c=true)&f18=(a=b,b=2,c=false)" + + "&f19=@((a=a,b=1,c=true))&f19=@((a=b,b=2,c=false))" + + "&f20=@((a=a,b=1,c=true))&f20=@((a=b,b=2,c=false))"; + + DTOs.B t = p.parse(in, DTOs.B.class); + String e = "{" + + "f01:['a','b']," + + "f02:['c','d']," + + "f03:[1,2]," + + "f04:[3,4]," + + "f05:[['e','f'],['g','h']]," + + "f06:[['i','j'],['k','l']]," + + "f07:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f08:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f09:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f10:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f11:['a','b']," + + "f12:['c','d']," + + "f13:[1,2]," + + "f14:[3,4]," + + "f15:[['e','f'],['g','h']]," + + "f16:[['i','j'],['k','l']]," + + "f17:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f18:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f19:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f20:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]" + +"}"; + assertSortedObjectEquals(e, t); + } + + //==================================================================================================== + // Multi-part parameters on beans via @UrlEncoding.expandedParams on class + //==================================================================================================== + @Test + public void testMultiPartParametersOnBeansViaAnnotationOnClass() throws Exception { + UrlEncodingParser p; + String in; + p = UrlEncodingParser.DEFAULT; + in = "" + + "f01=a&f01=b" + + "&f02=c&f02=d" + + "&f03=1&f03=2" + + "&f04=3&f04=4" + + "&f05=@(e,f)&f05=@(g,h)" + + "&f06=@(i,j)&f06=@(k,l)" + + "&f07=(a=a,b=1,c=true)&f07=(a=b,b=2,c=false)" + + "&f08=(a=a,b=1,c=true)&f08=(a=b,b=2,c=false)" + + "&f09=@((a=a,b=1,c=true))&f09=@((a=b,b=2,c=false))" + + "&f10=@((a=a,b=1,c=true))&f10=@((a=b,b=2,c=false))" + + "&f11=a&f11=b" + + "&f12=c&f12=d" + + "&f13=1&f13=2" + + "&f14=3&f14=4" + + "&f15=@(e,f)&f15=@(g,h)" + + "&f16=@(i,j)&f16=@(k,l)" + + "&f17=(a=a,b=1,c=true)&f17=(a=b,b=2,c=false)" + + "&f18=(a=a,b=1,c=true)&f18=(a=b,b=2,c=false)" + + "&f19=@((a=a,b=1,c=true))&f19=@((a=b,b=2,c=false))" + + "&f20=@((a=a,b=1,c=true))&f20=@((a=b,b=2,c=false))"; + + DTOs.C t = p.parse(in, DTOs.C.class); + String e = "{" + + "f01:['a','b']," + + "f02:['c','d']," + + "f03:[1,2]," + + "f04:[3,4]," + + "f05:[['e','f'],['g','h']]," + + "f06:[['i','j'],['k','l']]," + + "f07:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f08:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f09:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f10:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f11:['a','b']," + + "f12:['c','d']," + + "f13:[1,2]," + + "f14:[3,4]," + + "f15:[['e','f'],['g','h']]," + + "f16:[['i','j'],['k','l']]," + + "f17:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f18:[{a:'a',b:1,c:true},{a:'b',b:2,c:false}]," + + "f19:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]," + + "f20:[[{a:'a',b:1,c:true}],[{a:'b',b:2,c:false}]]" + +"}"; + assertSortedObjectEquals(e, t); + } +} \ No newline at end of file
