/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * 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.hazelcast.nio.serialization.impl; import com.hazelcast.config.Config; import com.hazelcast.core.IMap; import com.hazelcast.instance.HazelcastInstanceProxy; import com.hazelcast.internal.serialization.impl.SerializationServiceV1; import com.hazelcast.map.AbstractEntryProcessor; import com.hazelcast.map.impl.LazyMapEntry; import com.hazelcast.nio.serialization.Data; import com.hazelcast.nio.serialization.Portable; import com.hazelcast.nio.serialization.PortableReader; import com.hazelcast.query.impl.getters.MultiResult; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import com.hazelcast.util.ExceptionUtil; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import java.io.IOException; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.GroupPortable; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.BooleanArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.ByteArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.CharArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.DoubleArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.FloatArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.Generic; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.IntArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.LongArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.Portable; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.PortableArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.ShortArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.UTF; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.UTFArray; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.getArrayMethodFor; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.getPrimitiveArrays; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.Method.getPrimitives; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.NestedGroupPortable; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.PrimitivePortable; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.PrimitivePortable.Init.FULL; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.PrimitivePortable.Init.NONE; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.PrimitivePortable.Init.NULL; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.TestPortableFactory; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.group; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.nested; import static com.hazelcast.nio.serialization.impl.DefaultPortableReaderTestStructure.prim; import static java.util.Arrays.asList; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.isA; import static org.junit.Assert.assertThat; /** * Tests that verifies the behavior of the DefaultPortableReader. * All tests cases are generated, since there's a lot of possible cases due to the long lists of read* method on the reader. * * The test is parametrised with 4 parameters * Each test execution runs one read operation on the reader. * * The rationale behind these tests is to cover all possible combinations of reads using nested paths and quantifiers * (number or any) with all possible portable types. It's impossible to do it manually, since there's 20 supported * types and a read method for each one of them. * * Each test case is documented, plus each test outputs it's scenario in a readable way, so you it's easy to follow * the test case while you run it. Also each test case shows in which method it is generated. * * IF YOU SEE A FAILURE HERE: * - check the test output - analyse the test scenario * - check in which method the scenario is generated - narrow down the scope of the tests run */ @RunWith(Parameterized.class) @Category({QuickTest.class, ParallelTest.class}) public class DefaultPortableReaderSpecTest extends HazelcastTestSupport { private static final PrimitivePortable P_NON_EMPTY = new PrimitivePortable(0, PrimitivePortable.Init.FULL); private static final GroupPortable G_NON_EMPTY = group(FULL); private static final NestedGroupPortable N_NON_EMPTY = nested(new Portable[]{G_NON_EMPTY, G_NON_EMPTY}); @Rule public ExpectedException expected = ExpectedException.none(); // input object private Portable inputObject; // object or exception private Object expectedResult; // e.g. 'readInt', or generic 'read' private String readMethodNameToInvoke; // e.g. body.brain.iq private String pathToRead; // parent method of this test to identify it in case of failures private String parent; @Parameters(name = "{index}: {0}, read{2}, {3}") public static Collection<Object[]> parametrisationData() { List<Object[]> result = new ArrayList<Object[]>(); directPrimitiveScenarios(result); directPrimitiveScenariosWrongMethodType(result); fromPortableToPrimitiveScenarios(result); fromPortableArrayToPrimitiveScenarios(result); fromPortableToPortableToPrimitiveScenarios(result); fromPortableToPortableArrayToPrimitiveScenarios(result); fromPortableArrayToPortableArrayToPrimitiveArrayAnyScenarios(result); fromPortableArrayAnyToPortableArrayAnyToPrimitiveScenarios(result); fromPortableArrayToPortableArrayToPrimitiveScenarios(result); fromPortableArrayToPortableArrayAnyScenarios(result); return result; } public DefaultPortableReaderSpecTest(Portable inputObject, Object expectedResult, Method method, String pathToRead, String parent) { this.inputObject = inputObject; this.expectedResult = expectedResult; this.readMethodNameToInvoke = method.name().replace("Generic", ""); this.pathToRead = pathToRead; this.parent = parent; } @Test @SuppressWarnings("unchecked") public void executeTestScenario() throws Exception { // handle result Object resultToMatch = expectedResult; if (expectedResult instanceof Class) { // expected exception case expected.expect(isA((Class) expectedResult)); } else if (expectedResult instanceof List) { // just convenience -> if result is a list if will be compared to an array, so it has to be converted resultToMatch = ((List) resultToMatch).toArray(); } // print test scenario for debug purposes // it makes debugging easier since all scenarios are generated printlnScenarioDescription(resultToMatch); // assert the condition Object result = Invoker.invoke(reader(inputObject), readMethodNameToInvoke, pathToRead); if (result instanceof MultiResult) { // in case of multi result while invoking generic "read" method deal with the multi results result = ((MultiResult) result).getResults().toArray(); } assertThat(result, equalTo(resultToMatch)); } private void printlnScenarioDescription(Object resultToMatch) { String desc = "Running test case:\n"; desc += "parent:\t" + parent + "\n"; desc += "path:\t" + pathToRead + "\n"; desc += "method:\tread" + readMethodNameToInvoke + "\n"; desc += "result:\t" + resultToMatch + "\n"; desc += "input:\t" + inputObject + "\n"; System.out.println(desc); } /** * Expands test cases for primitive non-array data types. * Word "primitive_" from the pathToExplode is replaced by each primitive type and the scenario is expanded to: * <ul> * <li>scenario(input, result.byte_, Byte, adjustedPath + "byte_"),</li> * <li>scenario(input, result.short_, Short, adjustedPath + "short_"),</li> * <li>scenario(input, result.int_, Int, adjustedPath + "int_"),</li> * <li>scenario(input, result.long_, Long, adjustedPath + "long_"),</li> * <li>scenario(input, result.float_, Float, adjustedPath + "float_"),</li> * <li>scenario(input, result.double_, Double, adjustedPath + "double_"),</li> * <li>scenario(input, result.boolean_, Boolean, adjustedPath + "boolean_"),</li> * <li>scenario(input, result.char_, Char, adjustedPath + "char_"),</li> * <li>scenario(input, result.string_, UTF, adjustedPath + "string_"),</li> * </ul> */ private static Collection<Object[]> expandPrimitiveScenario(Portable input, Object result, String pathToExplode, String parent) { List<Object[]> scenarios = new ArrayList<Object[]>(); Object adjustedResult; String tokenToReplace = "primitive_"; if (pathToExplode.contains("primitiveUTF_")) { tokenToReplace = "primitiveUTF_"; } for (Method method : getPrimitives(tokenToReplace.contains("UTF"))) { if (result instanceof PrimitivePortable) { adjustedResult = ((PrimitivePortable) result).getPrimitive(method); } else if (result == null && method != UTF) { adjustedResult = IllegalArgumentException.class; } else { adjustedResult = result; } // type-specific method case scenarios.add(scenario(input, adjustedResult, method, pathToExplode.replace(tokenToReplace, method.field), parent)); // generic method case scenarios.add(scenario(input, adjustedResult == IllegalArgumentException.class ? null : adjustedResult, Generic, pathToExplode.replace(tokenToReplace, method.field), parent)); } return scenarios; } /** * Expands test cases for primitive non-array data types. * Word "primitive_" is replaced by each primitive type and the scenario is to call a wrong method type for the field. * * So, for example, for primitive byte field we call methods for other data types. * <ul> * <li>scenario(input, result.byte_, Short, adjustedPath + "byte_"),</li> * <li>scenario(input, result.byte_, Int, adjustedPath + "byte_"),</li> * <li>scenario(input, result.byte_, Long, adjustedPath + "byte_"),</li> * <li>plus all other combinations that are incorrect (also with read*array method family)</li> * </ul> */ @SuppressWarnings("SameParameterValue") private static Collection<Object[]> expandPrimitiveScenarioWrongMethodType(Portable input, String pathToExplode, String parent) { List<Object[]> scenarios = new ArrayList<Object[]>(); String tokenToReplace = "primitive_"; for (Method fieldMethod : getPrimitives(true)) { for (Method possibleMethod : getPrimitives(true)) { // type-specific method case String adjustedPath = pathToExplode.replace(tokenToReplace, fieldMethod.field); if (fieldMethod != possibleMethod) { scenarios.add(scenario(input, IllegalArgumentException.class, possibleMethod, adjustedPath, parent)); } scenarios.add(scenario(input, IllegalArgumentException.class, Method.getArrayMethodFor(possibleMethod), adjustedPath, parent)); } } return scenarios; } /** * Expands test cases for primitive array data types. * Word "primitive_" is replaced by each primitive type and the scenario is to call a wrong method type for the field. * * So, for example, for primitive byte field we call methods for other data types. * <ul> * <li>scenario(input, result.bytes, Short, adjustedPath + "bytes"),</li> * <li>scenario(input, result.bytes, Int, adjustedPath + "bytes"),</li> * <li>scenario(input, result.bytes, Long, adjustedPath + "bytes"),</li> * <li>plus all other combinations that are incorrect (also with read*array method family)</li> * </ul> */ @SuppressWarnings("SameParameterValue") private static Collection<Object[]> expandPrimitiveArrayScenarioWrongMethodType(Portable input, String pathToExplode, String parent) { List<Object[]> scenarios = new ArrayList<Object[]>(); String tokenToReplace = "primitiveArray"; for (Method fieldMethod : getPrimitiveArrays()) { for (Method possibleMethod : getPrimitives(true)) { // type-specific method case String adjustedPath = pathToExplode.replace(tokenToReplace, fieldMethod.field); if (fieldMethod != Method.getArrayMethodFor(possibleMethod)) { scenarios.add(scenario(input, IllegalArgumentException.class, Method.getArrayMethodFor(possibleMethod), adjustedPath, parent)); } scenarios.add(scenario(input, IllegalArgumentException.class, possibleMethod, adjustedPath, parent)); } } return scenarios; } /** * Expands test cases for primitive array data types. * Word "primitiveArray" is replaced by each primitive array type and the scenario is expanded to for each type: * * group A: * <ul> * <li>scenario(prim(FULL), prim(FULL).bytes, ByteArray, "bytes"),</li> * <li>scenario(prim(NONE), prim(NONE).bytes, ByteArray, "bytes"),</li> * <li>scenario(prim(NULL), prim(NULL).bytes, ByteArray, "bytes"),</li> * * <li>scenario(prim(FULL), prim(FULL).bytes, ByteArray, "bytes[any]"),</li> * <li>scenario(prim(NONE), prim(NONE).bytes, ByteArray, "bytes[any]"),</li> * <li>scenario(prim(NULL), prim(NULL).bytes, ByteArray, "bytes[any]"),</li> * </ul> * * group B: * <ul> * <li>scenario(prim(FULL), prim(FULL).bytes[0], Byte, "bytes[0]"),</li> * <li>scenario(prim(FULL), prim(FULL).bytes[1], Byte, "bytes[1]"),</li> * <li>scenario(prim(FULL), prim(FULL).bytes[2], Byte, "bytes[2]"),</li> * * <li>for all primitives apart from UTF (exception expected)<ul> * <li>scenario(prim(NONE), IllegalArgumentException.class, Byte, "bytes[0]"),</li> * <li>scenario(prim(NULL), IllegalArgumentException.class, Byte, "bytes[1]"),</li> * </ul></li> * * <li>for UTF (null expected)<ul> * <li>scenario(prim(NONE), null, UTF, "strings[0]"),</li> * <li>scenario(prim(NULL), null, UTF, "strings[1]"),</li> * </ul></li> * </ul> */ private static Collection<Object[]> expandPrimitiveArrayScenario(Portable input, PrimitivePortable result, String pathToExplode, String parent) { List<Object[]> scenarios = new ArrayList<Object[]>(); // group A: for (Method method : getPrimitiveArrays()) { String path = pathToExplode.replace("primitiveArray", method.field); Object resultToMatch = result != null ? result.getPrimitiveArray(method) : null; Object resultToMatchAny = resultToMatch; if (resultToMatchAny != null && Array.getLength(resultToMatchAny) == 0) { resultToMatchAny = null; } scenarios.addAll(asList( scenario(input, resultToMatch, method, path, parent), scenario(input, resultToMatchAny, method, path + "[any]", parent) )); scenarios.addAll(asList( scenario(input, resultToMatch, Generic, path, parent), scenario(input, resultToMatchAny, Generic, path + "[any]", parent) )); } // group B: for (Method method : getPrimitives(true)) { String path = pathToExplode.replace("primitiveArray", method.field).replace("_", "s"); if (result == null || result.getPrimitiveArray(method) == null || Array.getLength(result.getPrimitiveArray(method)) == 0) { if (method.equals(UTF)) { scenarios.addAll(asList( scenario(input, null, method, path + "[0]", parent), scenario(input, null, Generic, path + "[0]", parent)) ); } else { // IMPORTANT: the difference between generic and non-generic primitive call for null scenarios.addAll(asList( scenario(input, IllegalArgumentException.class, method, path + "[0]", parent), scenario(input, null, Generic, path + "[0]", parent)) ); } } else { scenarios.addAll(asList( scenario(input, Array.get(result.getPrimitiveArray(method), 0), method, path + "[0]", parent), scenario(input, Array.get(result.getPrimitiveArray(method), 1), method, path + "[1]", parent), scenario(input, Array.get(result.getPrimitiveArray(method), 2), method, path + "[2]", parent) )); scenarios.addAll(asList( scenario(input, Array.get(result.getPrimitiveArray(method), 0), Generic, path + "[0]", parent), scenario(input, Array.get(result.getPrimitiveArray(method), 1), Generic, path + "[1]", parent), scenario(input, Array.get(result.getPrimitiveArray(method), 2), Generic, path + "[2]", parent) )); } } return scenarios; } /** * Expands test cases for that navigate from portable array to a primitive field. * Word portableArray is replaced to: portables[0], portables[1], portables[2], portables[any] * Word "primitive_" is replaced by each primitive type and the scenario is expanded to for each type: * * A.) The contract is that input should somewhere on the path contain an array of Portable[] which contains objects of type * PrimitivePortable. For example: "portableArray.primitive_" will be expanded two-fold, the portable array and primitive * types will be expanded as follows: * <ul> * <li>portables[0].byte, portables[0].short, portables[0].char, ... for all primitive types</li> * <li>portables[1].byte, portables[1].short, portables[1].char, ...</li> * <li>portables[2].byte, portables[2].short, portables[2].char, ...</li> * </ul> * * B.) Then the [any] case will be expanded too: * <ul> * <li>portables[any].byte, portables[any].short, portables[any].char, ... for all primitive types</li> * </ul> * * The expected result should be the object that contains the portable array - that's the general contract. * The result for assertion will be automatically calculated */ @SuppressWarnings({"unchecked", "ConstantConditions"}) private static Collection<Object[]> expandPortableArrayPrimitiveScenario(Portable input, GroupPortable result, String pathToExplode, String parent) { List<Object[]> scenarios = new ArrayList<Object[]>(); // expansion of the portable array using the following quantifiers for (String token : asList("0", "1", "2", "any")) { String tokenToReplace = "primitive_"; if (pathToExplode.contains("primitiveUTF_")) { tokenToReplace = "primitiveUTF_"; } String path = pathToExplode.replace("portableArray", "portables[" + token + "]"); if (token.equals("any")) { // B. case with [any] operator on portable array // expansion of the primitive fields for (Method method : getPrimitives(tokenToReplace.contains("UTF"))) { List resultToMatch = new ArrayList(); int portableCount = 0; try { portableCount = result.portables.length; } catch (NullPointerException ignored) { } for (int i = 0; i < portableCount; i++) { PrimitivePortable portable = (PrimitivePortable) result.portables[i]; resultToMatch.add(portable.getPrimitive(method)); } if (result == null || result.portables == null || result.portables.length == 0) { resultToMatch = null; } scenarios.addAll(asList( scenario(input, resultToMatch, getArrayMethodFor(method), path.replace(tokenToReplace, method.field), parent), scenario(input, resultToMatch, Generic, path.replace(tokenToReplace, method.field), parent) )); } } else { // A. case with [0], [1], [2] operator on portable array // expansion of the primitive fields for (Method method : getPrimitives(tokenToReplace.contains("UTF"))) { Object resultToMatch = null; try { PrimitivePortable portable = (PrimitivePortable) result.portables[Integer.parseInt(token)]; resultToMatch = portable.getPrimitive(method); } catch (NullPointerException ignored) { } catch (IndexOutOfBoundsException ignored) { } if (method != UTF) { if (result == null || result.portables == null || result.portables.length == 0) { resultToMatch = IllegalArgumentException.class; } } scenarios.addAll(asList( scenario(input, resultToMatch, method, path.replace(tokenToReplace, method.field), parent), // IMPORTANT: the difference between generic and non-generic primitive call for null scenario(input, resultToMatch == IllegalArgumentException.class ? null : resultToMatch, Generic, path.replace(tokenToReplace, method.field), parent) )); } } } return scenarios; } // ---------------------------------------------------------------------------------------------------------- // DIRECT primitive and primitive-array access // ---------------------------------------------------------------------------------------------------------- private static void directPrimitiveScenarios(List<Object[]> result) { String parent = "directPrimitiveScenarios"; // FULLy initialised primitive objects accessed directly result.addAll(expandPrimitiveScenario(prim(FULL), prim(FULL), "primitiveUTF_", parent)); // primitive arrays accessed directly (arrays are fully initialised, empty and null) result.addAll(expandPrimitiveArrayScenario(prim(FULL), prim(FULL), "primitiveArray", parent)); result.addAll(expandPrimitiveArrayScenario(prim(NONE), prim(NONE), "primitiveArray", parent)); result.addAll(expandPrimitiveArrayScenario(prim(NULL), prim(NULL), "primitiveArray", parent)); } // ---------------------------------------------------------------------------------------------------------- // DIRECT primitive and primitive-array access -> wrong method usage // ---------------------------------------------------------------------------------------------------------- private static void directPrimitiveScenariosWrongMethodType(List<Object[]> result) { String parent = "directPrimitiveScenariosWrongMethodType"; // FULLy initialised primitive objects accessed directly result.addAll(expandPrimitiveScenarioWrongMethodType(prim(FULL), "primitive_", parent)); // primitive arrays accessed directly result.addAll(expandPrimitiveArrayScenarioWrongMethodType(prim(FULL), "primitiveArray", parent)); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE to primitive and primitive-array access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableToPrimitiveScenarios(List<Object[]> result) { String parent = "directPrimitiveScenariosWrongMethodType"; // FULLy initialised primitive objects accessed from portable result.addAll(expandPrimitiveScenario(group(prim(FULL)), prim(FULL), "portable.primitiveUTF_", parent)); // primitive arrays accessed from portable (arrays are fully initialised, empty and null) result.addAll(expandPrimitiveArrayScenario(group(prim(FULL)), prim(FULL), "portable.primitiveArray", parent)); result.addAll(expandPrimitiveArrayScenario(group(prim(NONE)), prim(NONE), "portable.primitiveArray", parent)); result.addAll(expandPrimitiveArrayScenario(group(prim(NULL)), prim(NULL), "portable.primitiveArray", parent)); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE-ARRAY to primitive and primitive-array access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableArrayToPrimitiveScenarios(List<Object[]> result) { String p = "fromPortableArrayToPrimitiveScenarios"; // FULLy initialised primitive objects accessed from portable stored in array GroupPortable fullGroupVarious = group(prim(1, FULL), prim(10, FULL), prim(100, FULL)); result.addAll(expandPortableArrayPrimitiveScenario(fullGroupVarious, fullGroupVarious, "portableArray.primitiveUTF_", p)); GroupPortable fullEmptyNullGroup = group(prim(1, FULL), prim(10, NONE), prim(100, NULL)); result.addAll(expandPortableArrayPrimitiveScenario(fullEmptyNullGroup, fullEmptyNullGroup, "portableArray.primitiveUTF_", p)); // empty or null portable array de-referenced further GroupPortable nullArrayGroup = new GroupPortable((Portable[]) null); result.addAll(expandPortableArrayPrimitiveScenario(nullArrayGroup, nullArrayGroup, "portableArray.primitiveUTF_", p)); GroupPortable emptyArrayGroup = new GroupPortable(new Portable[0]); result.addAll(expandPortableArrayPrimitiveScenario(emptyArrayGroup, emptyArrayGroup, "portableArray.primitiveUTF_", p)); // FULLy initialised primitive arrays accessed from portable stored in array GroupPortable fullGroup = group(prim(FULL), prim(FULL), prim(FULL)); result.addAll(expandPrimitiveArrayScenario(fullGroup, prim(FULL), "portables[0].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(fullGroup, prim(FULL), "portables[1].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(fullGroup, prim(FULL), "portables[2].primitiveArray", p)); // EMPTY primitive arrays accessed from portable stored in array GroupPortable noneGroup = group(prim(NONE), prim(NONE), prim(NONE)); result.addAll(expandPrimitiveArrayScenario(noneGroup, prim(NONE), "portables[0].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(noneGroup, prim(NONE), "portables[1].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(noneGroup, prim(NONE), "portables[2].primitiveArray", p)); // NULL primitive arrays accessed from portable stored in array GroupPortable nullGroup = group(prim(NULL), prim(NULL), prim(NULL)); result.addAll(expandPrimitiveArrayScenario(nullGroup, prim(NULL), "portables[0].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(nullGroup, prim(NULL), "portables[1].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(nullGroup, prim(NULL), "portables[2].primitiveArray", p)); // EMPTY portable array -> de-referenced further for primitive access result.addAll(expandPrimitiveScenario(emptyArrayGroup, IllegalArgumentException.class, "portables[0].primitive_", p)); result.addAll(expandPrimitiveScenario(emptyArrayGroup, IllegalArgumentException.class, "portables[1].primitive_", p)); result.addAll(expandPrimitiveScenario(emptyArrayGroup, IllegalArgumentException.class, "portables[2].primitive_", p)); result.add(scenario(emptyArrayGroup, null, UTF, "portables[0].string_", p)); result.add(scenario(emptyArrayGroup, null, UTF, "portables[1].string_", p)); result.add(scenario(emptyArrayGroup, null, Generic, "portables[0].string_", p)); result.add(scenario(emptyArrayGroup, null, Generic, "portables[1].string_", p)); // EMPTY portable array -> de-referenced further for array access result.addAll(expandPrimitiveArrayScenario(emptyArrayGroup, null, "portables[0].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(emptyArrayGroup, null, "portables[1].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(emptyArrayGroup, null, "portables[2].primitiveArray", p)); // NULL portable array -> de-referenced further for primitive access result.addAll(expandPrimitiveScenario(nullArrayGroup, IllegalArgumentException.class, "portables[0].primitive_", p)); result.addAll(expandPrimitiveScenario(nullArrayGroup, IllegalArgumentException.class, "portables[1].primitive_", p)); result.addAll(expandPrimitiveScenario(nullArrayGroup, IllegalArgumentException.class, "portables[2].primitive_", p)); result.add(scenario(nullArrayGroup, null, UTF, "portables[0].string_", p)); result.add(scenario(nullArrayGroup, null, UTF, "portables[1].string_", p)); result.add(scenario(nullArrayGroup, null, Generic, "portables[0].string_", p)); result.add(scenario(nullArrayGroup, null, Generic, "portables[1].string_", p)); // EMPTY portable array -> de-referenced further for array access result.addAll(expandPrimitiveArrayScenario(nullArrayGroup, null, "portables[0].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(nullArrayGroup, null, "portables[1].primitiveArray", p)); result.addAll(expandPrimitiveArrayScenario(nullArrayGroup, null, "portables[2].primitiveArray", p)); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE via PORTABLE to further access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableToPortableToPrimitiveScenarios(List<Object[]> result) { String p = "fromPortableToPortableToPrimitiveScenarios"; // FULLy initialised primitive objects accessed from portable stored in array NestedGroupPortable nestedFullGroup = nested(group(prim(1, FULL), prim(10, FULL), prim(100, FULL))); result.addAll(asList( scenario(nestedFullGroup, (nestedFullGroup.portable), Portable, "portable", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portable, Portable, "portable.portable", p) )); result.addAll(asList( scenario(nestedFullGroup, (nestedFullGroup.portable), Generic, "portable", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portable, Generic, "portable.portable", p) )); result.addAll(expandPrimitiveScenario(nestedFullGroup, ((GroupPortable) nestedFullGroup.portable).portable, "portable.portable.primitiveUTF_", p)); result.addAll(expandPrimitiveArrayScenario(nestedFullGroup, (PrimitivePortable) ((GroupPortable) nestedFullGroup.portable).portable, "portable.portable.primitiveArray", p)); NestedGroupPortable nestedFullEmptyNullGroup = nested(group(prim(1, FULL), prim(10, NONE), prim(100, NULL))); result.addAll(expandPrimitiveScenario(nestedFullEmptyNullGroup, ((GroupPortable) nestedFullEmptyNullGroup.portable).portable, "portable.portable.primitiveUTF_", p)); result.addAll(expandPrimitiveArrayScenario(nestedFullEmptyNullGroup, (PrimitivePortable) ((GroupPortable) nestedFullEmptyNullGroup.portable).portable, "portable.portable.primitiveArray", p)); // empty or null portable array de-referenced further NestedGroupPortable nestedNullArrayGroup = nested(new GroupPortable((Portable[]) null)); result.addAll(asList( scenario(nestedNullArrayGroup, (nestedNullArrayGroup.portable), Portable, "portable", p), scenario(nestedNullArrayGroup, null, Portable, "portable.portable", p) )); result.addAll(asList( scenario(nestedNullArrayGroup, (nestedNullArrayGroup.portable), Generic, "portable", p), scenario(nestedNullArrayGroup, null, Generic, "portable.portable", p) )); result.addAll(expandPrimitiveScenario(nestedNullArrayGroup, null, "portable.portable.primitiveUTF_", p)); result.addAll(expandPrimitiveArrayScenario(nestedNullArrayGroup, null, "portable.portable.primitiveArray", p)); NestedGroupPortable nestedNull = nested(new Portable[0]); result.addAll(asList( scenario(nestedNull, null, Portable, "portable", p), scenario(nestedNull, null, Portable, "portable.portable", p) )); result.addAll(asList( scenario(nestedNull, null, Generic, "portable", p), scenario(nestedNull, null, Generic, "portable.portable", p) )); result.addAll(expandPrimitiveScenario(nestedNull, null, "portable.portable.primitiveUTF_", p)); result.addAll(expandPrimitiveArrayScenario(nestedNull, null, "portable.portable.primitiveArray", p)); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE via PORTABLE_ARRAY to further access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableToPortableArrayToPrimitiveScenarios(List<Object[]> result) { // FULLy initialised primitive objects accessed from portable stored in array String p = "fromPortableToPortableToPrimitiveScenarios"; NestedGroupPortable nestedFullGroup = nested(group(prim(1, FULL), prim(10, FULL), prim(100, FULL))); result.addAll(asList( scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables, PortableArray, "portable.portables", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables, PortableArray, "portable.portables[any]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[0], Portable, "portable.portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[1], Portable, "portable.portables[1]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[2], Portable, "portable.portables[2]", p), scenario(nestedFullGroup, null, Portable, "portable.portables[12]", p) )); result.addAll(asList( scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables, Generic, "portable.portables", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables, Generic, "portable.portables[any]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[0], Generic, "portable.portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[1], Generic, "portable.portables[1]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portable)).portables[2], Generic, "portable.portables[2]", p), scenario(nestedFullGroup, null, Generic, "portable.portables[12]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedFullGroup, (GroupPortable) nestedFullGroup.portable, "portable.portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedFullEmptyNullGroup = nested(group(prim(1, FULL), prim(10, NONE), prim(100, NULL))); result.addAll(expandPortableArrayPrimitiveScenario(nestedFullEmptyNullGroup, (GroupPortable) nestedFullEmptyNullGroup.portable, "portable.portableArray.primitiveUTF_", p) ); // empty or null portable array de-referenced further NestedGroupPortable nestedNullArrayGroup = nested(new GroupPortable((Portable[]) null)); result.addAll(asList( scenario(nestedNullArrayGroup, null, PortableArray, "portable.portables", p), scenario(nestedNullArrayGroup, null, PortableArray, "portable.portables[any]", p), scenario(nestedNullArrayGroup, null, Portable, "portable.portables[0]", p), scenario(nestedNullArrayGroup, null, Portable, "portable.portables[1]", p), scenario(nestedNullArrayGroup, null, Portable, "portable.portables[2]", p) )); result.addAll(asList( scenario(nestedNullArrayGroup, null, Generic, "portable.portables", p), scenario(nestedNullArrayGroup, null, Generic, "portable.portables[any]", p), scenario(nestedNullArrayGroup, null, Generic, "portable.portables[0]", p), scenario(nestedNullArrayGroup, null, Generic, "portable.portables[1]", p), scenario(nestedNullArrayGroup, null, Generic, "portable.portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedNullArrayGroup, (GroupPortable) nestedNullArrayGroup.portable, "portable.portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedEmptyArrayGroup = nested(new GroupPortable(new Portable[0])); result.addAll(asList( scenario(nestedEmptyArrayGroup, new Portable[0], PortableArray, "portable.portables", p), scenario(nestedEmptyArrayGroup, null, PortableArray, "portable.portables[any]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portable.portables[0]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portable.portables[1]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portable.portables[2]", p) )); result.addAll(asList( scenario(nestedEmptyArrayGroup, new Portable[0], Generic, "portable.portables", p), scenario(nestedEmptyArrayGroup, null, Generic, "portable.portables[any]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portable.portables[0]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portable.portables[1]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portable.portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedEmptyArrayGroup, (GroupPortable) nestedEmptyArrayGroup.portable, "portable.portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedEmpty = nested(new GroupPortable[0]); result.addAll(asList( scenario(nestedEmpty, null, PortableArray, "portable.portables", p), scenario(nestedEmpty, null, PortableArray, "portable.portables[any]", p), scenario(nestedEmpty, null, Portable, "portable.portables[0]", p), scenario(nestedEmpty, null, Portable, "portable.portables[1]", p), scenario(nestedEmpty, null, Portable, "portable.portables[2]", p) )); result.addAll(asList( scenario(nestedEmpty, null, Generic, "portable.portables", p), scenario(nestedEmpty, null, Generic, "portable.portables[any]", p), scenario(nestedEmpty, null, Generic, "portable.portables[0]", p), scenario(nestedEmpty, null, Generic, "portable.portables[1]", p), scenario(nestedEmpty, null, Generic, "portable.portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedEmpty, (GroupPortable) nestedEmpty.portable, "portable.portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedNull = nested((GroupPortable[]) null); result.addAll(asList( scenario(nestedNull, null, PortableArray, "portable.portables", p), scenario(nestedNull, null, PortableArray, "portable.portables[any]", p), scenario(nestedNull, null, Portable, "portable.portables[0]", p), scenario(nestedNull, null, Portable, "portable.portables[1]", p), scenario(nestedNull, null, Portable, "portable.portables[2]", p) )); result.addAll(asList( scenario(nestedNull, null, Generic, "portable.portables", p), scenario(nestedNull, null, Generic, "portable.portables[any]", p), scenario(nestedNull, null, Generic, "portable.portables[0]", p), scenario(nestedNull, null, Generic, "portable.portables[1]", p), scenario(nestedNull, null, Generic, "portable.portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedNull, (GroupPortable) nestedNull.portable, "portable.portableArray.primitiveUTF_", p) ); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE_ARRAY[any] via PORTABLE_ARRAY[any] to further PRIMITIVE access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableArrayAnyToPortableArrayAnyToPrimitiveScenarios(List<Object[]> result) { String p = "fromPortableArrayAnyToPortableArrayAnyToPrimitiveScenarios"; // ============================================= // INPUT mixed // ============================================= PrimitivePortable p1 = prim(1, NONE); PrimitivePortable p10 = prim(10, FULL); PrimitivePortable p20 = prim(20, FULL); NestedGroupPortable input = nested( new Portable[]{ new GroupPortable(new Portable[0]), group(p1, p10), new GroupPortable((Portable[]) null), group(new PrimitivePortable[]{p20}) } ); Class failure = IllegalArgumentException.class; result.addAll(asList( scenario(input, failure, ByteArray, "portables[any].portables[any].byte_", p), scenario(input, failure, ShortArray, "portables[any].portables[any].short_", p), scenario(input, failure, IntArray, "portables[any].portables[any].int_", p), scenario(input, failure, LongArray, "portables[any].portables[any].long_", p), scenario(input, failure, CharArray, "portables[any].portables[any].char_", p), scenario(input, failure, FloatArray, "portables[any].portables[any].float_", p), scenario(input, failure, DoubleArray, "portables[any].portables[any].double_", p), scenario(input, failure, BooleanArray, "portables[any].portables[any].boolean_", p) )); List expectedUtfArray = list(null, p1.string_, p10.string_, null, p20.string_); result.add(scenario(input, expectedUtfArray, UTFArray, "portables[any].portables[any].string_", p)); result.addAll(asList( scenario(input, list(null, p1.byte_, p10.byte_, null, p20.byte_), Generic, "portables[any].portables[any].byte_", p), scenario(input, list(null, p1.short_, p10.short_, null, p20.short_), Generic, "portables[any].portables[any].short_", p), scenario(input, list(null, p1.int_, p10.int_, null, p20.int_), Generic, "portables[any].portables[any].int_", p), scenario(input, list(null, p1.long_, p10.long_, null, p20.long_), Generic, "portables[any].portables[any].long_", p), scenario(input, list(null, p1.char_, p10.char_, null, p20.char_), Generic, "portables[any].portables[any].char_", p), scenario(input, list(null, p1.float_, p10.float_, null, p20.float_), Generic, "portables[any].portables[any].float_", p), scenario(input, list(null, p1.double_, p10.double_, null, p20.double_), Generic, "portables[any].portables[any].double_", p), scenario(input, list(null, p1.boolean_, p10.boolean_, null, p20.boolean_), Generic, "portables[any].portables[any].boolean_", p), scenario(input, list(null, p1.string_, p10.string_, null, p20.string_), Generic, "portables[any].portables[any].string_", p) )); // ============================================= // INPUT empty // ============================================= NestedGroupPortable inputEmpty = nested( new Portable[0] ); result.addAll(asList( scenario(inputEmpty, null, ByteArray, "portables[any].portables[any].byte_", p), scenario(inputEmpty, null, ShortArray, "portables[any].portables[any].short_", p), scenario(inputEmpty, null, IntArray, "portables[any].portables[any].int_", p), scenario(inputEmpty, null, LongArray, "portables[any].portables[any].long_", p), scenario(inputEmpty, null, CharArray, "portables[any].portables[any].char_", p), scenario(inputEmpty, null, FloatArray, "portables[any].portables[any].float_", p), scenario(inputEmpty, null, DoubleArray, "portables[any].portables[any].double_", p), scenario(inputEmpty, null, BooleanArray, "portables[any].portables[any].boolean_", p), scenario(inputEmpty, null, UTFArray, "portables[any].portables[any].string_", p) )); result.addAll(asList( scenario(inputEmpty, null, Generic, "portables[any].portables[any].byte_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].short_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].int_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].long_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].char_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].float_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].double_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].boolean_", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].string_", p) )); // ============================================= // INPUT null // ============================================= NestedGroupPortable inputNull = nested((Portable[]) null); result.addAll(asList( scenario(inputNull, null, ByteArray, "portables[any].portables[any].byte_", p), scenario(inputNull, null, ShortArray, "portables[any].portables[any].short_", p), scenario(inputNull, null, IntArray, "portables[any].portables[any].int_", p), scenario(inputNull, null, LongArray, "portables[any].portables[any].long_", p), scenario(inputNull, null, CharArray, "portables[any].portables[any].char_", p), scenario(inputNull, null, FloatArray, "portables[any].portables[any].float_", p), scenario(inputNull, null, DoubleArray, "portables[any].portables[any].double_", p), scenario(inputNull, null, BooleanArray, "portables[any].portables[any].boolean_", p), scenario(inputNull, null, UTFArray, "portables[any].portables[any].string_", p) )); result.addAll(asList( scenario(inputNull, null, Generic, "portables[any].portables[any].byte_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].short_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].int_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].long_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].char_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].float_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].double_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].boolean_", p), scenario(inputNull, null, Generic, "portables[any].portables[any].string_", p) )); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE_ARRAY[any] via PORTABLE_ARRAY[any] to further PRIMITIVE_ARRAY[any] access // ---------------------------------------------------------------------------------------------------------- private static void fromPortableArrayToPortableArrayToPrimitiveArrayAnyScenarios(List<Object[]> result) { String method = "fromPortableArrayToPortableArrayToPrimitiveArrayAnyScenarios"; String p = method + " mixed"; // ============================================= // INPUT mixed // ============================================= NestedGroupPortable input = nested( new Portable[]{ new GroupPortable(new Portable[0]), group(prim(1, NONE), prim(10, FULL), prim(50, NULL)), new GroupPortable((Portable[]) null), group(prim(20, FULL), prim(70, NULL)) } ); PrimitivePortable p10 = prim(10, FULL); PrimitivePortable p20 = prim(20, FULL); Class failure = IllegalArgumentException.class; result.addAll(asList( scenario(input, failure, ByteArray, "portables[any].portables[any].bytes[any]", p), scenario(input, failure, ShortArray, "portables[any].portables[any].shorts[any]", p), scenario(input, failure, IntArray, "portables[any].portables[any].ints[any]", p), scenario(input, failure, LongArray, "portables[any].portables[any].longs[any]", p), scenario(input, failure, CharArray, "portables[any].portables[any].chars[any]", p), scenario(input, failure, FloatArray, "portables[any].portables[any].floats[any]", p), scenario(input, failure, DoubleArray, "portables[any].portables[any].doubles[any]", p), scenario(input, failure, BooleanArray, "portables[any].portables[any].booleans[any]", p) )); List expectedUtfArray = list(null, null, p10.strings, null, null, p20.strings, null); result.add(scenario(input, expectedUtfArray, UTFArray, "portables[any].portables[any].strings[any]", p)); result.addAll(asList( scenario(input, list(null, null, p10.bytes, null, null, p20.bytes, null), Generic, "portables[any].portables[any].bytes[any]", p), scenario(input, list(null, null, p10.shorts, null, null, p20.shorts, null), Generic, "portables[any].portables[any].shorts[any]", p), scenario(input, list(null, null, p10.ints, null, null, p20.ints, null), Generic, "portables[any].portables[any].ints[any]", p), scenario(input, list(null, null, p10.longs, null, null, p20.longs, null), Generic, "portables[any].portables[any].longs[any]", p), scenario(input, list(null, null, p10.chars, null, null, p20.chars, null), Generic, "portables[any].portables[any].chars[any]", p), scenario(input, list(null, null, p10.floats, null, null, p20.floats, null), Generic, "portables[any].portables[any].floats[any]", p), scenario(input, list(null, null, p10.doubles, null, null, p20.doubles, null), Generic, "portables[any].portables[any].doubles[any]", p), scenario(input, list(null, null, p10.booleans, null, null, p20.booleans, null), Generic, "portables[any].portables[any].booleans[any]", p), scenario(input, list(null, null, p10.strings, null, null, p20.strings, null), Generic, "portables[any].portables[any].strings[any]", p) )); // ============================================= // INPUT empty // ============================================= p = method + " empty"; NestedGroupPortable inputEmpty = nested( new Portable[0] ); result.addAll(asList( scenario(inputEmpty, null, ByteArray, "portables[any].portables[any].bytes[any]", p), scenario(inputEmpty, null, ShortArray, "portables[any].portables[any].shorts[any]", p), scenario(inputEmpty, null, IntArray, "portables[any].portables[any].ints[any]", p), scenario(inputEmpty, null, LongArray, "portables[any].portables[any].longs[any]", p), scenario(inputEmpty, null, CharArray, "portables[any].portables[any].chars[any]", p), scenario(inputEmpty, null, FloatArray, "portables[any].portables[any].floats[any]", p), scenario(inputEmpty, null, DoubleArray, "portables[any].portables[any].doubles[any]", p), scenario(inputEmpty, null, BooleanArray, "portables[any].portables[any].booleans[any]", p), scenario(inputEmpty, null, UTFArray, "portables[any].portables[any].strings[any]", p) )); result.addAll(asList( scenario(inputEmpty, null, Generic, "portables[any].portables[any].bytes[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].shorts[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].ints[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].longs[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].chars[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].floats[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].doubles[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].booleans[any]", p), scenario(inputEmpty, null, Generic, "portables[any].portables[any].strings[any]", p) )); // ============================================= // INPUT null // ============================================= p = method + " null"; NestedGroupPortable inputNull = nested((Portable[]) null); result.addAll(asList( scenario(inputNull, null, ByteArray, "portables[any].portables[any].bytes[any]", p), scenario(inputNull, null, ShortArray, "portables[any].portables[any].shorts[any]", p), scenario(inputNull, null, IntArray, "portables[any].portables[any].ints[any]", p), scenario(inputNull, null, LongArray, "portables[any].portables[any].longs[any]", p), scenario(inputNull, null, CharArray, "portables[any].portables[any].chars[any]", p), scenario(inputNull, null, FloatArray, "portables[any].portables[any].floats[any]", p), scenario(inputNull, null, DoubleArray, "portables[any].portables[any].doubles[any]", p), scenario(inputNull, null, BooleanArray, "portables[any].portables[any].booleans[any]", p), scenario(inputNull, null, UTFArray, "portables[any].portables[any].strings[any]", p) )); result.addAll(asList( scenario(inputNull, null, Generic, "portables[any].portables[any].bytes[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].shorts[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].ints[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].longs[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].chars[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].floats[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].doubles[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].booleans[any]", p), scenario(inputNull, null, Generic, "portables[any].portables[any].strings[any]", p) )); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE_ARRAY to PORTABLE_ARRAY access + further // ---------------------------------------------------------------------------------------------------------- private static void fromPortableArrayToPortableArrayToPrimitiveScenarios(List<Object[]> result) { String p = "fromPortableArrayToPortableArrayToPrimitiveScenarios"; // FULLy initialised primitive objects accessed from portable stored in array NestedGroupPortable nestedFullGroup = nested(group(prim(1, FULL), prim(10, FULL), prim(100, FULL))); result.addAll(asList( scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, PortableArray, "portables[0].portables", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, PortableArray, "portables[0].portables[any]", p), scenario(nestedFullGroup, new Portable[]{prim(1, FULL)}, PortableArray, "portables[any].portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, PortableArray, "portables[any].portables[any]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[0], Portable, "portables[0].portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[1], Portable, "portables[0].portables[1]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[2], Portable, "portables[0].portables[2]", p), scenario(nestedFullGroup, null, Portable, "portables[0].portables[12]", p) )); result.addAll(asList( scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, Generic, "portables[0].portables", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, Generic, "portables[0].portables[any]", p), scenario(nestedFullGroup, new Portable[]{prim(1, FULL)}, Generic, "portables[any].portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables, Generic, "portables[any].portables[any]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[0], Generic, "portables[0].portables[0]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[1], Generic, "portables[0].portables[1]", p), scenario(nestedFullGroup, ((GroupPortable) (nestedFullGroup.portables[0])).portables[2], Generic, "portables[0].portables[2]", p), scenario(nestedFullGroup, null, Generic, "portables[0].portables[12]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedFullGroup, (GroupPortable) nestedFullGroup.portable, "portables[0].portableArray.primitiveUTF_", p) ); NestedGroupPortable anyGroup = nested(new Portable[]{ group(prim(1, FULL), prim(10, NONE), prim(50, NULL)), group(prim(2, FULL), prim(20, NONE), prim(80, NULL)) }); result.addAll(expandPortableArrayPrimitiveScenario(anyGroup, (GroupPortable) anyGroup.portables[0], "portables[0].portableArray.primitiveUTF_", p) ); // empty or null portable array de-referenced further NestedGroupPortable nestedNullArrayGroup = nested(new GroupPortable((Portable[]) null)); result.addAll(asList( scenario(nestedNullArrayGroup, null, PortableArray, "portables[0].portables", p), scenario(nestedNullArrayGroup, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedNullArrayGroup, null, PortableArray, "portables[any].portables[0]", p), scenario(nestedNullArrayGroup, null, PortableArray, "portables[any].portables[any]", p), scenario(nestedNullArrayGroup, null, Portable, "portables[0].portables[0]", p), scenario(nestedNullArrayGroup, null, Portable, "portables[0].portables[1]", p), scenario(nestedNullArrayGroup, null, Portable, "portables[0].portables[2]", p) )); result.addAll(asList( scenario(nestedNullArrayGroup, null, Generic, "portables[0].portables", p), scenario(nestedNullArrayGroup, null, Generic, "portables[0].portables[any]", p), scenario(nestedNullArrayGroup, null, Generic, "portables[any].portables[0]", p), scenario(nestedNullArrayGroup, null, Generic, "portables[any].portables[any]", p), scenario(nestedNullArrayGroup, null, Generic, "portables[0].portables[0]", p), scenario(nestedNullArrayGroup, null, Generic, "portables[0].portables[1]", p), scenario(nestedNullArrayGroup, null, Generic, "portables[0].portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedNullArrayGroup, (GroupPortable) nestedNullArrayGroup.portable, "portables[0].portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedEmptyArrayGroup = nested(new GroupPortable(new Portable[0])); result.addAll(asList( scenario(nestedEmptyArrayGroup, new Portable[0], PortableArray, "portables[0].portables", p), scenario(nestedEmptyArrayGroup, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedEmptyArrayGroup, null, PortableArray, "portables[any].portables[0]", p), scenario(nestedEmptyArrayGroup, null, PortableArray, "portables[any].portables[any]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portables[0].portables[0]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portables[0].portables[1]", p), scenario(nestedEmptyArrayGroup, null, Portable, "portables[0].portables[2]", p) )); result.addAll(asList( scenario(nestedEmptyArrayGroup, new Portable[0], Generic, "portables[0].portables", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[0].portables[any]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[any].portables[0]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[any].portables[any]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[0].portables[0]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[0].portables[1]", p), scenario(nestedEmptyArrayGroup, null, Generic, "portables[0].portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedEmptyArrayGroup, (GroupPortable) nestedEmptyArrayGroup.portable, "portables[0].portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedEmpty = nested(new GroupPortable[0]); result.addAll(asList( scenario(nestedEmpty, null, PortableArray, "portables[0].portables", p), scenario(nestedEmpty, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedEmpty, null, PortableArray, "portables[any].portables[0]", p), scenario(nestedEmpty, null, PortableArray, "portables[any].portables[any]", p), scenario(nestedEmpty, null, Portable, "portables[0].portables[0]", p), scenario(nestedEmpty, null, Portable, "portables[0].portables[1]", p), scenario(nestedEmpty, null, Portable, "portables[0].portables[2]", p) )); result.addAll(asList( scenario(nestedEmpty, null, Generic, "portables[0].portables", p), scenario(nestedEmpty, null, Generic, "portables[0].portables[any]", p), scenario(nestedEmpty, null, Generic, "portables[any].portables[0]", p), scenario(nestedEmpty, null, Generic, "portables[any].portables[any]", p), scenario(nestedEmpty, null, Generic, "portables[0].portables[0]", p), scenario(nestedEmpty, null, Generic, "portables[0].portables[1]", p), scenario(nestedEmpty, null, Generic, "portables[0].portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedEmpty, (GroupPortable) nestedEmpty.portable, "portables[0].portableArray.primitiveUTF_", p) ); NestedGroupPortable nestedNull = nested((GroupPortable[]) null); result.addAll(asList( scenario(nestedNull, null, PortableArray, "portables[0].portables", p), scenario(nestedNull, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedNull, null, PortableArray, "portables[any].portables[0]", p), scenario(nestedNull, null, PortableArray, "portables[any].portables[any]", p), scenario(nestedNull, null, Portable, "portables[0].portables[0]", p), scenario(nestedNull, null, Portable, "portables[0].portables[1]", p), scenario(nestedNull, null, Portable, "portables[0].portables[2]", p) )); result.addAll(asList( scenario(nestedNull, null, Generic, "portables[0].portables", p), scenario(nestedNull, null, Generic, "portables[0].portables[any]", p), scenario(nestedNull, null, Generic, "portables[any].portables[0]", p), scenario(nestedNull, null, Generic, "portables[any].portables[any]", p), scenario(nestedNull, null, Generic, "portables[0].portables[0]", p), scenario(nestedNull, null, Generic, "portables[0].portables[1]", p), scenario(nestedNull, null, Generic, "portables[0].portables[2]", p) )); result.addAll(expandPortableArrayPrimitiveScenario(nestedNull, (GroupPortable) nestedNull.portable, "portables[0].portableArray.primitiveUTF_", p) ); } // ---------------------------------------------------------------------------------------------------------- // from PORTABLE_ARRAY to PORTABLE_ARRAY access + further // ---------------------------------------------------------------------------------------------------------- private static void fromPortableArrayToPortableArrayAnyScenarios(List<Object[]> result) { String p = "fromPortableArrayToPortableArrayAnyScenarios"; NestedGroupPortable anyGroup = nested(new Portable[]{ group(prim(1, FULL), prim(10, NONE), prim(50, NULL)), group(prim(2, FULL), prim(20, NONE), prim(80, NULL)) }); result.addAll(asList( scenario(anyGroup, ((GroupPortable) (anyGroup.portables[0])).portables, PortableArray, "portables[0].portables[any]", p), scenario(anyGroup, new Portable[]{prim(1, FULL), prim(2, FULL)}, PortableArray, "portables[any].portables[0]", p), scenario(anyGroup, new Portable[]{prim(10, FULL), prim(20, FULL)}, PortableArray, "portables[any].portables[1]", p), scenario(anyGroup, new Portable[]{prim(50, FULL), prim(80, FULL)}, PortableArray, "portables[any].portables[2]", p), scenario(anyGroup, new Portable[]{prim(1, FULL), prim(10, FULL), prim(50, FULL), prim(2, FULL), prim(20, FULL), prim(80, FULL)}, PortableArray, "portables[any].portables[any]", p) )); result.addAll(asList( scenario(anyGroup, ((GroupPortable) (anyGroup.portables[0])).portables, Generic, "portables[0].portables[any]", p), scenario(anyGroup, new Portable[]{prim(1, FULL), prim(2, FULL)}, Generic, "portables[any].portables[0]", p), scenario(anyGroup, new Portable[]{prim(10, FULL), prim(20, FULL)}, Generic, "portables[any].portables[1]", p), scenario(anyGroup, new Portable[]{prim(50, FULL), prim(80, FULL)}, Generic, "portables[any].portables[2]", p), scenario(anyGroup, new Portable[]{prim(1, FULL), prim(10, FULL), prim(50, FULL), prim(2, FULL), prim(20, FULL), prim(80, FULL)}, Generic, "portables[any].portables[any]", p) )); NestedGroupPortable nestedEmptyArrayGroup = nested(new Portable[]{new GroupPortable(new Portable[0]), group(prim(1, FULL), prim(10, NONE), prim(50, NULL))}); result.addAll(asList( scenario(nestedEmptyArrayGroup, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(1, FULL)}, PortableArray, "portables[any].portables[0]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(10, FULL)}, PortableArray, "portables[any].portables[1]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(50, FULL)}, PortableArray, "portables[any].portables[2]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(1, FULL), prim(10, FULL), prim(50, FULL)}, PortableArray, "portables[any].portables[any]", p) )); result.addAll(asList( scenario(nestedEmptyArrayGroup, null, Generic, "portables[0].portables[any]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(1, FULL)}, Generic, "portables[any].portables[0]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(10, FULL)}, Generic, "portables[any].portables[1]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(50, FULL)}, Generic, "portables[any].portables[2]", p), scenario(nestedEmptyArrayGroup, new Portable[]{null, prim(1, FULL), prim(10, FULL), prim(50, FULL)}, Generic, "portables[any].portables[any]", p) )); NestedGroupPortable nestedNullArrayGroup = nested(new Portable[]{new GroupPortable((Portable[]) null), group(prim(1, FULL), prim(10, NONE), prim(50, NULL))}); result.addAll(asList( scenario(nestedNullArrayGroup, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(1, FULL)}, PortableArray, "portables[any].portables[0]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(10, FULL)}, PortableArray, "portables[any].portables[1]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(50, FULL)}, PortableArray, "portables[any].portables[2]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(1, FULL), prim(10, FULL), prim(50, FULL)}, PortableArray, "portables[any].portables[any]", p) )); result.addAll(asList( scenario(nestedNullArrayGroup, null, PortableArray, "portables[0].portables[any]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(1, FULL)}, Generic, "portables[any].portables[0]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(10, FULL)}, Generic, "portables[any].portables[1]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(50, FULL)}, Generic, "portables[any].portables[2]", p), scenario(nestedNullArrayGroup, new Portable[]{null, prim(1, FULL), prim(10, FULL), prim(50, FULL)}, Generic, "portables[any].portables[any]", p) )); } // // Test data structure utilities // private static Object[] scenario(Portable input, Object result, Method method, String path, String parent) { return new Object[]{input, result, method, path, parent}; } private static Collection<Object[]> test(Object[]... scenarios) { List<Object[]> result = new ArrayList<Object[]>(); for (Object[] scenario : scenarios) { result.add(scenario); } return result; } /** * Unwraps input objects if they are arrays or lists and adds all to an output list. */ @SuppressWarnings("unchecked") private static <T> List<T> list(T... objects) { List<T> result = new ArrayList<T>(); for (T object : objects) { if (object == null) { //noinspection ConstantConditions result.add(object); } else if (object.getClass().isArray()) { int length = Array.getLength(object); for (int i = 0; i < length; i++) { result.add((T) Array.get(object, i)); } } else if (object instanceof Collection) { result.addAll((Collection<T>) object); } else { result.add(object); } } return result; } // // Hazelcast init Utilities // public PortableReader reader(Portable portable) throws IOException { Config config = new Config(); config.getSerializationConfig().addPortableFactory(TestPortableFactory.ID, new TestPortableFactory()); HazelcastInstanceProxy hz = (HazelcastInstanceProxy) createHazelcastInstance(config); IMap<String, Object> map = hz.getMap("stealingMap"); // put fully initialised object to a map // avoid the case where there's no class definition if (portable instanceof PrimitivePortable) { map.put(P_NON_EMPTY.toString(), P_NON_EMPTY); } if (portable instanceof GroupPortable) { map.put(G_NON_EMPTY.toString(), G_NON_EMPTY); } if (portable instanceof NestedGroupPortable) { map.put(N_NON_EMPTY.toString(), N_NON_EMPTY); } map.put(portable.toString(), portable); EntryStealingProcessor processor = new EntryStealingProcessor(portable.toString()); map.executeOnEntries(processor); SerializationServiceV1 ss = (SerializationServiceV1) hz.getSerializationService(); return ss.createPortableReader(processor.stolenEntryData); } /** * Steals a "real" serialised Data of a PortableObject to be as close as possible to real use-case. */ public static class EntryStealingProcessor extends AbstractEntryProcessor { private final Object key; private Data stolenEntryData; EntryStealingProcessor(String key) { super(false); this.key = key; } @Override public Object process(Map.Entry entry) { // hack to get rid of de-serialization cost (assuming in-memory-format is BINARY, if it is OBJECT you can replace // the null check below with entry.getValue() != null), but works only for versions >= 3.6 if (key.equals(entry.getKey())) { stolenEntryData = (Data) ((LazyMapEntry) entry).getValueData(); } return null; } } /** * Since the reader has a lot of methods and we want to parametrise the test to invoke each one of them in a generic * way, we invoke them using this Invoker that leverages reflection. */ static class Invoker { public static <T> T invoke(PortableReader reader, String methodName, String path) { return invokeMethod(reader, "read" + methodName, path); } @SuppressWarnings("unchecked") static <T> T invokeMethod(Object object, String methodName, String arg) throws RuntimeException { try { java.lang.reflect.Method method = object.getClass().getMethod(methodName, String.class); return (T) method.invoke(object, arg); } catch (Exception e) { throw ExceptionUtil.rethrow(e); } } } }