/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.test.ext.jaxrs.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import junit.framework.AssertionFailedError; import org.restlet.ext.jaxrs.internal.util.EncodeOrCheck; import org.restlet.test.RestletTestCase; /** * @author Stephan Koops * @see EncodeOrCheck */ @SuppressWarnings("all") public class EncodeOrCheckTests extends RestletTestCase { static final Method FRAGMENT; static final Method FULL_MATRIX; static final Method FULL_QUERY; static final Method HOST; static final Method NAME_OR_VALUE; static final Method PATH_SEGMENT_WITH_MATRIX; static final Method PATH_WITHOUT_MATRIX; static final Method SCHEME; static final Method USER_INFO; static { try { FRAGMENT = EncodeOrCheck.class.getMethod("fragment", CharSequence.class); FULL_MATRIX = EncodeOrCheck.class.getMethod("fullMatrix", CharSequence.class); FULL_QUERY = EncodeOrCheck.class.getMethod("fullQuery", CharSequence.class, Boolean.TYPE); HOST = EncodeOrCheck.class.getMethod("host", String.class); NAME_OR_VALUE = EncodeOrCheck.class.getMethod("nameOrValue", Object.class, Boolean.TYPE, String.class); PATH_SEGMENT_WITH_MATRIX = EncodeOrCheck.class.getMethod( "pathSegmentWithMatrix", CharSequence.class, Boolean.TYPE); PATH_WITHOUT_MATRIX = EncodeOrCheck.class.getMethod( "pathWithoutMatrix", CharSequence.class); SCHEME = EncodeOrCheck.class.getMethod("scheme", String.class); USER_INFO = EncodeOrCheck.class.getMethod("userInfo", CharSequence.class, Boolean.TYPE); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } /** * @param method * static method. The in value is the first parameter. If the * method has two or three parameters, the second is the encode * value. If it has three arguments, a generic error message is * used for it. * @param in * @param encode * must not be null, if the method has more than one argument. * @param out * if null, an IllegalArgumentException must be thrown * @throws IllegalAccessException * @throws IllegalArgumentException * @throws RuntimeException */ private void check(Method method, String in, Boolean encode, String out) { Object result; try { final int paramCount = method.getParameterTypes().length; if (paramCount == 0) { throw new AssertionFailedError( ("The method " + method + " must have between 1 and 3 parameters")); } else if (paramCount == 1) { result = method.invoke(null, in); } else if ((paramCount == 2) && (encode != null)) { result = method.invoke(null, in, encode); } else if ((paramCount == 3) && (encode != null)) { result = method.invoke(null, in, encode, "{generic test error message}"); } else { throw new AssertionFailedError( ("The method " + method + " has to much parameters")); } if (paramCount > 1) { if (out == null) { fail("must throw an IllegalArgumentException for \"" + in + "\" and encode = " + encode); } assertEquals(out, result != null ? result.toString() : null); } } catch (InvocationTargetException e) { if (!(e.getCause() instanceof IllegalArgumentException)) { throw (RuntimeException) e.getCause(); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** encoding necessary; not encoding must throw an exception */ void checkEncoding(Method method, String in, String encodedOut) { check(method, in, true, encodedOut); check(method, in, false, null); } void checkForInvalidCharFail(String uriPart) { try { EncodeOrCheck.checkForInvalidUriChars(uriPart, -1, ""); fail("\"" + uriPart + "\" contains an invalid char. The test must fail"); } catch (IllegalArgumentException e) { // wonderful } } /** * in String full invalid */ void checkInvalid(Method method, String in) { check(method, in, true, null); check(method, in, false, null); } /** * No encoding necessary */ void checkNoEncode(Method method, String testString) { check(method, testString, true, testString); check(method, testString, false, testString); } public void testCheckForInvalidUriChars() { final String allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{}"; EncodeOrCheck.checkForInvalidUriChars(allowed, -1, ""); EncodeOrCheck.checkForInvalidUriChars("aaaaa", -1, ""); EncodeOrCheck.checkForInvalidUriChars("\\\\\\", -1, ""); checkForInvalidCharFail("a:a"); checkForInvalidCharFail("a:1"); checkForInvalidCharFail("/a:"); checkForInvalidCharFail("a:"); checkForInvalidCharFail("/"); checkForInvalidCharFail(" "); checkForInvalidCharFail("\0"); checkForInvalidCharFail("abc{ }kg jj"); EncodeOrCheck.checkForInvalidUriChars("abc{ }kgjj", -1, "test"); } public void testEncodePathWithoutMatrix() { EncodeOrCheck.pathWithoutMatrix(""); EncodeOrCheck.pathWithoutMatrix("%20"); } public void testFragment() { checkNoEncode(FRAGMENT, EncodeOrCheck.UNRESERVED); checkInvalid(FRAGMENT, "{}"); checkNoEncode(FRAGMENT, "dfd{ %K}7"); checkInvalid(FRAGMENT, "dfd{ { %K}}}7"); checkInvalid(FRAGMENT, "dfd{}7"); } public void testFullMatrixes() { xtestFullQueryOrMatrix(FULL_MATRIX, ';', '&'); checkEncoding(FULL_MATRIX, "jhg jk", "jhg%20jk"); } public void testFullQueries() { xtestFullQueryOrMatrix(FULL_QUERY, '&', ';'); checkEncoding(FULL_QUERY, "jhg jk", "jhg+jk"); } public void testHost() throws Exception { checkNoEncode(HOST, "a"); checkNoEncode(HOST, "a{sdf}f"); checkNoEncode(HOST, "a{ }f"); checkEncoding(HOST, "a{ } f", "a{ }%20f"); checkNoEncode(HOST, "98.76.54.32"); checkNoEncode(HOST, "9876:fg12::5432"); // host = IP-literal / IPv4address / reg-name // IP-literal = "[" ( IPv6address / IPvFuture ) "]" // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) // NICE also allow national special chars etc. in a host } public void testNameOrValue() { checkNoEncode(NAME_OR_VALUE, ""); checkNoEncode(NAME_OR_VALUE, "sdf"); assertEquals("sdf%20hfdf", EncodeOrCheck.nameOrValue("sdf%20hfdf", false, "guj")); assertEquals("sdf%2520hfdf", EncodeOrCheck.nameOrValue("sdf%20hfdf", true, "guj")); checkEncoding(NAME_OR_VALUE, "abc def", "abc%20def"); final StringBuilder reservedEnc = new StringBuilder(); for (int i = 0; i < EncodeOrCheck.RESERVED.length(); i++) { EncodeOrCheck.toHex(EncodeOrCheck.RESERVED.charAt(i), reservedEnc); } checkEncoding(NAME_OR_VALUE, EncodeOrCheck.RESERVED, reservedEnc.toString()); } public void testPathSegmentWithMatrix() { checkNoEncode(PATH_SEGMENT_WITH_MATRIX, ""); checkNoEncode(PATH_SEGMENT_WITH_MATRIX, "sdf"); checkEncoding(PATH_SEGMENT_WITH_MATRIX, "abc def", "abc%20def"); checkNoEncode(PATH_SEGMENT_WITH_MATRIX, "abc;1298=213"); } public void testSchemeCheck() { // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) EncodeOrCheck.scheme("f"); } public void testUserInfo() { checkNoEncode(USER_INFO, ""); // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) checkNoEncode(USER_INFO, "a"); checkNoEncode(USER_INFO, "a{g}a"); checkNoEncode(USER_INFO, "a{g }a"); checkNoEncode(USER_INFO, "user:password"); checkEncoding(USER_INFO, "a{g } a", "a{g }%20a"); } /** * @param delim * ';' or '&' * @param nonDelim * '&' or ';' */ private void xtestFullQueryOrMatrix(Method method, char delim, char nonDelim) { final String nonDelimStr = (nonDelim == ';' ? "%3B" : "%26"); final String str = "jshfk=kzi" + delim + "hk=" + delim + "k" + delim + delim; checkNoEncode(method, str); checkEncoding(method, str + nonDelim, str + nonDelimStr); checkNoEncode(method, ""); // LATER is the following right? checkEncoding(method, "%20", "%2520"); checkEncoding(method, delim + "=" + nonDelim + "?", delim + "=" + nonDelimStr + "%3F"); checkNoEncode(method, "{s&?df}"); checkNoEncode(method, "{sdf}"); checkNoEncode(method, delim + "{sdf}"); checkInvalid(method, "gg{nk{}}"); checkInvalid(method, "gg{nk{"); checkInvalid(method, "gg}ff"); } }