// *************************************************************************************************************************** | |
// * 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; | |
//==================================================================================================== | |
// 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.parsePart(t, Object.class)); | |
assertEquals("a", p.parsePart(t, String.class)); | |
t = "'a'"; | |
assertEquals("a", p.parsePart(t, String.class)); | |
assertEquals("a", p.parsePart(t, Object.class)); | |
t = " 'a' "; | |
assertEquals("a", p.parsePart(t, String.class)); | |
// 2nd level | |
t = "?a=a"; | |
assertEquals("a", ((Map)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.parsePart(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")); | |
assertEquals("%00", m.get("f")); | |
t = "(a=b,c=123,d=false,e=true,f=null)"; | |
m = p.parsePart(t, 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.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class); | |
assertTrue(l.isEmpty()); | |
t = " @( ) "; | |
l = p.parsePart(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 = "_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.parsePart(t, Object.class); | |
assertTrue(l.size() == 1); | |
l = (List)l.get(0); | |
assertTrue(l.isEmpty()); | |
t = "@(@())"; | |
l = (List)p.parsePart(t, 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.parsePart(t, Object.class); | |
assertTrue(l.size() == 1); | |
assertEquals("", l.get(0)); | |
t = "@('')"; | |
l = (List)p.parsePart(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 = "_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.parsePart(t, Object.class); | |
assertTrue(l.size() == 3); | |
assertEquals("", l.get(0)); | |
assertEquals("", l.get(1)); | |
assertEquals("", l.get(2)); | |
t = "@('','','')"; | |
l = (List)p.parsePart(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 = "_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.parsePart(t, Object.class)); | |
t = "'\u0000'"; | |
assertEquals("\u0000", p.parsePart(t, String.class)); | |
assertEquals("\u0000", p.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class); | |
assertEquals(Boolean.FALSE, b); | |
b = p.parsePart(t, Boolean.class); | |
assertEquals(Boolean.FALSE, b); | |
t = "false"; | |
b = p.parsePart(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, 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.parsePart(t, Object.class); | |
assertEquals(123, i.intValue()); | |
i = p.parsePart(t, Integer.class); | |
assertEquals(123, i.intValue()); | |
d = p.parsePart(t, Double.class); | |
assertEquals(123, d.intValue()); | |
f = p.parsePart(t, Float.class); | |
assertEquals(123, f.intValue()); | |
t = "123"; | |
i = p.parsePart(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()); | |
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.parsePart(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 = "_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.parsePart(t, Object.class)); | |
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.parsePart(t, Object.class)); | |
assertEquals("x%7B%7D%7C%5C%5E%5B%5D%60%3C%3E%23%25%22%26%2B", p.parsePart(t, String.class)); | |
// 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.parsePart(t, Object.class)); | |
t = "_value='x~~$~~,~~(~~)'"; | |
assertEquals("x~$~,~(~)", p.parse(t, Object.class)); | |
t = "'x~~$~~,~~(~~)'"; | |
assertEquals("x~$~,~(~)", p.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class)); | |
t = "'x%3D'"; | |
assertEquals("x%3D", p.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class)); | |
assertEquals("()", p.parsePart(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 = "_value=$a"; | |
assertEquals("$a", p.parse(t, Object.class)); | |
t = "_value=$a"; | |
assertEquals("$a", p.parse(t, Object.class)); | |
t = "$a"; | |
assertEquals("$a", p.parsePart(t, Object.class)); | |
t = "$a"; | |
assertEquals("$a", p.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class)); | |
t = "'\n'"; | |
assertEquals("\n", p.parsePart(t, Object.class)); | |
// 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.parsePart(t, Object.class)); | |
assertEquals("¢", p.parsePart(t, String.class)); | |
t = "%C2%A2"; | |
assertEquals("%C2%A2", p.parsePart(t, Object.class)); | |
assertEquals("%C2%A2", p.parsePart(t, String.class)); | |
// 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.parsePart(t, Object.class)); | |
assertEquals("€", p.parsePart(t, String.class)); | |
t = "%E2%82%AC"; | |
assertEquals("%E2%82%AC", p.parsePart(t, Object.class)); | |
assertEquals("%E2%82%AC", p.parsePart(t, String.class)); | |
// 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.parsePart(t, Object.class)); | |
assertEquals("ð¤¢", p.parsePart(t, String.class)); | |
t = "%F0%A4%AD%A2"; | |
assertEquals("%F0%A4%AD%A2", p.parsePart(t, Object.class)); | |
assertEquals("%F0%A4%AD%A2", p.parsePart(t, String.class)); | |
// 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.parsePart(s, A.class); | |
assertEquals("foo", t.f1); | |
assertEquals(123, t.f2); | |
s = "('f1'='foo','f2'=123)"; | |
t = p.parsePart(s, 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); | |
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); | |
assertEquals("v1", m.get("f1")[0]); | |
assertEquals("", m.get("")[0]); | |
s = "f1=v1&f2&f3"; | |
m = p.parseIntoSimpleMap(s); | |
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); | |
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); | |
} | |
} |