blob: f9ff36521fb9dd584847e04aa641816fb39207e0 [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.server.rpc;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializedTypeViolationException;
import junit.framework.TestCase;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
/**
* Array test cases for the type checking code found in server-side RPC
* deserialization.
*/
@SuppressWarnings("rawtypes")
public class RPCTypeCheckArraysTest extends TestCase {
/*
* Test that primitive arrays cannot be replaced by non-array types
* - int for int[]: testPrimitiveSpoofingArray
* - String for String[]: testPrimitiveSpoofingArray
* - HashSet for int[]: testHashSetSpoofingArray
* - HashSet for String[]: testHashSetSpoofingArray
* - HashSet for AClass[]: testHashSetSpoofingClassArray
*
* Test that non-array-type cannot be replaced by array types
* - int[] for int: testArraysSpoofingObjects
* - String[] for String: testArraytestArraysSpoofingObjects
* - String[] for AClass: testArraysSpoofingObjects
*
* Test generics parameterized by arrays:
* - HashMap<String, int[]>: testArrayAsGeneric
* - HashMap<String, Integer[]>: testArrayAsGeneric
* - HashMap<String, AClass[]>: testArrayAsGeneric
*
* Test arrays of generics:
* - List<Integer>[]: testArrayOfGeneric
* - List[]: testArrayOfGeneric
* - List<? extends HashSet<Integer>>[]: testArrayOfGeneric
*/
/**
* A class for testing spoofing of arrays.
*/
public static class ArraysParamTestClass implements RemoteService {
@SuppressWarnings("unused")
public static void testArrays(int[] intArg, String[] stringArg) { }
@SuppressWarnings("unused")
public static void testAClassArray(RPCTypeCheckTest.AClass[] arg1) { }
@SuppressWarnings("unused")
public static void testGenericsArrays(
HashMap<String, int[]> arg1,
HashMap<String, Integer[]> arg2,
HashMap<String, RPCTypeCheckTest.AClass[]> arg3) { }
@SuppressWarnings("unused")
public static void testArrayOfGeneric(List<Integer>[] arg1) { }
@SuppressWarnings("unused")
public static void testArrayOfGenericRaw(List[] arg1) { }
@SuppressWarnings("unused")
public static void testArrayOfGenericWildcard(List<? extends HashSet<Integer>>[] arg1) { }
}
private static String generateArrayGenericsA() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testGenericsArrays");
HashMap<String, HashSet> arg1 = new HashMap<String, HashSet>();
arg1.put("foo", RPCTypeCheckFactory.generateTestHashSet());
strFactory.write(arg1);
HashMap<String, Integer[]> arg2 = new HashMap<String, Integer[]>();
Integer[] entry1 = new Integer[] {12345, 67890};
arg2.put("bar", entry1);
strFactory.write(arg2);
HashMap<String, RPCTypeCheckTest.AClass[]> arg3 =
new HashMap<String, RPCTypeCheckTest.AClass[]>();
RPCTypeCheckTest.AClass[] entry2 = new RPCTypeCheckTest.AClass[2];
entry2[0] = new RPCTypeCheckTest.AClass(234);
entry2[1] = new RPCTypeCheckTest.AClass(567);
arg3.put("baz", entry2);
strFactory.write(arg3);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateArrayGenericsB() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testGenericsArrays");
HashMap<String, int[]> arg1 = new HashMap<String, int[]>();
int[] entry1 = new int[] { 234, 567 };
arg1.put("foo", entry1);
strFactory.write(arg1);
HashMap<String, HashSet[]> arg2 = new HashMap<String, HashSet[]>();
HashSet[] entry2 = new HashSet[] { RPCTypeCheckFactory.generateTestHashSet() };
arg2.put("bar", entry2);
strFactory.write(arg2);
HashMap<String, RPCTypeCheckTest.AClass[]> arg3 =
new HashMap<String, RPCTypeCheckTest.AClass[]>();
RPCTypeCheckTest.AClass[] entry3 = new RPCTypeCheckTest.AClass[2];
entry3[0] = new RPCTypeCheckTest.AClass(234);
entry3[1] = new RPCTypeCheckTest.AClass(567);
arg3.put("baz", entry3);
strFactory.write(arg3);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateArrayGenericsC() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testGenericsArrays");
HashMap<String, int[]> arg1 = new HashMap<String, int[]>();
int[] entry1 = new int[] { 234, 567 };
arg1.put("foo", entry1);
strFactory.write(arg1);
HashMap<String, Integer[]> arg2 = new HashMap<String, Integer[]>();
Integer[] entry2 = new Integer[] {12345, 67890};
arg2.put("bar", entry2);
strFactory.write(arg2);
HashMap<String, HashSet[]> arg3 = new HashMap<String, HashSet[]>();
HashSet[] entry3 = new HashSet[] { RPCTypeCheckFactory.generateTestHashSet() };
arg3.put("baz", entry3);
strFactory.write(arg3);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateArrayOfGenericsA(String methodName) {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, methodName);
HashMap<String, HashSet> arg1 = new HashMap<String, HashSet>();
arg1.put("foo", RPCTypeCheckFactory.generateTestHashSet());
strFactory.write(arg1);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateArrayOfGenericsB(String methodName) {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, methodName);
LinkedList[] arg1 = new LinkedList[1];
LinkedList<LinkedHashSet> list = new LinkedList<LinkedHashSet>();
list.add(RPCTypeCheckFactory.generateTestLinkedHashSet());
arg1[0] = list;
strFactory.write(arg1);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
@SuppressWarnings("unchecked")
private static String generateArrayOfGenericsC(String methodName) {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, methodName);
LinkedList<HashSet<Integer>>[] arg1 = new LinkedList[1];
LinkedList<HashSet<Integer>> list = new LinkedList<HashSet<Integer>>();
HashSet<Integer> listElmt = new HashSet<Integer>();
listElmt.add(12345);
listElmt.add(67890);
list.add(listElmt);
arg1[0] = list;
strFactory.write(arg1);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateHashSetSpoofingClassArray() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testAClassArray");
HashSet<Integer> hashSet = new HashSet<Integer>();
hashSet.add(12345);
hashSet.add(67890);
strFactory.write(hashSet);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateHashSetSpoofingIntArray() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testArrays");
HashSet<Integer> hashSet = new HashSet<Integer>();
hashSet.add(12345);
hashSet.add(67890);
strFactory.write(hashSet);
String[] stringArray = new String[]{"foo", "bar"};
strFactory.write(stringArray);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateHashSetSpoofingStringArray() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testArrays");
int[] intArray = new int[]{12345, 67890};
strFactory.write(intArray);
HashSet<Integer> hashSet = new HashSet<Integer>();
hashSet.add(12345);
hashSet.add(67890);
strFactory.write(hashSet);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateIntArraySpoofingInt() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(RPCTypeCheckTest.PrimitiveParamTestClass.class, "testIntString");
int[] iArray = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
strFactory.write(iArray);
strFactory.write("foo");
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateIntSpoofingIntArray() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testArrays");
int i = 12345;
strFactory.write(i);
String[] stringArray = new String[]{"foo", "bar"};
strFactory.write(stringArray);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateStringArraySpoofingClass() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(RPCTypeCheckTest.ClassesParamTestClass.class, "testAClass");
String a = "a";
String[] stringArray = new String[]{a, a, a, a, a, a, a, a, a, a, a, a, a, a};
strFactory.write(stringArray);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateStringArraySpoofingString() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(RPCTypeCheckTest.PrimitiveParamTestClass.class, "testIntString");
int i = 12345;
strFactory.write(i);
String a = "a";
String[] stringArray = new String[]{a, a, a, a, a, a, a, a, a, a, a, a, a, a};
strFactory.write(stringArray);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
private static String generateStringSpoofingStringArray() {
try {
RPCTypeCheckFactory strFactory =
new RPCTypeCheckFactory(ArraysParamTestClass.class, "testArrays");
int[] arg1 = new int[]{12345, 67890};
strFactory.write(arg1);
String arg2 = "bar";
strFactory.write(arg2);
return strFactory.toString();
} catch (Exception e) {
fail(e.getMessage());
return null;
}
}
/**
* This checks that arrays as generic types are checked correctly.
*/
public void testArrayGenerics() {
try {
RPC.decodeRequest(generateArrayGenericsA());
fail("Expected IncompatibleRemoteServiceException from testArrayGenerics (1)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*int.*"));
}
try {
RPC.decodeRequest(generateArrayGenericsB());
fail("Expected IncompatibleRemoteServiceException from testArrayGenerics (2)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*Integer.*"));
}
try {
RPC.decodeRequest(generateArrayGenericsC());
fail("Expected IncompatibleRemoteServiceException from testArrayGenerics (3)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*AClass.*"));
}
}
/**
* This checks that arrays of generic types are checked correctly.
*/
public void testArrayOfGenerics() {
try {
RPC.decodeRequest(generateArrayOfGenericsC("testArrayOfGenericRaw"));
// Expect to pass
} catch (Exception e) {
fail("Unexpected exception from testArrayOfGenerics (0): " + e.getMessage());
}
try {
RPC.decodeRequest(generateArrayOfGenericsA("testArrayOfGeneric"));
fail("Expected IncompatibleRemoteServiceException from testArrayOfGenerics (1)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashMap.*List.*"));
}
try {
RPC.decodeRequest(generateArrayOfGenericsB("testArrayOfGeneric"));
fail("Expected IncompatibleRemoteServiceException from testArrayOfGenerics (2)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*Integer.*"));
}
try {
RPC.decodeRequest(generateArrayOfGenericsA("testArrayOfGenericWildcard"));
fail("Expected IncompatibleRemoteServiceException from testArrayOfGenerics (3)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashMap.*List.*"));
}
try {
RPC.decodeRequest(generateArrayOfGenericsC("testArrayOfGenericWildcard"));
} catch (Exception e) {
fail("Unexpected Exception from testArrayOfGenerics (4): " + e.getMessage());
}
try {
RPC.decodeRequest(generateArrayOfGenericsB("testArrayOfGenericWildcard"));
fail("Expected IncompatibleRemoteServiceException from testArrayOfGenerics (5)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*Integer.*"));
}
}
/**
* This checks that arrays cannot be used in place of primitives.
*/
public void testArraysSpoofingObjects() {
try {
RPC.decodeRequest(generateIntArraySpoofingInt());
fail("Expected ArrayIndexOutOfBoundsException from testArraysSpoofingPrimitives (1)");
} catch (Exception e) {
// Expected to get here
assertTrue(e instanceof ArrayIndexOutOfBoundsException);
}
try {
RPCRequest result = RPC.decodeRequest(generateStringArraySpoofingString());
assertTrue(result.getParameters()[1].toString().matches(".*\\[Ljava.lang.String.*"));
} catch (Exception e) {
fail("Unexpected Exception from testArraysSpoofingPrimitives (2)");
}
try {
RPC.decodeRequest(generateStringArraySpoofingClass());
fail("Expected IncompatibleRemoteServiceException from testArraysSpoofingPrimitives (3)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*\\[Ljava.lang.String.*AClass.*"));
}
}
/**
* This checks situations in which an RPC message is modified to replace
* arguments of a primitive type with another primitive type.
*/
public void testHashSetSpoofingArray() {
try {
RPC.decodeRequest(generateHashSetSpoofingIntArray());
fail("Expected IncompatibleRemoteServiceException from testHashSetSpoofingArray (1)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here. When the int array is processed, it reads the
// HashSet class and fails to know what it is, because it is not the
// way an int would be serialized in this context.
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*\\[I.*"));
}
try {
RPC.decodeRequest(generateHashSetSpoofingStringArray());
fail("Expected IncompatibleRemoteServiceException from testHashSetSpoofingArray (2)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*String.*"));
}
}
/**
* This checks situations in which an RPC message is modified to replace an
* array of objects with a HashSet (custom serialized container type).
*/
public void testHashSetSpoofingClassArray() {
try {
RPC.decodeRequest(generateHashSetSpoofingClassArray());
fail("Expected IncompatibleRemoteServiceException from testHashSetSpoofingClassArray");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here.
assertEquals(SerializedTypeViolationException.class, e.getCause().getClass());
assertTrue(e.getCause().getMessage().matches(".*HashSet.*AClass.*"));
}
}
/**
* This checks situations in which an RPC message is modified to replace
* arguments of a primitive type with another primitive type.
*/
public void testPrimitiveSpoofingArray() {
try {
RPC.decodeRequest(generateIntSpoofingIntArray());
fail("Expected IncompatibleRemoteServiceException from testPrimitiveSpoofingArray (1)");
} catch (Exception e) {
// Expected to get here. When the int array value is processed, it reads
// the
// integer value and tries to look it up as a class string, only to run
// out
// of bounds in the string table.
assertTrue(e instanceof ArrayIndexOutOfBoundsException);
}
try {
RPC.decodeRequest(generateStringSpoofingStringArray());
fail("Expected IncompatibleRemoteServiceException from testPrimitiveSpoofingArray (2)");
} catch (IncompatibleRemoteServiceException e) {
// Expected to get here
assertEquals(SerializationException.class, e.getCause().getClass());
}
}
}