diff --git a/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/problem/rpc/ParamDto.java b/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/problem/rpc/ParamDto.java index 22df9bee53..17e2c0f976 100644 --- a/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/problem/rpc/ParamDto.java +++ b/client-java/controller-api/src/main/java/org/evomaster/client/java/controller/api/dto/problem/rpc/ParamDto.java @@ -167,4 +167,17 @@ public void setNotNullValue() { stringValue = NOT_NULL_MARK_OBJ_DATE; } + public ParamDto findObjectByTypeName(String typeName){ + if (typeName == null || innerContent == null || innerContent.isEmpty()) return null; + for (ParamDto p : innerContent){ + if (p.type.fullTypeNameWithGenericType.equals(typeName) && p.innerContent != null && !p.innerContent.isEmpty()){ + return p; + } + ParamDto ip = p.findObjectByTypeName(typeName); + if (ip != null) + return ip; + } + return null; + } + } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilder.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilder.java index dd2e61eb4d..4d31c173d1 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilder.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilder.java @@ -523,6 +523,7 @@ private static NamedTypedValue build(InterfaceSchema schema, Class clazz, Typ // note that here we only extract class name and message StringParam msgField = new StringParam("message", new AccessibleSchema(false, null, "getMessage")); ObjectType exceptionType = new ObjectType(clazz.getSimpleName(), clazz.getName(), Collections.singletonList(msgField), clazz, genericTypes); + exceptionType.ownerSchema = schema; namedValue = new ObjectParam(name, exceptionType, accessibleSchema); } else { if (clazz.getName().startsWith("java")){ @@ -590,6 +591,7 @@ private static NamedTypedValue build(InterfaceSchema schema, Class clazz, Typ handleNativeRPCConstraints(clazz, fields, rpcType); ObjectType otype = new ObjectType(clazz.getSimpleName(), clazz.getName(), fields, clazz, genericTypes); + otype.ownerSchema = schema; otype.setOriginalType(originalType); otype.depth = getDepthLevel(clazz, depth, clazzWithGenericTypes); ObjectParam oparam = new ObjectParam(name, otype, accessibleSchema); @@ -597,6 +599,7 @@ private static NamedTypedValue build(InterfaceSchema schema, Class clazz, Typ namedValue = oparam; }else { CycleObjectType otype = new CycleObjectType(clazz.getSimpleName(), clazz.getName(), clazz, genericTypes); + otype.ownerSchema = schema; otype.depth = getDepthLevel(clazz, depth, clazzWithGenericTypes); ObjectParam oparam = new ObjectParam(name, otype, accessibleSchema); schema.registerType(otype.copy(), oparam, isTypeToIdentify); diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/params/ObjectParam.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/params/ObjectParam.java index 350e0da74c..84bbba71ba 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/params/ObjectParam.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/params/ObjectParam.java @@ -3,10 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import org.evomaster.client.java.controller.api.dto.problem.rpc.ParamDto; import org.evomaster.client.java.controller.problem.rpc.CodeJavaGenerator; -import org.evomaster.client.java.controller.problem.rpc.schema.types.AccessibleSchema; -import org.evomaster.client.java.controller.problem.rpc.schema.types.ObjectType; -import org.evomaster.client.java.controller.problem.rpc.schema.types.PrimitiveOrWrapperType; -import org.evomaster.client.java.controller.problem.rpc.schema.types.TypeSchema; +import org.evomaster.client.java.controller.problem.rpc.schema.types.*; import org.evomaster.client.java.utils.SimpleLogger; import java.lang.reflect.Field; @@ -106,6 +103,10 @@ public void setValueBasedOnDto(ParamDto dto) { if (dto.innerContent!=null && !dto.innerContent.isEmpty()){ List fields = getType().getFields(); + List fs = getFieldsForCycleObjectType(); + if (fs != null) + fields = fs; + List values = new ArrayList<>(); for (ParamDto p: dto.innerContent){ @@ -122,12 +123,21 @@ public void setValueBasedOnDto(ParamDto dto) { protected void setValueBasedOnValidInstance(Object instance) { List values = new ArrayList<>(); List fields = getType().getFields(); + + if (instance != null && (fields == null || fields.isEmpty())){ + List fs = getFieldsForCycleObjectType(); + if (fs != null) + fields = fs; + } + Class clazz; try { clazz = Class.forName(getType().getFullTypeName()); } catch (ClassNotFoundException e) { throw new RuntimeException("ERROR: fail to get class with the name"+getType().getFullTypeName()+" Msg:"+e.getMessage()); } + + for (NamedTypedValue f: fields){ NamedTypedValue copy = f.copyStructureWithProperties(); try { @@ -149,7 +159,6 @@ protected void setValueBasedOnValidInstance(Object instance) { values.add(copy); } - setValue(values); } @@ -178,6 +187,10 @@ public void setValueBasedOnInstanceOrJson(Object json) throws JsonProcessingExce if (!(instance instanceof Map)) throw new RuntimeException("cannot parse the map param "+getName()+ " with the type" + instance.getClass().getName()); + List fs = getFieldsForCycleObjectType(); + if (fs != null) + fields = fs; + for (NamedTypedValue f: fields){ NamedTypedValue copy = f.copyStructureWithProperties(); Object fiv = ((Map)instance).get(f.getName()); @@ -258,4 +271,20 @@ public String getValueAsJavaString() { return null; } + private List getFieldsForCycleObjectType(){ + if (!(getType() instanceof CycleObjectType)) + return null; + + if (getType().ownerSchema == null) + SimpleLogger.warn("owner schema of the type is null"); + else { + TypeSchema typeSchema = getType().ownerSchema.getTypeCollections().get(getType().getFullTypeNameWithGenericType()); + if (typeSchema == null || !(typeSchema instanceof ObjectType)) + SimpleLogger.warn("cannot find the object type with name "+getType().getFullTypeNameWithGenericType()); + else + return ((ObjectType)typeSchema.copy()).getFields(); + } + return null; + } + } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigDecimalType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigDecimalType.java index 37115b13df..c911d462f2 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigDecimalType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigDecimalType.java @@ -23,7 +23,7 @@ public TypeDto getDto() { } @Override - public BigDecimalType copy() { + public BigDecimalType copyContent() { return new BigDecimalType(); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigIntegerType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigIntegerType.java index 254f37b749..3a02ab894e 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigIntegerType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/BigIntegerType.java @@ -23,7 +23,7 @@ public TypeDto getDto() { } @Override - public BigDecimalType copy() { + public BigDecimalType copyContent() { return new BigDecimalType(); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ByteBufferType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ByteBufferType.java index aa74ba5224..6c32d71851 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ByteBufferType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ByteBufferType.java @@ -25,7 +25,7 @@ public TypeDto getDto() { } @Override - public ByteBufferType copy() { + public ByteBufferType copyContent() { return new ByteBufferType(); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CollectionType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CollectionType.java index 4795ea3d8d..f39b4871ea 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CollectionType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CollectionType.java @@ -37,7 +37,7 @@ public String getTypeNameForInstance() { } @Override - public CollectionType copy() { + public CollectionType copyContent() { return new CollectionType(getType(), getFullTypeName(), template, getClazz()); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CycleObjectType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CycleObjectType.java index 3693409b57..a31aadfcce 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CycleObjectType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/CycleObjectType.java @@ -16,6 +16,11 @@ public CycleObjectType(String type, String fullTypeName, Class clazz, List(), clazz, genericTypes); } + public CycleObjectType copyContent(){ + List genericTypes = this.genericTypes != null? new ArrayList<>(this.genericTypes): null; + return new CycleObjectType(getType(), getFullTypeName(), getClazz(), genericTypes); + } + @Override public TypeDto getDto() { TypeDto dto = super.getDto(); diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/DateType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/DateType.java index 2fe6fe5dd2..fc4a0c25d4 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/DateType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/DateType.java @@ -238,7 +238,7 @@ public TypeDto getDto() { @Override - public DateType copy() { + public DateType copyContent() { return new DateType(); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/EnumType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/EnumType.java index 7e175f244d..0735fd9f00 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/EnumType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/EnumType.java @@ -32,7 +32,7 @@ public TypeDto getDto() { } @Override - public EnumType copy() { + public EnumType copyContent() { return new EnumType(getType(), getFullTypeName(), items, getClazz()); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/MapType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/MapType.java index 3119cac414..64483b2c1b 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/MapType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/MapType.java @@ -43,7 +43,7 @@ public String getTypeNameForInstance() { } @Override - public MapType copy() { + public MapType copyContent() { return new MapType(getType(),getFullTypeName(), template, getClazz()); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ObjectType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ObjectType.java index 4b3b73d370..19e96ff270 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ObjectType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/ObjectType.java @@ -20,7 +20,7 @@ public class ObjectType extends TypeSchema { /** * a list of generic types */ - private final List genericTypes; + protected final List genericTypes; public ObjectType(String type, String fullTypeName, List fields, Class clazz, List genericTypes) { @@ -41,7 +41,7 @@ public TypeDto getDto() { return dto; } - public ObjectType copy(){ + public ObjectType copyContent(){ List cfields = new ArrayList<>(); if (fields != null){ for (NamedTypedValue f: fields){ diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PairType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PairType.java index 3040528a9a..52ad48df36 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PairType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PairType.java @@ -49,7 +49,7 @@ public TypeDto getDto() { } @Override - public PairType copy() { + public PairType copyContent() { return new PairType(getFirstTemplate(), getSecondTemplate()); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PrimitiveOrWrapperType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PrimitiveOrWrapperType.java index dc36dc948e..a251bf43d2 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PrimitiveOrWrapperType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/PrimitiveOrWrapperType.java @@ -42,7 +42,7 @@ public static boolean isPrimitiveOrTypes(Class clazz){ @Override - public PrimitiveOrWrapperType copy() { + public PrimitiveOrWrapperType copyContent() { return new PrimitiveOrWrapperType(getType(), getFullTypeName(), isWrapper, getClazz()); } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/StringType.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/StringType.java index 9a861e9bf6..bc7ff5f883 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/StringType.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/StringType.java @@ -23,7 +23,7 @@ public TypeDto getDto() { } @Override - public StringType copy() { + public StringType copyContent() { return new StringType(); } } diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/TypeSchema.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/TypeSchema.java index 05e969fe2c..da7bdd8212 100644 --- a/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/TypeSchema.java +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/problem/rpc/schema/types/TypeSchema.java @@ -1,6 +1,7 @@ package org.evomaster.client.java.controller.problem.rpc.schema.types; import org.evomaster.client.java.controller.api.dto.problem.rpc.TypeDto; +import org.evomaster.client.java.controller.problem.rpc.schema.InterfaceSchema; /** * type schema @@ -51,7 +52,16 @@ public String getFullTypeNameWithGenericType(){ return fullTypeName; } - public abstract TypeSchema copy(); + public InterfaceSchema ownerSchema; + + public abstract TypeSchema copyContent(); + + public TypeSchema copy(){ + TypeSchema content = copyContent(); + // keep refer to schema + content.ownerSchema = ownerSchema; + return content; + } public TypeDto getDto(){ TypeDto dto = new TypeDto(); diff --git a/client-java/controller/src/test/java/com/thrift/example/artificial/CycleAObj.java b/client-java/controller/src/test/java/com/thrift/example/artificial/CycleAObj.java index 8240638f7c..3480111080 100644 --- a/client-java/controller/src/test/java/com/thrift/example/artificial/CycleAObj.java +++ b/client-java/controller/src/test/java/com/thrift/example/artificial/CycleAObj.java @@ -1,6 +1,6 @@ package com.thrift.example.artificial; public class CycleAObj { - + public String aID; public CycleBObj obj; } diff --git a/client-java/controller/src/test/java/com/thrift/example/artificial/CycleBObj.java b/client-java/controller/src/test/java/com/thrift/example/artificial/CycleBObj.java index 16cb2f986e..0f8a560d47 100644 --- a/client-java/controller/src/test/java/com/thrift/example/artificial/CycleBObj.java +++ b/client-java/controller/src/test/java/com/thrift/example/artificial/CycleBObj.java @@ -1,6 +1,6 @@ package com.thrift.example.artificial; public class CycleBObj { - + public String bID; public CycleAObj obj; } diff --git a/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExample.java b/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExample.java index 7229e890c0..c4cc69f321 100644 --- a/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExample.java +++ b/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExample.java @@ -28,7 +28,7 @@ public interface RPCInterfaceExample { ObjectResponse objResponse(); - CycleAObj objCycleA(); + CycleAObj objCycleA(CycleAObj objA); CycleBObj objCycleB(); diff --git a/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExampleImpl.java b/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExampleImpl.java index 4a53acc964..4a50fb1515 100644 --- a/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExampleImpl.java +++ b/client-java/controller/src/test/java/com/thrift/example/artificial/RPCInterfaceExampleImpl.java @@ -85,8 +85,8 @@ public ObjectResponse objResponse() { } @Override - public CycleAObj objCycleA() { - return null; + public CycleAObj objCycleA(CycleAObj objA) { + return objA; } @Override diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/ExampleBuilderTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/ExampleBuilderTest.java index aeb70b77ef..a4e31238c1 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/ExampleBuilderTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/ExampleBuilderTest.java @@ -1,5 +1,6 @@ package org.evomaster.client.java.controller.problem.rpc; +import com.fasterxml.jackson.core.JsonProcessingException; import com.thrift.example.artificial.*; import org.evomaster.client.java.controller.api.dto.*; import org.evomaster.client.java.controller.problem.rpc.schema.EndpointSchema; @@ -9,12 +10,10 @@ import org.evomaster.client.java.controller.problem.rpc.schema.params.*; import org.evomaster.client.java.controller.problem.rpc.schema.types.*; import org.evomaster.client.java.controller.api.dto.problem.rpc.RPCType; -import org.glassfish.jersey.server.model.Suspendable; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.math.BigInteger; -import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.*; import java.util.stream.Collectors; @@ -1264,7 +1263,7 @@ public void testObjResponse() { public void testObjCycleA() { EndpointSchema endpoint = getOneEndpoint("objCycleA"); - assertEquals(0, endpoint.getRequestParams().size()); + assertEquals(1, endpoint.getRequestParams().size()); assertNotNull(endpoint.getResponse()); NamedTypedValue param = endpoint.getResponse(); @@ -1272,10 +1271,10 @@ public void testObjCycleA() { assertTrue(param.getType() instanceof ObjectType); List fs = ((ObjectType) param.getType()).getFields(); - assertEquals(1, fs.size()); - assertTrue(fs.get(0) instanceof ObjectParam); - assertEquals(1, ((ObjectParam) fs.get(0)).getType().getFields().size()); - assertTrue(((ObjectParam) fs.get(0)).getType().getFields().get(0).getType() instanceof CycleObjectType); + assertEquals(2, fs.size()); + assertTrue(fs.get(1) instanceof ObjectParam); + assertEquals(2, ((ObjectParam) fs.get(1)).getType().getFields().size()); + assertTrue(((ObjectParam) fs.get(1)).getType().getFields().get(1).getType() instanceof CycleObjectType); } @@ -1291,10 +1290,44 @@ public void testObjCycleB() { assertTrue(param.getType() instanceof ObjectType); List fs = ((ObjectType) param.getType()).getFields(); - assertEquals(1, fs.size()); - assertTrue(fs.get(0) instanceof ObjectParam); - assertEquals(1, ((ObjectParam) fs.get(0)).getType().getFields().size()); - assertTrue(((ObjectParam) fs.get(0)).getType().getFields().get(0).getType() instanceof CycleObjectType); + assertEquals(2, fs.size()); + assertTrue(fs.get(1) instanceof ObjectParam); + assertEquals(2, ((ObjectParam) fs.get(1)).getType().getFields().size()); + assertTrue(((ObjectParam) fs.get(1)).getType().getFields().get(1).getType() instanceof CycleObjectType); + + } + + @Test + public void test2DepthCycleAObj() throws JsonProcessingException, ClassNotFoundException { + EndpointSchema endpoint = getOneEndpoint("objCycleA"); + assertEquals(1, endpoint.getRequestParams().size()); + + CycleAObj objA = new CycleAObj(){{ + aID = "a"; + }}; + CycleBObj objAB = new CycleBObj(){{ + bID = "ab"; + }}; + objA.obj = objAB; + CycleAObj objABA = new CycleAObj(){{ + aID = "aba"; + }}; + objAB.obj = objABA; + CycleBObj objABAB = new CycleBObj(){{ + bID = "abab"; + }}; + objABA.obj = objABAB; + + String expectedJson = mapper.writeValueAsString(objA); + + NamedTypedValue param = endpoint.getRequestParams().get(0); + assertTrue(param instanceof ObjectParam); + param.setValueBasedOnInstance(objA); + Object instance = param.newInstance(); + assertTrue(instance instanceof CycleAObj); + String actualJson = mapper.writeValueAsString(instance); + assertEquals(expectedJson, actualJson); + assertEquals("{\"name\":\"arg0\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"aID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"a\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleBObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleBObj\",\"type\":\"CUSTOM_OBJECT\",\"example\":null,\"depth\":1,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"bID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"ab\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"aID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"aba\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleBObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleBObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"bID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"abab\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":null,\"innerContent\":[],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}",mapper.writeValueAsString(param.getDto())); } diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilderTestBase.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilderTestBase.java index 0243600cc7..671cc40cf7 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilderTestBase.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/RPCEndpointsBuilderTestBase.java @@ -1,5 +1,6 @@ package org.evomaster.client.java.controller.problem.rpc; +import com.fasterxml.jackson.databind.ObjectMapper; import com.thrift.example.artificial.Necessity; import com.thrift.example.artificial.RPCInterfaceExampleImpl; import org.evomaster.client.java.controller.api.dto.AuthenticationDto; @@ -19,6 +20,8 @@ */ public abstract class RPCEndpointsBuilderTestBase { + public ObjectMapper mapper = new ObjectMapper(); + public InterfaceSchema schema = RPCEndpointsBuilder.build(getInterfaceName(), getRPCType(), new RPCInterfaceExampleImpl(), null, null, null, null, getAuthInfo(), getCustomizedValueInRequests(), specifyCustomizedNotNullAnnotation()); public abstract String getInterfaceName(); diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/FakeSutController.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/FakeSutController.java index ccc1f9b75c..80dc3a097f 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/FakeSutController.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/FakeSutController.java @@ -1,6 +1,5 @@ package org.evomaster.client.java.controller.problem.rpc.invocation; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.thrift.example.artificial.BigNumberObj; import com.thrift.example.artificial.RPCInterfaceExample; diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/RPCSutControllerTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/RPCSutControllerTest.java index bdd810fbbf..8bc971ffe6 100644 --- a/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/RPCSutControllerTest.java +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/problem/rpc/invocation/RPCSutControllerTest.java @@ -1,10 +1,9 @@ package org.evomaster.client.java.controller.problem.rpc.invocation; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.thrift.example.artificial.*; import io.restassured.RestAssured; -import io.restassured.common.mapper.TypeRef; -import io.restassured.path.json.JsonPath; -import io.restassured.response.ResponseBodyExtractionOptions; import org.apache.thrift.TApplicationException; import org.apache.thrift.TException; import org.apache.thrift.protocol.TProtocolException; @@ -17,7 +16,6 @@ import org.evomaster.client.java.controller.api.dto.problem.rpc.RPCInterfaceSchemaDto; import org.evomaster.client.java.controller.api.dto.problem.rpc.RPCSupportedDataType; import org.evomaster.client.java.controller.api.dto.problem.rpc.exception.RPCExceptionType; -import org.evomaster.client.java.controller.problem.rpc.schema.params.NamedTypedValue; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -29,7 +27,6 @@ import static io.restassured.RestAssured.given; -import static org.evomaster.client.java.controller.contentMatchers.NumberMatcher.numbersMatch; import static org.hamcrest.CoreMatchers.is; import static org.junit.jupiter.api.Assertions.*; @@ -43,6 +40,8 @@ public class RPCSutControllerTest { private static List interfaceSchemas; private static List> seededTestDtos; + private static ObjectMapper mapper = new ObjectMapper(); + @BeforeAll public static void initClass() { rpcController.setControllerPort(0); @@ -338,6 +337,28 @@ public void testListResponse(){ assertEquals(expectedAssertions, String.join("\n", responseDto.assertionScript)); } + @Test + public void testCycleAObj() throws JsonProcessingException { + List dtos = interfaceSchemas.get(0).endpoints.stream().filter(s-> s.actionName.equals("objCycleA")).collect(Collectors.toList()); + assertEquals(1, dtos.size()); + RPCActionDto dto = dtos.get(0).copy(); + assertEquals(1, dto.requestParams.size()); + dto.doGenerateAssertions = true; + dto.doGenerateTestScript = true; + dto.controllerVariable = "rpcController"; + + String json = "{\"name\":\"arg0\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"aID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"a\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleBObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleBObj\",\"type\":\"CUSTOM_OBJECT\",\"example\":null,\"depth\":1,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"bID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"ab\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"aID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"aba\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleBObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleBObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"{}\",\"innerContent\":[{\"name\":\"bID\",\"type\":{\"fullTypeName\":\"java.lang.String\",\"fullTypeNameWithGenericType\":\"java.lang.String\",\"type\":\"STRING\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":\"abab\",\"innerContent\":null,\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":true,\"maxInclusive\":true,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null},{\"name\":\"obj\",\"type\":{\"fullTypeName\":\"com.thrift.example.artificial.CycleAObj\",\"fullTypeNameWithGenericType\":\"com.thrift.example.artificial.CycleAObj\",\"type\":\"CUSTOM_CYCLE_OBJECT\",\"example\":null,\"depth\":0,\"fixedItems\":null,\"precision\":-1},\"stringValue\":null,\"innerContent\":[],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}],\"isNullable\":true,\"minSize\":null,\"maxSize\":null,\"minValue\":null,\"maxValue\":null,\"precision\":null,\"scale\":null,\"minInclusive\":false,\"maxInclusive\":false,\"pattern\":null,\"candidates\":null,\"candidateReferences\":null,\"isMutable\":true,\"defaultValue\":null}"; + + ParamDto cycleA2depth = mapper.readValue(json, ParamDto.class); + dto.requestParams.clear(); + dto.requestParams.add(cycleA2depth); + + ActionResponseDto responseDto = new ActionResponseDto(); + rpcController.executeAction(dto, responseDto); + + assertEquals("{\"aID\":\"a\",\"obj\":{\"bID\":\"ab\",\"obj\":{\"aID\":\"aba\",\"obj\":{\"bID\":\"abab\",\"obj\":null}}}}", responseDto.jsonResponse); + } + @Test public void testBigNumber(){ List dtos = interfaceSchemas.get(0).endpoints.stream().filter(s-> s.actionName.equals("bigNumber")).collect(Collectors.toList()); diff --git a/core/src/main/kotlin/org/evomaster/core/problem/rpc/service/RPCEndpointsHandler.kt b/core/src/main/kotlin/org/evomaster/core/problem/rpc/service/RPCEndpointsHandler.kt index 8596dbceb0..b9b8cc074e 100644 --- a/core/src/main/kotlin/org/evomaster/core/problem/rpc/service/RPCEndpointsHandler.kt +++ b/core/src/main/kotlin/org/evomaster/core/problem/rpc/service/RPCEndpointsHandler.kt @@ -40,6 +40,7 @@ import org.evomaster.core.search.gene.collection.PairGene import org.evomaster.core.search.gene.datetime.DateTimeGene import org.evomaster.core.search.gene.numeric.* import org.evomaster.core.search.gene.optional.CustomMutationRateGene +import org.evomaster.core.search.gene.optional.FlexibleCycleObjectGene import org.evomaster.core.search.gene.optional.OptionalGene import org.evomaster.core.search.gene.placeholder.CycleObjectGene import org.evomaster.core.search.gene.regex.RegexGene @@ -437,7 +438,7 @@ class RPCEndpointsHandler { setAuthInfo(infoDto) - // handle seeded test dto + // handle seeded external service info dto infoDto.rpcProblem.seededTestDtos?.forEach { t-> t.forEach { a-> extractRPCExternalServiceAction(infoDto, a) @@ -659,6 +660,19 @@ class RPCEndpointsHandler { } is ObjectGene -> { valueGene.fields.forEach { f-> + val cpdto = dto.innerContent.find { it.name == f.name } + if (cpdto == null){ + if (valueGene.parent is FlexibleCycleObjectGene){ + Lazy.assert { dto.innerContent == null || dto.innerContent.isEmpty() } + val found = actionSchemaCluster.values + .flatMap { it.requestParams } + .find { p-> p.type.fullTypeNameWithGenericType == valueGene.refType || p.findObjectByTypeName(valueGene.refType) != null} + ?:throw IllegalStateException("could not find template object (${valueGene.refType}) in actionSchemaCluster") + val objTemplate = if (found.type.fullTypeNameWithGenericType == valueGene.refType) found else found.findObjectByTypeName(valueGene.refType) + dto.innerContent = (objTemplate!!.copy()).innerContent + }else + throw IllegalStateException("could not find the field (${f.name}) in ParamDto") + } val pdto = dto.innerContent.find { it.name == f.name } ?:throw IllegalStateException("could not find the field (${f.name}) in ParamDto") transformGeneToParamDto(f, pdto) @@ -757,8 +771,23 @@ class RPCEndpointsHandler { } } is CycleObjectGene ->{ - if (dto.innerContent != null){ - LoggingUtil.uniqueWarn(log, "NOT support to handle cycle object with more than 2 depth") + if (!isNullDto(dto) && dto.innerContent != null && dto.innerContent.isNotEmpty()){ + if (valueGene.refType!=null && valueGene.parent != null && valueGene.parent is FlexibleCycleObjectGene){ + val template = typeCache[valueGene.refType] + if (template == null || template !is ObjectGene){ + LoggingUtil.uniqueWarn(log, "Cannot find object gene with ${valueGene.refType} in cached types") + }else{ + val replaced = template.copy() as ObjectGene + (valueGene.parent as FlexibleCycleObjectGene).replaceGeneTo(replaced) + replaced.fields.forEach { f-> + val pdto = dto.innerContent.find { it.name == f.name } + ?:throw IllegalStateException("could not find the field (${f.name}) in ParamDto") + setGeneBasedOnParamDto(f, pdto) + } + } + }else{ + LoggingUtil.uniqueWarn(log, "NOT support to handle cycle object with more than 2 depth (refType: ${valueGene.refType}, parent: ${valueGene.parent?.javaClass?.name?:"null-parent"})") + } } } else -> throw IllegalStateException("Not support setGeneBasedOnParamDto with gene ${gene::class.java.simpleName} and dto (${dto.type.type})") @@ -815,7 +844,7 @@ class RPCEndpointsHandler { RPCSupportedDataType.ARRAY, RPCSupportedDataType.SET, RPCSupportedDataType.LIST-> valueGene is ArrayGene<*> RPCSupportedDataType.MAP -> valueGene is FixedMapGene<*, *> RPCSupportedDataType.CUSTOM_OBJECT -> valueGene is ObjectGene || valueGene is FixedMapGene<*, *> - RPCSupportedDataType.CUSTOM_CYCLE_OBJECT -> valueGene is CycleObjectGene + RPCSupportedDataType.CUSTOM_CYCLE_OBJECT -> valueGene is CycleObjectGene || valueGene is FlexibleCycleObjectGene || valueGene is ObjectGene RPCSupportedDataType.UTIL_DATE -> valueGene is DateTimeGene RPCSupportedDataType.PAIR -> valueGene is PairGene<*, *> RPCSupportedDataType.BIGDECIMAL -> valueGene is BigDecimalGene @@ -927,7 +956,7 @@ class RPCEndpointsHandler { RPCSupportedDataType.MAP -> handleMapParam(param, building) RPCSupportedDataType.UTIL_DATE -> handleUtilDate(param) RPCSupportedDataType.CUSTOM_OBJECT -> handleObjectParam(param) - RPCSupportedDataType.CUSTOM_CYCLE_OBJECT -> CycleObjectGene(param.name) + RPCSupportedDataType.CUSTOM_CYCLE_OBJECT -> FlexibleCycleObjectGene(param.name, CycleObjectGene(param.name, param.type.fullTypeNameWithGenericType)) RPCSupportedDataType.PAIR -> throw IllegalStateException("ERROR: pair should be handled inside Map") RPCSupportedDataType.BIGINTEGER -> BigIntegerGene(param.name, min = param.minValue?.toBigIntegerOrNull(), max = param.maxValue?.toBigIntegerOrNull(), diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/MapGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/MapGene.kt index 04a194a981..0ec9a0d116 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/collection/MapGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/collection/MapGene.kt @@ -61,10 +61,20 @@ abstract class MapGene( killAllChildren() log.trace("Randomizing MapGene") val n = randomness.nextInt(getMinSizeOrDefault(), getMaxSizeUsedInRandomize()) - (0 until n).forEach { - val gene = addRandomElement(randomness, false) + + addNElements(n, randomness) + + if (getSizeOfElements(false) < n && getSizeOfElements(false) < getMinSizeOrDefault()){ + addNElements(n-getSizeOfElements(false), randomness) + if (getSizeOfElements(false) < getMinSizeOrDefault()) + log.warn("cannot create ${getMinSizeOrDefault()} elements in order to satisfy its ${getMinSizeOrDefault()} min size") + } + } + + private fun addNElements(n : Int, randomness: Randomness){ + (0 until n).forEach { _ -> // if the key of gene exists, the value would be replaced with the latest one - addElement(gene) + addElement(sampleRandomElementToAdd(randomness, false)) } } @@ -108,7 +118,7 @@ abstract class MapGene( override fun shallowMutate(randomness: Randomness, apc: AdaptiveParameterControl, mwc: MutationWeightControl, selectionStrategy: SubsetGeneMutationSelectionStrategy, enableAdaptiveGeneMutation: Boolean, additionalGeneMutationInfo: AdditionalGeneMutationInfo?) : Boolean{ if(elements.size < getMaxSizeOrDefault() && (elements.size == getMinSizeOrDefault() || elements.isEmpty() || randomness.nextBoolean())){ - val gene = addRandomElement(randomness, false) + val gene = sampleRandomElementToAdd(randomness, false) addElement(gene) } else { log.trace("Removing gene in mutation") @@ -186,10 +196,10 @@ abstract class MapGene( * add [element] (key to value) to [elements], * if the key of [element] exists in [elements], * we replace the existing one with [element] + * @return whether a new element is added */ - fun addElement(element: PairGene){ + fun addElement(element: PairGene) { checkConstraintsForAdd() - getElementsBy(element).forEach { e-> removeExistingElement(e) } @@ -238,7 +248,7 @@ abstract class MapGene( return listOf() } - private fun addRandomElement(randomness: Randomness, forceNewValue: Boolean) : PairGene { + private fun sampleRandomElementToAdd(randomness: Randomness, forceNewValue: Boolean) : PairGene { val keyName = "key_${keyCounter++}" val gene = template.copy() as PairGene diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleCycleObjectGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleCycleObjectGene.kt new file mode 100644 index 0000000000..3bbe81c132 --- /dev/null +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleCycleObjectGene.kt @@ -0,0 +1,39 @@ +package org.evomaster.core.search.gene.optional + +import org.evomaster.core.search.gene.Gene +import org.evomaster.core.search.gene.ObjectGene +import org.evomaster.core.search.gene.placeholder.CycleObjectGene + +/** + * there might be a case where the 2 depth cycle is not enough to handle seeded value or responses + * this class allows to replace a CycleObject with its ObjectGene based on the refType + */ +class FlexibleCycleObjectGene( + name: String, + gene: Gene, + replaceable: Boolean = true +) : FlexibleGene(name, gene, replaceable) { + + init { + if (gene !is ObjectGene && gene !is CycleObjectGene) + throw IllegalArgumentException("For a FlexibleCycleObjectGene, its gene is either ObjectGene or CycleObjectGene") + } + + override fun copyContent(): FlexibleCycleObjectGene { + return FlexibleCycleObjectGene(name, gene.copy(), replaceable) + } + + override fun replaceGeneTo(geneToUpdate: Gene) { + if (geneToUpdate !is ObjectGene && geneToUpdate !is CycleObjectGene) + throw IllegalArgumentException("For a FlexibleCycleObjectGene, its gene is either ObjectGene or CycleObjectGene") + + val currentRefType = if (gene is ObjectGene) (gene as ObjectGene).refType else (gene as CycleObjectGene).refType + val replacedRefType = if (geneToUpdate is ObjectGene) geneToUpdate.refType else (geneToUpdate as CycleObjectGene).refType + + if (currentRefType != replacedRefType) + throw IllegalArgumentException("Cannot replace a FlexibleCycleObjectGene with a gene which has different refType with current gene (current is $currentRefType and replaced is $replacedRefType)") + + super.replaceGeneTo(geneToUpdate) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleGene.kt index 0fa3ea6e77..68e512b354 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/optional/FlexibleGene.kt @@ -21,13 +21,13 @@ import org.slf4j.LoggerFactory * might not follow a fixed typed. FlexibleMap is added, might need it for * array gene */ -class FlexibleGene(name: String, +open class FlexibleGene(name: String, gene: Gene, - private var replaceable: Boolean = true + protected var replaceable: Boolean = true ) : CompositeGene(name, mutableListOf(gene)) { init { - geneCheck(gene) + validateGeneToReplace(gene) } companion object{ @@ -53,10 +53,10 @@ class FlexibleGene(name: String, replaceable = false } - fun replaceGeneTo(geneToUpdate: Gene){ + open fun replaceGeneTo(geneToUpdate: Gene){ if (!replaceable) throw IllegalStateException("attempt to replace the gene which is not replaceable") - geneCheck(geneToUpdate) + validateGeneToReplace(geneToUpdate) Lazy.assert { children.size == 1 } killAllChildren() @@ -148,7 +148,7 @@ class FlexibleGene(name: String, return gene.getValueAsRawString() } - private fun geneCheck(geneToBeUpdated : Gene){ + private fun validateGeneToReplace(geneToBeUpdated : Gene){ if (geneToBeUpdated is FlexibleGene){ throw IllegalArgumentException("For a FlexibleGene, its gene to be employed or updated cannot be FlexibleGene") } diff --git a/core/src/main/kotlin/org/evomaster/core/search/gene/placeholder/CycleObjectGene.kt b/core/src/main/kotlin/org/evomaster/core/search/gene/placeholder/CycleObjectGene.kt index 24b11c6b55..3817b8452e 100644 --- a/core/src/main/kotlin/org/evomaster/core/search/gene/placeholder/CycleObjectGene.kt +++ b/core/src/main/kotlin/org/evomaster/core/search/gene/placeholder/CycleObjectGene.kt @@ -15,16 +15,17 @@ import org.evomaster.core.search.service.Randomness * TODO need to handle cases when some of those are * marked with "required" * - * Note that for [CycleObjectGene], its [refType] is null + * link CycleObjectGene with ObjectGene using [refType] if it has + * eg, for RPC, refType is the full name of jvm class */ -class CycleObjectGene(name: String) : SimpleGene(name) { +class CycleObjectGene(name: String, val refType : String? = null) : SimpleGene(name) { override fun isMutable() = false override fun isLocallyValid() : Boolean{ return true } - override fun copyContent(): Gene = CycleObjectGene(name) + override fun copyContent(): Gene = CycleObjectGene(name, refType) override fun setValueWithRawString(value: String) { throw IllegalStateException("cannot set value with string ($value) for CycleObjectGene") diff --git a/core/src/test/kotlin/org/evomaster/core/search/gene/GeneSamplerForTests.kt b/core/src/test/kotlin/org/evomaster/core/search/gene/GeneSamplerForTests.kt index 966ebfa6dc..cb70676343 100644 --- a/core/src/test/kotlin/org/evomaster/core/search/gene/GeneSamplerForTests.kt +++ b/core/src/test/kotlin/org/evomaster/core/search/gene/GeneSamplerForTests.kt @@ -85,7 +85,11 @@ object GeneSamplerForTests { } - fun sample(klass: KClass, rand: Randomness): T where T : Gene { + /** + * @param rangeDelta represents a min delta between min and max if the gene has + * this is used for eg, the min size of MapGene is 2, but the max length of the string key gene is 0 + */ + fun sample(klass: KClass, rand: Randomness, rangeDelta: Int? = null): T where T : Gene { return when (klass) { /* @@ -94,80 +98,81 @@ object GeneSamplerForTests { when genes need input genes, we sample those at random as well */ - TaintedArrayGene::class -> sampleTaintedArrayGene(rand) as T - ArrayGene::class -> sampleArrayGene(rand) as T - Base64StringGene::class -> sampleBase64StringGene(rand) as T - BigDecimalGene::class -> sampleBigDecimalGene(rand) as T - BigIntegerGene::class -> sampleBigIntegerGene(rand) as T - BooleanGene::class -> sampleBooleanGene(rand) as T - CycleObjectGene::class -> sampleCycleObjectGene(rand) as T - CustomMutationRateGene::class -> sampleDisruptiveGene(rand) as T - DoubleGene::class -> sampleDoubleGene(rand) as T - EnumGene::class -> sampleEnumGene(rand) as T - FloatGene::class -> sampleFloatGene(rand) as T - ImmutableDataHolderGene::class -> sampleImmutableDataHolderGene(rand) as T - IntegerGene::class -> sampleIntegerGene(rand) as T - LimitObjectGene::class -> sampleLimitObjectGene(rand) as T - LongGene::class -> sampleLongGene(rand) as T - FixedMapGene::class -> sampleFixedMapGene(rand) as T - FlexibleMapGene::class -> sampleFlexibleMapGene(rand) as T - FlexibleGene::class -> samplePrintableFlexibleGene(rand) as T - NumericStringGene::class -> sampleNumericStringGene(rand) as T - ObjectGene::class -> sampleObjectGene(rand) as T - OptionalGene::class -> sampleOptionalGene(rand) as T - ChoiceGene::class -> sampleChoiceGene(rand) as T - PairGene::class -> samplePairGene(rand) as T - SeededGene::class -> sampleSeededGene(rand) as T - StringGene::class -> sampleStringGene(rand) as T - TupleGene::class -> sampleTupleGene(rand) as T - DateGene::class -> sampleDateGene(rand) as T - DateTimeGene::class -> sampleDateGene(rand) as T - TimeGene::class -> sampleTimeGene(rand) as T - AnyCharacterRxGene::class -> sampleAnyCharacterRxGene(rand) as T - CharacterClassEscapeRxGene::class -> sampleCharacterClassEscapeRxGene(rand) as T - CharacterRangeRxGene::class -> sampleCharacterRangeRxGene(rand) as T - DisjunctionRxGene::class -> sampleDisjunctionRxGene(rand) as T - DisjunctionListRxGene::class -> sampleDisjunctionListRxGene(rand) as T - PatternCharacterBlockGene::class -> samplePatternCharacterBlock(rand) as T - QuantifierRxGene::class -> sampleQuantifierRxGene(rand) as T - RegexGene::class -> sampleRegexGene(rand) as T + TaintedArrayGene::class -> sampleTaintedArrayGene(rand, rangeDelta) as T + ArrayGene::class -> sampleArrayGene(rand, rangeDelta) as T + Base64StringGene::class -> sampleBase64StringGene(rand, rangeDelta) as T + BigDecimalGene::class -> sampleBigDecimalGene(rand, rangeDelta) as T + BigIntegerGene::class -> sampleBigIntegerGene(rand, rangeDelta) as T + BooleanGene::class -> sampleBooleanGene(rand, rangeDelta) as T + CycleObjectGene::class -> sampleCycleObjectGene(rand, rangeDelta) as T + CustomMutationRateGene::class -> sampleDisruptiveGene(rand, rangeDelta) as T + DoubleGene::class -> sampleDoubleGene(rand, rangeDelta) as T + EnumGene::class -> sampleEnumGene(rand, rangeDelta) as T + FloatGene::class -> sampleFloatGene(rand, rangeDelta) as T + ImmutableDataHolderGene::class -> sampleImmutableDataHolderGene(rand, rangeDelta) as T + IntegerGene::class -> sampleIntegerGene(rand, rangeDelta) as T + LimitObjectGene::class -> sampleLimitObjectGene(rand, rangeDelta) as T + LongGene::class -> sampleLongGene(rand, rangeDelta) as T + FixedMapGene::class -> sampleFixedMapGene(rand, rangeDelta) as T + FlexibleMapGene::class -> sampleFlexibleMapGene(rand, rangeDelta) as T + FlexibleGene::class -> samplePrintableFlexibleGene(rand, rangeDelta) as T + FlexibleCycleObjectGene::class -> sampleFlexibleCycleObjectGene(rand, rangeDelta) as T + NumericStringGene::class -> sampleNumericStringGene(rand, rangeDelta) as T + ObjectGene::class -> sampleObjectGene(rand, rangeDelta) as T + OptionalGene::class -> sampleOptionalGene(rand, rangeDelta) as T + ChoiceGene::class -> sampleChoiceGene(rand, rangeDelta) as T + PairGene::class -> samplePairGene(rand, rangeDelta) as T + SeededGene::class -> sampleSeededGene(rand, rangeDelta) as T + StringGene::class -> sampleStringGene(rand, rangeDelta) as T + TupleGene::class -> sampleTupleGene(rand, rangeDelta) as T + DateGene::class -> sampleDateGene(rand, rangeDelta) as T + DateTimeGene::class -> sampleDateGene(rand, rangeDelta) as T + TimeGene::class -> sampleTimeGene(rand, rangeDelta) as T + AnyCharacterRxGene::class -> sampleAnyCharacterRxGene(rand, rangeDelta) as T + CharacterClassEscapeRxGene::class -> sampleCharacterClassEscapeRxGene(rand, rangeDelta) as T + CharacterRangeRxGene::class -> sampleCharacterRangeRxGene(rand, rangeDelta) as T + DisjunctionRxGene::class -> sampleDisjunctionRxGene(rand, rangeDelta) as T + DisjunctionListRxGene::class -> sampleDisjunctionListRxGene(rand, rangeDelta) as T + PatternCharacterBlockGene::class -> samplePatternCharacterBlock(rand, rangeDelta) as T + QuantifierRxGene::class -> sampleQuantifierRxGene(rand, rangeDelta) as T + RegexGene::class -> sampleRegexGene(rand, rangeDelta) as T //SQL genes - SqlJSONPathGene::class -> sampleSqlJSONPathGene(rand) as T - SqlTextSearchVectorGene::class -> sampleSqlTextSearchVectorGene(rand) as T - SqlBoxGene::class -> sampleSqlBoxGene(rand) as T - SqlPointGene::class -> sampleSqlPointGene(rand) as T - SqlForeignKeyGene::class -> sampleSqlForeignKeyGene(rand) as T - SqlLogSeqNumberGene::class -> sampleSqlLogSeqNumberGene(rand) as T - SqlRangeGene::class -> sampleSqlRangeGene(rand) as T - SqlJSONGene::class -> sampleSqlJSONGene(rand) as T - SqlTextSearchQueryGene::class -> sampleSqlTextSearchQueryGene(rand) as T - SqlPrimaryKeyGene::class -> sampleSqlPrimaryKeyGene(rand) as T - NullableGene::class -> sampleSqlNullableGene(rand) as T - SqlMultidimensionalArrayGene::class -> sampleSqlMultidimensionalArrayGene(rand) as T - MacAddrGene::class -> sampleSqlMacAddrGene(rand) as T - InetGene::class -> sampleSqlInetGene(rand) as T - CidrGene::class -> sampleSqlCidrGene(rand) as T - SqlAutoIncrementGene::class -> sampleSqlAutoIncrementGene(rand) as T - SqlPathGene::class -> sampleSqlPathGene(rand) as T - SqlMultiPointGene::class -> sampleSqlMultiPointGene(rand) as T - SqlMultiPolygonGene::class -> sampleSqlMultiPolygonGene(rand) as T - SqlMultiPathGene::class -> sampleSqlMultiPathGene(rand) as T - SqlLineGene::class -> sampleSqlLineGene(rand) as T - SqlPolygonGene::class -> sampleSqlPolygonGene(rand) as T - SqlCircleGene::class -> sampleSqlCircleGene(rand) as T - SqlLineSegmentGene::class -> sampleSqlLineSegmentGene(rand) as T - SqlTimeIntervalGene::class -> sampleSqlTimeIntervalGene(rand) as T - SqlCompositeGene::class -> sampleSqlCompositeGene(rand) as T - SqlBitStringGene::class -> sampleSqlBitStringGene(rand) as T - SqlXMLGene::class -> sampleSqlXMLGene(rand) as T - SqlMultiRangeGene::class -> sampleSqlMultiRangeGene(rand) as T - SqlBinaryStringGene::class -> sampleSqlBinaryStringGene(rand) as T - UUIDGene::class -> sampleSqlUUIDGene(rand) as T - SqlGeometryCollectionGene::class -> sampleSqlGeometryCollectionGene(rand) as T - UriGene::class -> sampleUrlGene(rand) as T - UrlHttpGene::class -> sampleUrlHttpGene(rand) as T - UriDataGene::class -> sampleUrlDataGene(rand) as T + SqlJSONPathGene::class -> sampleSqlJSONPathGene(rand, rangeDelta) as T + SqlTextSearchVectorGene::class -> sampleSqlTextSearchVectorGene(rand, rangeDelta) as T + SqlBoxGene::class -> sampleSqlBoxGene(rand, rangeDelta) as T + SqlPointGene::class -> sampleSqlPointGene(rand, rangeDelta) as T + SqlForeignKeyGene::class -> sampleSqlForeignKeyGene(rand, rangeDelta) as T + SqlLogSeqNumberGene::class -> sampleSqlLogSeqNumberGene(rand, rangeDelta) as T + SqlRangeGene::class -> sampleSqlRangeGene(rand, rangeDelta) as T + SqlJSONGene::class -> sampleSqlJSONGene(rand, rangeDelta) as T + SqlTextSearchQueryGene::class -> sampleSqlTextSearchQueryGene(rand, rangeDelta) as T + SqlPrimaryKeyGene::class -> sampleSqlPrimaryKeyGene(rand, rangeDelta) as T + NullableGene::class -> sampleSqlNullableGene(rand, rangeDelta) as T + SqlMultidimensionalArrayGene::class -> sampleSqlMultidimensionalArrayGene(rand, rangeDelta) as T + MacAddrGene::class -> sampleSqlMacAddrGene(rand, rangeDelta) as T + InetGene::class -> sampleSqlInetGene(rand, rangeDelta) as T + CidrGene::class -> sampleSqlCidrGene(rand, rangeDelta) as T + SqlAutoIncrementGene::class -> sampleSqlAutoIncrementGene(rand, rangeDelta) as T + SqlPathGene::class -> sampleSqlPathGene(rand, rangeDelta) as T + SqlMultiPointGene::class -> sampleSqlMultiPointGene(rand, rangeDelta) as T + SqlMultiPolygonGene::class -> sampleSqlMultiPolygonGene(rand, rangeDelta) as T + SqlMultiPathGene::class -> sampleSqlMultiPathGene(rand, rangeDelta) as T + SqlLineGene::class -> sampleSqlLineGene(rand, rangeDelta) as T + SqlPolygonGene::class -> sampleSqlPolygonGene(rand, rangeDelta) as T + SqlCircleGene::class -> sampleSqlCircleGene(rand, rangeDelta) as T + SqlLineSegmentGene::class -> sampleSqlLineSegmentGene(rand, rangeDelta) as T + SqlTimeIntervalGene::class -> sampleSqlTimeIntervalGene(rand, rangeDelta) as T + SqlCompositeGene::class -> sampleSqlCompositeGene(rand, rangeDelta) as T + SqlBitStringGene::class -> sampleSqlBitStringGene(rand, rangeDelta) as T + SqlXMLGene::class -> sampleSqlXMLGene(rand, rangeDelta) as T + SqlMultiRangeGene::class -> sampleSqlMultiRangeGene(rand, rangeDelta) as T + SqlBinaryStringGene::class -> sampleSqlBinaryStringGene(rand, rangeDelta) as T + UUIDGene::class -> sampleSqlUUIDGene(rand, rangeDelta) as T + SqlGeometryCollectionGene::class -> sampleSqlGeometryCollectionGene(rand, rangeDelta) as T + UriGene::class -> sampleUrlGene(rand, rangeDelta) as T + UrlHttpGene::class -> sampleUrlHttpGene(rand, rangeDelta) as T + UriDataGene::class -> sampleUrlDataGene(rand, rangeDelta) as T else -> throw IllegalStateException("No sampler for $klass") } @@ -175,39 +180,39 @@ object GeneSamplerForTests { - private fun sampleUrlDataGene(rand: Randomness): UriDataGene { + private fun sampleUrlDataGene(rand: Randomness, rangeDelta: Int? = null): UriDataGene { return UriDataGene("rand UrlDataGene ${rand.nextInt()}") } - private fun sampleUrlHttpGene(rand: Randomness): UrlHttpGene { + private fun sampleUrlHttpGene(rand: Randomness, rangeDelta: Int? = null): UrlHttpGene { return UrlHttpGene("rand UrlHttpGene ${rand.nextInt()}") } - private fun sampleUrlGene(rand: Randomness): UriGene { + private fun sampleUrlGene(rand: Randomness, rangeDelta: Int? = null): UriGene { return UriGene("rand UrlGene ${rand.nextInt()}") } - private fun sampleSqlUUIDGene(rand: Randomness): UUIDGene { + private fun sampleSqlUUIDGene(rand: Randomness, rangeDelta: Int? = null): UUIDGene { return UUIDGene("rand SqlUUIDGene ${rand.nextInt()}") } - private fun sampleSqlBinaryStringGene(rand: Randomness): SqlBinaryStringGene { - val maxSize = rand.nextInt(1, ArrayGene.MAX_SIZE) + private fun sampleSqlBinaryStringGene(rand: Randomness, rangeDelta: Int? = null): SqlBinaryStringGene { + val maxSize = rand.nextInt(max(1, rangeDelta?:0), ArrayGene.MAX_SIZE) val minSize = rand.nextInt(0, maxSize) return SqlBinaryStringGene("rand SqlBinaryStringGene", minSize = minSize, maxSize = maxSize) } - private fun sampleSqlMultiRangeGene(rand: Randomness): SqlMultiRangeGene<*> { - return SqlMultiRangeGene("rand SqlMultiRangeGene", template = sampleSqlRangeGene(rand)) + private fun sampleSqlMultiRangeGene(rand: Randomness, rangeDelta: Int? = null): SqlMultiRangeGene<*> { + return SqlMultiRangeGene("rand SqlMultiRangeGene", template = sampleSqlRangeGene(rand, rangeDelta)) } - private fun sampleSqlXMLGene(rand: Randomness): SqlXMLGene { + private fun sampleSqlXMLGene(rand: Randomness, rangeDelta: Int? = null): SqlXMLGene { return SqlXMLGene("rand SqlXMLGene ${rand.nextInt()}") } - private fun sampleSqlBitStringGene(rand: Randomness): SqlBitStringGene { + private fun sampleSqlBitStringGene(rand: Randomness, rangeDelta: Int? = null): SqlBitStringGene { val maxSize = rand.nextInt(1, ArrayGene.MAX_SIZE) val minSize = rand.nextInt(0, maxSize) return SqlBitStringGene("rand SqlBitStringGene", @@ -215,17 +220,17 @@ object GeneSamplerForTests { maxSize = maxSize) } - private fun sampleSqlCompositeGene(rand: Randomness): SqlCompositeGene { + private fun sampleSqlCompositeGene(rand: Randomness, rangeDelta: Int? = null): SqlCompositeGene { val selection = geneClasses.filter { !it.isAbstract } val numberOfFields = rand.nextInt(1, MAX_NUMBER_OF_FIELDS) return SqlCompositeGene( name = "rand SqlCompositeGene", - fields = List(numberOfFields) { sample(rand.choose(selection), rand) } + fields = List(numberOfFields) { sample(rand.choose(selection), rand, rangeDelta) } ) } - private fun sampleSqlTimeIntervalGene(rand: Randomness): SqlTimeIntervalGene { + private fun sampleSqlTimeIntervalGene(rand: Randomness, rangeDelta: Int? = null): SqlTimeIntervalGene { val timeGeneFormats = listOf(TimeGene.TimeGeneFormat.ISO_LOCAL_DATE_FORMAT, TimeGene.TimeGeneFormat.TIME_WITH_MILLISECONDS) val timeGeneFormat = rand.choose(timeGeneFormats) @@ -233,60 +238,60 @@ object GeneSamplerForTests { time = TimeGene("hoursMinutesAndSeconds", timeGeneFormat = timeGeneFormat)) } - private fun sampleSqlLineSegmentGene(rand: Randomness): SqlLineSegmentGene { + private fun sampleSqlLineSegmentGene(rand: Randomness, rangeDelta: Int? = null): SqlLineSegmentGene { return SqlLineSegmentGene("rand SqlLineSegmentGene ${rand.nextInt()}") } - private fun sampleSqlCircleGene(rand: Randomness): SqlCircleGene { + private fun sampleSqlCircleGene(rand: Randomness, rangeDelta: Int? = null): SqlCircleGene { return SqlCircleGene("rand SqlCircleGene ${rand.nextInt()}") } - private fun sampleSqlPolygonGene(rand: Randomness): SqlPolygonGene { + private fun sampleSqlPolygonGene(rand: Randomness, rangeDelta: Int? = null): SqlPolygonGene { return SqlPolygonGene("rand SqlPolygonGene ${rand.nextInt()}") } - private fun sampleSqlLineGene(rand: Randomness): SqlLineGene { + private fun sampleSqlLineGene(rand: Randomness, rangeDelta: Int? = null): SqlLineGene { return SqlLineGene("rand SqlLineGene ${rand.nextInt()}") } - private fun sampleSqlPathGene(rand: Randomness): SqlPathGene { + private fun sampleSqlPathGene(rand: Randomness, rangeDelta: Int? = null): SqlPathGene { return SqlPathGene("rand SqlPathGene ${rand.nextInt()}") } - private fun sampleSqlMultiPointGene(rand: Randomness) = SqlMultiPointGene("rand SqlMultiPointGene ${rand.nextInt()}") + private fun sampleSqlMultiPointGene(rand: Randomness, rangeDelta: Int? = null) = SqlMultiPointGene("rand SqlMultiPointGene ${rand.nextInt()}") - private fun sampleSqlGeometryCollectionGene(rand: Randomness): SqlGeometryCollectionGene { + private fun sampleSqlGeometryCollectionGene(rand: Randomness, range: Int? = null): SqlGeometryCollectionGene { return SqlGeometryCollectionGene("rand SqlGeometryCollectionGene ${rand.nextInt()}", - template = ChoiceGene(name = "rand ChoiceGene", listOf(sample(SqlPointGene::class, rand), - sample(SqlPathGene::class, rand), sample(SqlMultiPointGene::class, rand), - sample(SqlMultiPathGene::class, rand), - sample(SqlPolygonGene::class, rand), - sample(SqlMultiPolygonGene::class, rand))) + template = ChoiceGene(name = "rand ChoiceGene", listOf(sample(SqlPointGene::class, rand, range), + sample(SqlPathGene::class, rand, range), sample(SqlMultiPointGene::class, rand, range), + sample(SqlMultiPathGene::class, rand, range), + sample(SqlPolygonGene::class, rand, range), + sample(SqlMultiPolygonGene::class, rand, range))) ) } - private fun sampleSqlMultiPolygonGene(rand: Randomness): SqlMultiPolygonGene { + private fun sampleSqlMultiPolygonGene(rand: Randomness, rangeDelta: Int? = null): SqlMultiPolygonGene { return SqlMultiPolygonGene("rand SqlMultiPolygonGene ${rand.nextInt()}") } - private fun sampleSqlMultiPathGene(rand: Randomness): SqlMultiPathGene { + private fun sampleSqlMultiPathGene(rand: Randomness, rangeDelta: Int? = null): SqlMultiPathGene { return SqlMultiPathGene("rand SqlMultiPathGene ${rand.nextInt()}") } - private fun sampleSqlAutoIncrementGene(rand: Randomness): SqlAutoIncrementGene { + private fun sampleSqlAutoIncrementGene(rand: Randomness, rangeDelta: Int? = null): SqlAutoIncrementGene { return SqlAutoIncrementGene("rand SqlAutoIncrementGene ${rand.nextInt()}") } - private fun sampleSqlCidrGene(rand: Randomness): CidrGene { + private fun sampleSqlCidrGene(rand: Randomness, rangeDelta: Int? = null): CidrGene { return CidrGene("rand SqlCidrGene ${rand.nextInt()}") } - private fun sampleSqlInetGene(rand: Randomness): InetGene { + private fun sampleSqlInetGene(rand: Randomness, rangeDelta: Int? = null): InetGene { return InetGene("rand SqlInetGene ${rand.nextInt()}") } - private fun sampleSqlMacAddrGene(rand: Randomness): MacAddrGene { + private fun sampleSqlMacAddrGene(rand: Randomness, rangeDelta: Int? = null): MacAddrGene { return MacAddrGene("rand SqlMacAddrGene ${rand.nextInt()}", numberOfOctets = rand.nextInt(1, MAX_NUMBER_OF_OCTETS)) } @@ -303,44 +308,44 @@ object GeneSamplerForTests { // TODO might filter out some more genes here } - private fun sampleSqlMultidimensionalArrayGene(rand: Randomness): SqlMultidimensionalArrayGene<*> { + private fun sampleSqlMultidimensionalArrayGene(rand: Randomness, rangeDelta: Int? = null): SqlMultidimensionalArrayGene<*> { val selection = selectionForArrayTemplate() - val template = samplePrintableTemplate(selection, rand) + val template = samplePrintableTemplate(selection, rand, rangeDelta) return SqlMultidimensionalArrayGene("rand SqlMultidimensionalArrayGene", template = template, numberOfDimensions = rand.nextInt(1, MAX_NUMBER_OF_DIMENSIONS)) } - private fun sampleSqlNullableGene(rand: Randomness): NullableGene { + private fun sampleSqlNullableGene(rand: Randomness, rangeDelta: Int? = null): NullableGene { val selection = geneClasses.filter { !it.isAbstract } .filter { it.java != SqlForeignKeyGene::class.java } return NullableGene("rand NullableGene", - gene = sample(rand.choose(selection), rand)) + gene = sample(rand.choose(selection), rand, rangeDelta)) } - private fun sampleSqlPrimaryKeyGene(rand: Randomness): SqlPrimaryKeyGene { + private fun sampleSqlPrimaryKeyGene(rand: Randomness, rangeDelta: Int? = null): SqlPrimaryKeyGene { val selection = geneClasses.filter { !it.isAbstract && it.isSubclassOf(ComparableGene::class) } return SqlPrimaryKeyGene("rand SqlPrimaryKeyGene", tableName = "rand tableName", - gene = sample(rand.choose(selection), rand), + gene = sample(rand.choose(selection), rand, rangeDelta), uniqueId = rand.nextLong(0, Long.MAX_VALUE)) } - private fun sampleSqlTextSearchQueryGene(rand: Randomness): SqlTextSearchQueryGene { + private fun sampleSqlTextSearchQueryGene(rand: Randomness, rangeDelta: Int? = null): SqlTextSearchQueryGene { return SqlTextSearchQueryGene("rand SqlTextSearchQueryGene ${rand.nextInt()}") } - private fun sampleSqlJSONGene(rand: Randomness): SqlJSONGene { + private fun sampleSqlJSONGene(rand: Randomness, rangeDelta: Int? = null): SqlJSONGene { return SqlJSONGene("rand SqlJSONGene ${rand.nextInt()}") } - private fun sampleSqlRangeGene(rand: Randomness): SqlRangeGene<*> { + private fun sampleSqlRangeGene(rand: Randomness, rangeDelta: Int? = null): SqlRangeGene<*> { val selection = geneClasses.filter { !it.isAbstract && it.isSubclassOf(ComparableGene::class) } val selectedClass = rand.choose(selection) - val templateSample = sample(selectedClass, rand) + val templateSample = sample(selectedClass, rand, rangeDelta) if (templateSample !is ComparableGene) { throw IllegalStateException("${templateSample::class.java} does not implement ComparableGene") } @@ -350,11 +355,11 @@ object GeneSamplerForTests { } - private fun sampleSqlLogSeqNumberGene(rand: Randomness): SqlLogSeqNumberGene { + private fun sampleSqlLogSeqNumberGene(rand: Randomness, rangeDelta: Int? = null): SqlLogSeqNumberGene { return SqlLogSeqNumberGene("rand SqlLogSeqNumberGene ${rand.nextInt()}") } - private fun sampleSqlForeignKeyGene(rand: Randomness): SqlForeignKeyGene { + private fun sampleSqlForeignKeyGene(rand: Randomness, rangeDelta: Int? = null): SqlForeignKeyGene { return SqlForeignKeyGene(sourceColumn = "rand source column", uniqueId = rand.nextLong(min = 0L, max = Long.MAX_VALUE), targetTable = "rand target table", @@ -362,28 +367,28 @@ object GeneSamplerForTests { uniqueIdOfPrimaryKey = rand.nextLong()) } - private fun sampleSqlPointGene(rand: Randomness): SqlPointGene { + private fun sampleSqlPointGene(rand: Randomness, rangeDelta: Int? = null): SqlPointGene { return SqlPointGene("rand SqlPointGene ${rand.nextInt()}") } - private fun sampleSqlBoxGene(rand: Randomness): SqlBoxGene { + private fun sampleSqlBoxGene(rand: Randomness, rangeDelta: Int? = null): SqlBoxGene { return SqlBoxGene("rand SqlBoxGene ${rand.nextInt()}") } - private fun sampleSqlTextSearchVectorGene(rand: Randomness): SqlTextSearchVectorGene { + private fun sampleSqlTextSearchVectorGene(rand: Randomness, rangeDelta: Int? = null): SqlTextSearchVectorGene { return SqlTextSearchVectorGene("rand SqlTextSearchVectorGene ${rand.nextInt()}") } - private fun sampleSqlJSONPathGene(rand: Randomness): SqlJSONPathGene { + private fun sampleSqlJSONPathGene(rand: Randomness, rangeDelta: Int? = null): SqlJSONPathGene { return SqlJSONPathGene("rand JSONPathGene ${rand.nextInt()}") } - fun sampleRegexGene(rand: Randomness): RegexGene { - return RegexGene(name = "rand RegexGene", disjunctions = sampleDisjunctionListRxGene(rand)) + fun sampleRegexGene(rand: Randomness, rangeDelta: Int? = null): RegexGene { + return RegexGene(name = "rand RegexGene", disjunctions = sampleDisjunctionListRxGene(rand, rangeDelta)) } - fun sampleQuantifierRxGene(rand: Randomness): QuantifierRxGene { + fun sampleQuantifierRxGene(rand: Randomness, rangeDelta: Int? = null): QuantifierRxGene { val selection = geneClasses .filter { !it.isAbstract } @@ -392,25 +397,25 @@ object GeneSamplerForTests { return QuantifierRxGene( name = "rand QuantifierRxGene", - template = sample(rand.choose(selection), rand), + template = sample(rand.choose(selection), rand, rangeDelta), min = min, max = min + rand.nextInt(1, 2) ) } - fun samplePatternCharacterBlock(rand: Randomness): PatternCharacterBlockGene { + fun samplePatternCharacterBlock(rand: Randomness, rangeDelta: Int? = null): PatternCharacterBlockGene { return PatternCharacterBlockGene(name = "rand PatternCharacterBlock", stringBlock = rand.nextWordString()) } - fun sampleDisjunctionListRxGene(rand: Randomness): DisjunctionListRxGene { + fun sampleDisjunctionListRxGene(rand: Randomness, rangeDelta: Int? = null): DisjunctionListRxGene { return DisjunctionListRxGene(listOf( - sampleDisjunctionRxGene(rand), - sampleDisjunctionRxGene(rand) + sampleDisjunctionRxGene(rand, rangeDelta), + sampleDisjunctionRxGene(rand, rangeDelta) )) } - fun sampleDisjunctionRxGene(rand: Randomness): DisjunctionRxGene { + fun sampleDisjunctionRxGene(rand: Randomness, rangeDelta: Int? = null): DisjunctionRxGene { val selection = geneClasses .filter { !it.isAbstract } @@ -424,182 +429,191 @@ object GeneSamplerForTests { val numberOfTerms = rand.nextInt(1, 3) return DisjunctionRxGene( name = "rand DisjunctionRxGene", - terms = List(numberOfTerms) { sample(rand.choose(selection), rand) }, + terms = List(numberOfTerms) { sample(rand.choose(selection), rand, rangeDelta) }, matchStart = rand.nextBoolean(), matchEnd = rand.nextBoolean() ) } - fun sampleCharacterRangeRxGene(rand: Randomness): CharacterRangeRxGene { + fun sampleCharacterRangeRxGene(rand: Randomness, rangeDelta: Int? = null): CharacterRangeRxGene { return CharacterRangeRxGene( negated = false, // TODO update once fixed ranges = listOf(Pair('a', 'z')) ) } - fun sampleCharacterClassEscapeRxGene(rand: Randomness): CharacterClassEscapeRxGene { + fun sampleCharacterClassEscapeRxGene(rand: Randomness, rangeDelta: Int? = null): CharacterClassEscapeRxGene { return CharacterClassEscapeRxGene(type = rand.choose(listOf("w", "W", "d", "D", "s", "S"))) } - fun sampleAnyCharacterRxGene(rand: Randomness): AnyCharacterRxGene { + fun sampleAnyCharacterRxGene(rand: Randomness, rangeDelta: Int? = null): AnyCharacterRxGene { return AnyCharacterRxGene() } - fun sampleTimeGene(rand: Randomness): TimeGene { + fun sampleTimeGene(rand: Randomness, rangeDelta: Int? = null): TimeGene { return TimeGene(name = "rand TimeGene") } - fun sampleDateTimeGene(rand: Randomness): DateTimeGene { + fun sampleDateTimeGene(rand: Randomness, rangeDelta: Int? = null): DateTimeGene { return DateTimeGene("rand DateTimeGene") } - fun sampleDateGene(rand: Randomness): DateGene { + fun sampleDateGene(rand: Randomness, rangeDelta: Int? = null): DateGene { return DateGene(name = "rand DateGene", onlyValidDates = rand.nextBoolean()) } - fun sampleSeededGene(rand: Randomness): SeededGene<*> { + fun sampleSeededGene(rand: Randomness, rangeDelta: Int? = null): SeededGene<*> { //TODO update after refactoring SeededGene with ChoiceGene (to implement) return SeededGene( name = "rand SeededGene", - gene = sampleStringGene(rand), - seeded = sampleEnumGene(rand) as EnumGene, + gene = sampleStringGene(rand, rangeDelta), + seeded = sampleEnumGene(rand, rangeDelta) as EnumGene, employSeeded = rand.nextBoolean() ) } - fun sampleTupleGene(rand: Randomness): TupleGene { + fun sampleTupleGene(rand: Randomness, rangeDelta: Int? = null): TupleGene { val selection = geneClasses.filter { !it.isAbstract } return TupleGene( name = "rand TupleGene ${rand.nextInt()}", elements = listOf( - sample(rand.choose(selection), rand), - sample(rand.choose(selection), rand), - sample(rand.choose(selection), rand) + sample(rand.choose(selection), rand, rangeDelta), + sample(rand.choose(selection), rand, rangeDelta), + sample(rand.choose(selection), rand, rangeDelta) ), lastElementTreatedSpecially = rand.nextBoolean() ) } - fun samplePairGene(rand: Randomness): PairGene<*, *> { + fun samplePairGene(rand: Randomness, rangeDelta: Int? = null): PairGene<*, *> { val selection = geneClasses.filter { !it.isAbstract } return PairGene( name = "rand PairGene", - first = sample(rand.choose(selection), rand), - second = sample(rand.choose(selection), rand), + first = sample(rand.choose(selection), rand, rangeDelta), + second = sample(rand.choose(selection), rand, rangeDelta), isFirstMutable = rand.nextBoolean() ) } - fun samplePrintablePairGene(rand: Randomness): PairGene<*, *> { + fun samplePrintablePairGene(rand: Randomness, rangeDelta: Int? = null): PairGene<*, *> { val selection = geneClasses.filter { !it.isAbstract } return PairGene( name = "rand PairGene", - first = samplePrintableTemplate(selection, rand), - second = samplePrintableTemplate(selection, rand), + first = samplePrintableTemplate(selection, rand, rangeDelta), + second = samplePrintableTemplate(selection, rand, rangeDelta), isFirstMutable = rand.nextBoolean() ) } - fun samplePrintableFlexiblePairGene(rand: Randomness): PairGene<*, FlexibleGene> { + fun samplePrintableFlexiblePairGene(rand: Randomness, rangeDelta: Int? = null): PairGene<*, FlexibleGene> { val selection = geneClasses.filter { !it.isAbstract } return PairGene( name = "rand PairGene", - first = samplePrintableTemplate(selection, rand), - second = samplePrintableFlexibleGene(rand), + first = samplePrintableTemplate(selection, rand, rangeDelta), + second = samplePrintableFlexibleGene(rand, rangeDelta), isFirstMutable = rand.nextBoolean() ) } - fun samplePrintableFlexibleGene(rand: Randomness): FlexibleGene { + fun samplePrintableFlexibleGene(rand: Randomness, rangeDelta: Int? = null): FlexibleGene { val selection = geneClasses.filter { !it.isAbstract} - val valueTemplate = samplePrintableTemplate(selection, rand) + val valueTemplate = samplePrintableTemplate(selection, rand, rangeDelta) return FlexibleGene(valueTemplate.name, valueTemplate) } - - fun sampleOptionalGene(rand: Randomness): OptionalGene { + + fun sampleFlexibleCycleObjectGene(rand: Randomness, rangeDelta: Int? = null) : FlexibleCycleObjectGene{ + val gene = sampleCycleObjectGene(rand, rangeDelta) + return FlexibleCycleObjectGene(gene.name, gene) + } + + fun sampleOptionalGene(rand: Randomness, rangeDelta: Int? = null): OptionalGene { val selection = geneClasses.filter { !it.isAbstract } return OptionalGene( name = "rand OptionalGene", - gene = sample(rand.choose(selection), rand) + gene = sample(rand.choose(selection), rand, rangeDelta) ) } - fun sampleChoiceGene(rand: Randomness): ChoiceGene<*> { + fun sampleChoiceGene(rand: Randomness, rangeDelta: Int? = null): ChoiceGene<*> { val selection = geneClasses.filter { !it.isAbstract } return ChoiceGene( name = "rand ChoiceGene", geneChoices = listOf( - sample(rand.choose(selection), rand), - sample(rand.choose(selection), rand) + sample(rand.choose(selection), rand, rangeDelta), + sample(rand.choose(selection), rand, rangeDelta) ) ) } - fun sampleObjectGene(rand: Randomness): ObjectGene { + fun sampleObjectGene(rand: Randomness, rangeDelta: Int? = null): ObjectGene { val selection = geneClasses.filter { !it.isAbstract } return ObjectGene( name = "rand ObjectGene ${rand.nextInt()}", fields = listOf( - sample(rand.choose(selection), rand), - sample(rand.choose(selection), rand), - sample(rand.choose(selection), rand) + sample(rand.choose(selection), rand, rangeDelta), + sample(rand.choose(selection), rand, rangeDelta), + sample(rand.choose(selection), rand, rangeDelta) ) ) } - fun sampleNumericStringGene(rand: Randomness): NumericStringGene { + fun sampleNumericStringGene(rand: Randomness, rangeDelta: Int? = null): NumericStringGene { return NumericStringGene( name = "rand NumericStringGene", minLength = rand.nextInt(2), - number = sample(BigDecimalGene::class, rand) + number = sample(BigDecimalGene::class, rand, rangeDelta) ) } - fun sampleFixedMapGene(rand: Randomness): FixedMapGene<*, *> { + fun sampleFixedMapGene(rand: Randomness, rangeDelta: Int? = null): FixedMapGene<*, *> { val min = rand.nextInt(0, 2) + val minSize = rand.choose(listOf(null, min)) + val maxSize = rand.choose(listOf(null, min + (rangeDelta?:0) + rand.nextInt(1, 3))) return FixedMapGene( name = "rand MapGene", - minSize = rand.choose(listOf(null, min)), - maxSize = rand.choose(listOf(null, min + rand.nextInt(1, 3))), - template = samplePrintablePairGene(rand) + minSize = minSize, + maxSize = maxSize, + template = samplePrintablePairGene(rand, if (minSize != null) max(minSize, rangeDelta?:0) else rangeDelta) ) } - fun sampleFlexibleMapGene(rand: Randomness): FlexibleMapGene<*> { + fun sampleFlexibleMapGene(rand: Randomness, rangeDelta: Int? = null): FlexibleMapGene<*> { val min = rand.nextInt(0, 2) + val minSize = rand.choose(listOf(null, min)) + val maxSize = rand.choose(listOf(null, min + (rangeDelta?:0) + rand.nextInt(1, 3))) return FlexibleMapGene( name = "rand MapGene", - minSize = rand.choose(listOf(null, min)), - maxSize = rand.choose(listOf(null, min + rand.nextInt(1, 3))), - template = samplePrintableFlexiblePairGene(rand) + minSize = minSize, + maxSize = maxSize, + template = samplePrintableFlexiblePairGene(rand, if (minSize != null) max(minSize, rangeDelta?:0) else rangeDelta) ) } - fun sampleLimitObjectGene(rand: Randomness): LimitObjectGene { + fun sampleLimitObjectGene(rand: Randomness, rangeDelta: Int? = null): LimitObjectGene { return LimitObjectGene(name = "rand LimitObjectGene") } - fun sampleImmutableDataHolderGene(rand: Randomness): ImmutableDataHolderGene { + fun sampleImmutableDataHolderGene(rand: Randomness, rangeDelta: Int? = null): ImmutableDataHolderGene { return ImmutableDataHolderGene( name = "rand ImmutableDataHolderGene", value = rand.nextWordString(), @@ -607,30 +621,30 @@ object GeneSamplerForTests { ) } - fun sampleEnumGene(rand: Randomness): EnumGene<*> { + fun sampleEnumGene(rand: Randomness, rangeDelta: Int? = null): EnumGene<*> { return EnumGene("rand EnumGene ${rand.nextInt()}", listOf("A", "B", "C")) } - fun sampleDisruptiveGene(rand: Randomness): CustomMutationRateGene<*> { + fun sampleDisruptiveGene(rand: Randomness, rangeDelta: Int? = null): CustomMutationRateGene<*> { val selection = geneClasses .filter { !it.isAbstract } .filter { it != CustomMutationRateGene::class } - val chosen = sample(rand.choose(selection), rand) + val chosen = sample(rand.choose(selection), rand, rangeDelta) return CustomMutationRateGene("rand DisruptiveGene", chosen, 0.5) } - fun sampleCycleObjectGene(rand: Randomness): CycleObjectGene { + fun sampleCycleObjectGene(rand: Randomness, rangeDelta: Int? = null): CycleObjectGene { return CycleObjectGene("rand CycleObjectGene ${rand.nextInt()}") } - fun sampleBooleanGene(rand: Randomness): BooleanGene { + fun sampleBooleanGene(rand: Randomness, rangeDelta: Int? = null): BooleanGene { return BooleanGene(name = "rand boolean ${rand.nextInt()}") } - fun sampleDoubleGene(rand: Randomness): DoubleGene { + fun sampleDoubleGene(rand: Randomness, rangeDelta: Int? = null): DoubleGene { val scale: Int? = rand.choose(listOf(null, rand.nextInt(0, 2))) // if scale is 0, to distinguish min and max @@ -654,7 +668,7 @@ object GeneSamplerForTests { return DoubleGene( name = "rand DoubleGene ${rand.nextInt()}", min = rand.choose(listOf(null, min)), - max = rand.choose(listOf(null, min + delta + rand.nextDouble())), + max = rand.choose(listOf(null, min + max((rangeDelta?:0).toDouble(), delta)+ rand.nextDouble())), minInclusive = minInclusive, maxInclusive = maxInclusive, precision = rand.choose(listOf(null, precision)), @@ -663,10 +677,10 @@ object GeneSamplerForTests { } - fun sampleIntegerGene(rand: Randomness): IntegerGene { + fun sampleIntegerGene(rand: Randomness, rangeDelta: Int? = null): IntegerGene { val min = rand.nextInt() / 2 - val least = getMinPrecision(min) + val least = max(getMinPrecision(min), rangeDelta?:0) val precision = max(min(least + rand.nextInt(0, 2), 8), least) val minInclusive = rand.nextBoolean() @@ -685,10 +699,10 @@ object GeneSamplerForTests { ) } - fun sampleLongGene(rand: Randomness): LongGene { + fun sampleLongGene(rand: Randomness, rangeDelta: Int? = null): LongGene { val min = rand.nextLong() / 2 - val least = getMinPrecision(min) + val least = max(getMinPrecision(min), rangeDelta?:0) val precision = max(min(least + rand.nextInt(0, 2), 10), least) @@ -706,7 +720,7 @@ object GeneSamplerForTests { ) } - fun sampleFloatGene(rand: Randomness): FloatGene { + fun sampleFloatGene(rand: Randomness, rangeDelta: Int? = null): FloatGene { val scale: Int? = rand.choose(listOf(null, rand.nextInt(0, 2))) val min = rand.nextFloat().run { @@ -717,7 +731,7 @@ object GeneSamplerForTests { this } - val least = getMinPrecision(min) + val least = max(getMinPrecision(min), rangeDelta?:0) val precision = max(min(least + rand.nextInt(0, 2), 12), least) + (scale ?: 0) @@ -738,7 +752,7 @@ object GeneSamplerForTests { ) } - fun sampleBigDecimalGene(rand: Randomness): BigDecimalGene { + fun sampleBigDecimalGene(rand: Randomness, rangeDelta: Int? = null): BigDecimalGene { val scale: Int? = rand.choose(listOf(null, rand.nextInt(0, 2))) @@ -759,7 +773,7 @@ object GeneSamplerForTests { maxBigDecimal = minBigDecimal + BigDecimal.valueOf(max(minDelta, rand.nextLong(0, addition) / 2)) } - val least = if (minBigDecimal != null) getMinPrecision(minBigDecimal) else rand.nextInt(1, 5) + val least = max((if (minBigDecimal != null) getMinPrecision(minBigDecimal) else rand.nextInt(1, 5)), rangeDelta?:0) val precision = max(min(least + rand.nextInt(0, 2), 12), least) + (scale ?: 0) @@ -775,7 +789,7 @@ object GeneSamplerForTests { ) } - fun sampleBigIntegerGene(rand: Randomness): BigIntegerGene { + fun sampleBigIntegerGene(rand: Randomness, rangeDelta: Int? = null): BigIntegerGene { val minBigInteger: BigInteger? val maxBigInteger: BigInteger? @@ -791,7 +805,7 @@ object GeneSamplerForTests { maxBigInteger = minBigInteger.plus(BigInteger.valueOf(max(minDelta, rand.nextLong(0, Long.MAX_VALUE) / 2))) } - val least = if (minBigInteger != null) getMinPrecision(minBigInteger) else rand.nextInt(1, 5) + val least = max(if (minBigInteger != null) getMinPrecision(minBigInteger) else rand.nextInt(1, 5), rangeDelta?:0) val precision = max(min(least + rand.nextInt(0, 2), 12), least) return BigIntegerGene( @@ -804,19 +818,20 @@ object GeneSamplerForTests { ) } - private fun samplePrintableTemplate(selection: List>,rand: Randomness) : Gene{ - val filter = selection.filter { it != FlexibleGene::class } - var chosen = sample(rand.choose(filter), rand) + private fun samplePrintableTemplate(selection: List>, rand: Randomness, rangeDelta: Int? = null) : Gene{ + val filter = selection.filter { !isFlexible(it) } + var chosen = sample(rand.choose(filter), rand, rangeDelta) while(!chosen.isPrintable()){ - chosen = sample(rand.choose(filter), rand) + chosen = sample(rand.choose(filter), rand, rangeDelta) } return chosen } + private fun isFlexible(kclass : KClass) : Boolean = kclass == FlexibleGene::class || kclass == FlexibleCycleObjectGene::class || kclass == FlexibleMapGene::class - private fun sampleTaintedArrayGene(rand: Randomness): TaintedArrayGene { + private fun sampleTaintedArrayGene(rand: Randomness, rangeDelta: Int? = null): TaintedArrayGene { - val array = if(rand.nextBoolean()) sampleArrayGene(rand) else null + val array = if(rand.nextBoolean()) sampleArrayGene(rand, rangeDelta) else null val isActive = if(array == null) false else rand.nextBoolean() return TaintedArrayGene( @@ -827,22 +842,22 @@ object GeneSamplerForTests { ) } - fun sampleArrayGene(rand: Randomness): ArrayGene<*> { + fun sampleArrayGene(rand: Randomness, rangeDelta: Int? = null): ArrayGene<*> { val selection = selectionForArrayTemplate() - val chosen = samplePrintableTemplate(selection, rand) + val chosen = samplePrintableTemplate(selection, rand, rangeDelta) return ArrayGene("rand array ${rand.nextInt()}", chosen) } - fun sampleBase64StringGene(rand: Randomness): Base64StringGene { + fun sampleBase64StringGene(rand: Randomness, rangeDelta: Int? = null): Base64StringGene { return Base64StringGene("rand Base64StringGene ${rand.nextInt()}") } - fun sampleStringGene(rand: Randomness): StringGene { + fun sampleStringGene(rand: Randomness, rangeDelta: Int? = null): StringGene { val min = rand.nextInt(0, 3) - val max = min + rand.nextInt(20) + val max = min + rand.nextInt(rangeDelta?:0,20) return StringGene("rand string ${rand.nextInt()}", minLength = min, maxLength = max) } diff --git a/core/src/test/kotlin/org/evomaster/core/search/gene/GeneTest.kt b/core/src/test/kotlin/org/evomaster/core/search/gene/GeneTest.kt index 31f6966f36..d218ec4010 100644 --- a/core/src/test/kotlin/org/evomaster/core/search/gene/GeneTest.kt +++ b/core/src/test/kotlin/org/evomaster/core/search/gene/GeneTest.kt @@ -24,7 +24,7 @@ class GeneTest { This number should not change, unless you explicitly add/remove any gene. if so, update this number accordingly */ - assertEquals(81, genes.size) + assertEquals(82, genes.size) } @Test diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationService.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationService.java index 474a9ac5aa..9431e8d428 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationService.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationService.java @@ -7,7 +7,7 @@ package com.foo.rpc.examples.spring.customization; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-01-07") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-11-08") public class CustomizationService { public interface Iface { @@ -16,6 +16,8 @@ public interface Iface { public int handleCombinedSeed(RequestWithCombinedSeedDto dto) throws org.apache.thrift.TException; + public CycleADto handleCycleDto(CycleADto dto) throws org.apache.thrift.TException; + } public interface AsyncIface { @@ -24,6 +26,8 @@ public interface AsyncIface { public void handleCombinedSeed(RequestWithCombinedSeedDto dto, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void handleCycleDto(CycleADto dto, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + } public static class Client extends org.apache.thrift.TServiceClient implements Iface { @@ -92,6 +96,29 @@ public int recv_handleCombinedSeed() throws org.apache.thrift.TException throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "handleCombinedSeed failed: unknown result"); } + public CycleADto handleCycleDto(CycleADto dto) throws org.apache.thrift.TException + { + send_handleCycleDto(dto); + return recv_handleCycleDto(); + } + + public void send_handleCycleDto(CycleADto dto) throws org.apache.thrift.TException + { + handleCycleDto_args args = new handleCycleDto_args(); + args.setDto(dto); + sendBase("handleCycleDto", args); + } + + public CycleADto recv_handleCycleDto() throws org.apache.thrift.TException + { + handleCycleDto_result result = new handleCycleDto_result(); + receiveBase(result, "handleCycleDto"); + if (result.isSetSuccess()) { + return result.success; + } + throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "handleCycleDto failed: unknown result"); + } + } public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface { public static class Factory implements org.apache.thrift.async.TAsyncClientFactory { @@ -174,6 +201,38 @@ public java.lang.Integer getResult() throws org.apache.thrift.TException { } } + public void handleCycleDto(CycleADto dto, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + handleCycleDto_call method_call = new handleCycleDto_call(dto, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class handleCycleDto_call extends org.apache.thrift.async.TAsyncMethodCall { + private CycleADto dto; + public handleCycleDto_call(CycleADto dto, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.dto = dto; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("handleCycleDto", org.apache.thrift.protocol.TMessageType.CALL, 0)); + handleCycleDto_args args = new handleCycleDto_args(); + args.setDto(dto); + args.write(prot); + prot.writeMessageEnd(); + } + + public CycleADto getResult() throws org.apache.thrift.TException { + if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { + throw new java.lang.IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + return (new Client(prot)).recv_handleCycleDto(); + } + } + } public static class Processor extends org.apache.thrift.TBaseProcessor implements org.apache.thrift.TProcessor { @@ -189,6 +248,7 @@ protected Processor(I iface, java.util.Map java.util.Map> getProcessMap(java.util.Map> processMap) { processMap.put("handleDependent", new handleDependent()); processMap.put("handleCombinedSeed", new handleCombinedSeed()); + processMap.put("handleCycleDto", new handleCycleDto()); return processMap; } @@ -244,6 +304,31 @@ public handleCombinedSeed_result getResult(I iface, handleCombinedSeed_args args } } + public static class handleCycleDto extends org.apache.thrift.ProcessFunction { + public handleCycleDto() { + super("handleCycleDto"); + } + + public handleCycleDto_args getEmptyArgsInstance() { + return new handleCycleDto_args(); + } + + protected boolean isOneway() { + return false; + } + + @Override + protected boolean rethrowUnhandledExceptions() { + return false; + } + + public handleCycleDto_result getResult(I iface, handleCycleDto_args args) throws org.apache.thrift.TException { + handleCycleDto_result result = new handleCycleDto_result(); + result.success = iface.handleCycleDto(args.dto); + return result; + } + } + } public static class AsyncProcessor extends org.apache.thrift.TBaseAsyncProcessor { @@ -259,6 +344,7 @@ protected AsyncProcessor(I iface, java.util.Map java.util.Map> getProcessMap(java.util.Map> processMap) { processMap.put("handleDependent", new handleDependent()); processMap.put("handleCombinedSeed", new handleCombinedSeed()); + processMap.put("handleCycleDto", new handleCycleDto()); return processMap; } @@ -386,6 +472,67 @@ public void start(I iface, handleCombinedSeed_args args, org.apache.thrift.async } } + public static class handleCycleDto extends org.apache.thrift.AsyncProcessFunction { + public handleCycleDto() { + super("handleCycleDto"); + } + + public handleCycleDto_args getEmptyArgsInstance() { + return new handleCycleDto_args(); + } + + public org.apache.thrift.async.AsyncMethodCallback getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) { + final org.apache.thrift.AsyncProcessFunction fcall = this; + return new org.apache.thrift.async.AsyncMethodCallback() { + public void onComplete(CycleADto o) { + handleCycleDto_result result = new handleCycleDto_result(); + result.success = o; + try { + fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); + } catch (org.apache.thrift.transport.TTransportException e) { + _LOGGER.error("TTransportException writing to internal frame buffer", e); + fb.close(); + } catch (java.lang.Exception e) { + _LOGGER.error("Exception writing to internal frame buffer", e); + onError(e); + } + } + public void onError(java.lang.Exception e) { + byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; + org.apache.thrift.TSerializable msg; + handleCycleDto_result result = new handleCycleDto_result(); + if (e instanceof org.apache.thrift.transport.TTransportException) { + _LOGGER.error("TTransportException inside handler", e); + fb.close(); + return; + } else if (e instanceof org.apache.thrift.TApplicationException) { + _LOGGER.error("TApplicationException inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = (org.apache.thrift.TApplicationException)e; + } else { + _LOGGER.error("Exception inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); + } + try { + fcall.sendResponse(fb,msg,msgType,seqid); + } catch (java.lang.Exception ex) { + _LOGGER.error("Exception writing to internal frame buffer", ex); + fb.close(); + } + } + }; + } + + protected boolean isOneway() { + return false; + } + + public void start(I iface, handleCycleDto_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + iface.handleCycleDto(args.dto,resultHandler); + } + } + } public static class handleDependent_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { @@ -1852,4 +1999,744 @@ private static S scheme(org.apache. } } + public static class handleCycleDto_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("handleCycleDto_args"); + + private static final org.apache.thrift.protocol.TField DTO_FIELD_DESC = new org.apache.thrift.protocol.TField("dto", org.apache.thrift.protocol.TType.STRUCT, (short)1); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new handleCycleDto_argsStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new handleCycleDto_argsTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable CycleADto dto; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + DTO((short)1, "dto"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // DTO + return DTO; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.DTO, new org.apache.thrift.meta_data.FieldMetaData("dto", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, CycleADto.class))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(handleCycleDto_args.class, metaDataMap); + } + + public handleCycleDto_args() { + } + + public handleCycleDto_args( + CycleADto dto) + { + this(); + this.dto = dto; + } + + /** + * Performs a deep copy on other. + */ + public handleCycleDto_args(handleCycleDto_args other) { + if (other.isSetDto()) { + this.dto = new CycleADto(other.dto); + } + } + + public handleCycleDto_args deepCopy() { + return new handleCycleDto_args(this); + } + + @Override + public void clear() { + this.dto = null; + } + + @org.apache.thrift.annotation.Nullable + public CycleADto getDto() { + return this.dto; + } + + public handleCycleDto_args setDto(@org.apache.thrift.annotation.Nullable CycleADto dto) { + this.dto = dto; + return this; + } + + public void unsetDto() { + this.dto = null; + } + + /** Returns true if field dto is set (has been assigned a value) and false otherwise */ + public boolean isSetDto() { + return this.dto != null; + } + + public void setDtoIsSet(boolean value) { + if (!value) { + this.dto = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case DTO: + if (value == null) { + unsetDto(); + } else { + setDto((CycleADto)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case DTO: + return getDto(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case DTO: + return isSetDto(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that instanceof handleCycleDto_args) + return this.equals((handleCycleDto_args)that); + return false; + } + + public boolean equals(handleCycleDto_args that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_dto = true && this.isSetDto(); + boolean that_present_dto = true && that.isSetDto(); + if (this_present_dto || that_present_dto) { + if (!(this_present_dto && that_present_dto)) + return false; + if (!this.dto.equals(that.dto)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetDto()) ? 131071 : 524287); + if (isSetDto()) + hashCode = hashCode * 8191 + dto.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(handleCycleDto_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.compare(isSetDto(), other.isSetDto()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetDto()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.dto, other.dto); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("handleCycleDto_args("); + boolean first = true; + + sb.append("dto:"); + if (this.dto == null) { + sb.append("null"); + } else { + sb.append(this.dto); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + if (dto != null) { + dto.validate(); + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class handleCycleDto_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public handleCycleDto_argsStandardScheme getScheme() { + return new handleCycleDto_argsStandardScheme(); + } + } + + private static class handleCycleDto_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, handleCycleDto_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // DTO + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.dto = new CycleADto(); + struct.dto.read(iprot); + struct.setDtoIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, handleCycleDto_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.dto != null) { + oprot.writeFieldBegin(DTO_FIELD_DESC); + struct.dto.write(oprot); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class handleCycleDto_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public handleCycleDto_argsTupleScheme getScheme() { + return new handleCycleDto_argsTupleScheme(); + } + } + + private static class handleCycleDto_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, handleCycleDto_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetDto()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetDto()) { + struct.dto.write(oprot); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, handleCycleDto_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.dto = new CycleADto(); + struct.dto.read(iprot); + struct.setDtoIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + + public static class handleCycleDto_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("handleCycleDto_result"); + + private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField("success", org.apache.thrift.protocol.TType.STRUCT, (short)0); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new handleCycleDto_resultStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new handleCycleDto_resultTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable CycleADto success; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + SUCCESS((short)0, "success"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 0: // SUCCESS + return SUCCESS; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.SUCCESS, new org.apache.thrift.meta_data.FieldMetaData("success", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, CycleADto.class))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(handleCycleDto_result.class, metaDataMap); + } + + public handleCycleDto_result() { + } + + public handleCycleDto_result( + CycleADto success) + { + this(); + this.success = success; + } + + /** + * Performs a deep copy on other. + */ + public handleCycleDto_result(handleCycleDto_result other) { + if (other.isSetSuccess()) { + this.success = new CycleADto(other.success); + } + } + + public handleCycleDto_result deepCopy() { + return new handleCycleDto_result(this); + } + + @Override + public void clear() { + this.success = null; + } + + @org.apache.thrift.annotation.Nullable + public CycleADto getSuccess() { + return this.success; + } + + public handleCycleDto_result setSuccess(@org.apache.thrift.annotation.Nullable CycleADto success) { + this.success = success; + return this; + } + + public void unsetSuccess() { + this.success = null; + } + + /** Returns true if field success is set (has been assigned a value) and false otherwise */ + public boolean isSetSuccess() { + return this.success != null; + } + + public void setSuccessIsSet(boolean value) { + if (!value) { + this.success = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case SUCCESS: + if (value == null) { + unsetSuccess(); + } else { + setSuccess((CycleADto)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case SUCCESS: + return getSuccess(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case SUCCESS: + return isSetSuccess(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that instanceof handleCycleDto_result) + return this.equals((handleCycleDto_result)that); + return false; + } + + public boolean equals(handleCycleDto_result that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_success = true && this.isSetSuccess(); + boolean that_present_success = true && that.isSetSuccess(); + if (this_present_success || that_present_success) { + if (!(this_present_success && that_present_success)) + return false; + if (!this.success.equals(that.success)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetSuccess()) ? 131071 : 524287); + if (isSetSuccess()) + hashCode = hashCode * 8191 + success.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(handleCycleDto_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.compare(isSetSuccess(), other.isSetSuccess()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetSuccess()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("handleCycleDto_result("); + boolean first = true; + + sb.append("success:"); + if (this.success == null) { + sb.append("null"); + } else { + sb.append(this.success); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + if (success != null) { + success.validate(); + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class handleCycleDto_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public handleCycleDto_resultStandardScheme getScheme() { + return new handleCycleDto_resultStandardScheme(); + } + } + + private static class handleCycleDto_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, handleCycleDto_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 0: // SUCCESS + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.success = new CycleADto(); + struct.success.read(iprot); + struct.setSuccessIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, handleCycleDto_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.success != null) { + oprot.writeFieldBegin(SUCCESS_FIELD_DESC); + struct.success.write(oprot); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class handleCycleDto_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public handleCycleDto_resultTupleScheme getScheme() { + return new handleCycleDto_resultTupleScheme(); + } + } + + private static class handleCycleDto_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, handleCycleDto_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetSuccess()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetSuccess()) { + struct.success.write(oprot); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, handleCycleDto_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.success = new CycleADto(); + struct.success.read(iprot); + struct.setSuccessIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + } diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationServiceImp.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationServiceImp.java index d6b2f895b2..e47469ee39 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationServiceImp.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CustomizationServiceImp.java @@ -37,4 +37,12 @@ public int handleCombinedSeed(RequestWithCombinedSeedDto dto) throws TException return 101; return 0; } + + @Override + public CycleADto handleCycleDto(CycleADto dto) throws TException { + if (dto == null) return null; + if (dto.obj != null && dto.obj.obj != null && dto.obj.obj.obj != null && dto.obj.obj.obj.obj != null) + return dto; + return null; + } } diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleADto.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleADto.java new file mode 100644 index 0000000000..5651a66395 --- /dev/null +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleADto.java @@ -0,0 +1,478 @@ +/** + * Autogenerated by Thrift Compiler (0.15.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.foo.rpc.examples.spring.customization; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-11-08") +public class CycleADto implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("CycleADto"); + + private static final org.apache.thrift.protocol.TField A_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("aID", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField OBJ_FIELD_DESC = new org.apache.thrift.protocol.TField("obj", org.apache.thrift.protocol.TType.STRUCT, (short)2); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new CycleADtoStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new CycleADtoTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable java.lang.String aID; // required + public @org.apache.thrift.annotation.Nullable CycleBDto obj; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + A_ID((short)1, "aID"), + OBJ((short)2, "obj"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // A_ID + return A_ID; + case 2: // OBJ + return OBJ; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.A_ID, new org.apache.thrift.meta_data.FieldMetaData("aID", org.apache.thrift.TFieldRequirementType.REQUIRED, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.OBJ, new org.apache.thrift.meta_data.FieldMetaData("obj", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRUCT , "CycleBDto"))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(CycleADto.class, metaDataMap); + } + + public CycleADto() { + } + + public CycleADto( + java.lang.String aID, + CycleBDto obj) + { + this(); + this.aID = aID; + this.obj = obj; + } + + /** + * Performs a deep copy on other. + */ + public CycleADto(CycleADto other) { + if (other.isSetAID()) { + this.aID = other.aID; + } + if (other.isSetObj()) { + this.obj = new CycleBDto(other.obj); + } + } + + public CycleADto deepCopy() { + return new CycleADto(this); + } + + @Override + public void clear() { + this.aID = null; + this.obj = null; + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getAID() { + return this.aID; + } + + public CycleADto setAID(@org.apache.thrift.annotation.Nullable java.lang.String aID) { + this.aID = aID; + return this; + } + + public void unsetAID() { + this.aID = null; + } + + /** Returns true if field aID is set (has been assigned a value) and false otherwise */ + public boolean isSetAID() { + return this.aID != null; + } + + public void setAIDIsSet(boolean value) { + if (!value) { + this.aID = null; + } + } + + @org.apache.thrift.annotation.Nullable + public CycleBDto getObj() { + return this.obj; + } + + public CycleADto setObj(@org.apache.thrift.annotation.Nullable CycleBDto obj) { + this.obj = obj; + return this; + } + + public void unsetObj() { + this.obj = null; + } + + /** Returns true if field obj is set (has been assigned a value) and false otherwise */ + public boolean isSetObj() { + return this.obj != null; + } + + public void setObjIsSet(boolean value) { + if (!value) { + this.obj = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case A_ID: + if (value == null) { + unsetAID(); + } else { + setAID((java.lang.String)value); + } + break; + + case OBJ: + if (value == null) { + unsetObj(); + } else { + setObj((CycleBDto)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case A_ID: + return getAID(); + + case OBJ: + return getObj(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case A_ID: + return isSetAID(); + case OBJ: + return isSetObj(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that instanceof CycleADto) + return this.equals((CycleADto)that); + return false; + } + + public boolean equals(CycleADto that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_aID = true && this.isSetAID(); + boolean that_present_aID = true && that.isSetAID(); + if (this_present_aID || that_present_aID) { + if (!(this_present_aID && that_present_aID)) + return false; + if (!this.aID.equals(that.aID)) + return false; + } + + boolean this_present_obj = true && this.isSetObj(); + boolean that_present_obj = true && that.isSetObj(); + if (this_present_obj || that_present_obj) { + if (!(this_present_obj && that_present_obj)) + return false; + if (!this.obj.equals(that.obj)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetAID()) ? 131071 : 524287); + if (isSetAID()) + hashCode = hashCode * 8191 + aID.hashCode(); + + hashCode = hashCode * 8191 + ((isSetObj()) ? 131071 : 524287); + if (isSetObj()) + hashCode = hashCode * 8191 + obj.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(CycleADto other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.compare(isSetAID(), other.isSetAID()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetAID()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.aID, other.aID); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.compare(isSetObj(), other.isSetObj()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetObj()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.obj, other.obj); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("CycleADto("); + boolean first = true; + + sb.append("aID:"); + if (this.aID == null) { + sb.append("null"); + } else { + sb.append(this.aID); + } + first = false; + if (!first) sb.append(", "); + sb.append("obj:"); + if (this.obj == null) { + sb.append("null"); + } else { + sb.append(this.obj); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + if (aID == null) { + throw new org.apache.thrift.protocol.TProtocolException("Required field 'aID' was not present! Struct: " + toString()); + } + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class CycleADtoStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public CycleADtoStandardScheme getScheme() { + return new CycleADtoStandardScheme(); + } + } + + private static class CycleADtoStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, CycleADto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // A_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.aID = iprot.readString(); + struct.setAIDIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // OBJ + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.obj = new CycleBDto(); + struct.obj.read(iprot); + struct.setObjIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, CycleADto struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.aID != null) { + oprot.writeFieldBegin(A_ID_FIELD_DESC); + oprot.writeString(struct.aID); + oprot.writeFieldEnd(); + } + if (struct.obj != null) { + oprot.writeFieldBegin(OBJ_FIELD_DESC); + struct.obj.write(oprot); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class CycleADtoTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public CycleADtoTupleScheme getScheme() { + return new CycleADtoTupleScheme(); + } + } + + private static class CycleADtoTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, CycleADto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + oprot.writeString(struct.aID); + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetObj()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetObj()) { + struct.obj.write(oprot); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, CycleADto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + struct.aID = iprot.readString(); + struct.setAIDIsSet(true); + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.obj = new CycleBDto(); + struct.obj.read(iprot); + struct.setObjIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleBDto.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleBDto.java new file mode 100644 index 0000000000..8618789d61 --- /dev/null +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/CycleBDto.java @@ -0,0 +1,481 @@ +/** + * Autogenerated by Thrift Compiler (0.15.0) + * + * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING + * @generated + */ +package com.foo.rpc.examples.spring.customization; + +@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-11-08") +public class CycleBDto implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("CycleBDto"); + + private static final org.apache.thrift.protocol.TField B_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("bID", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField OBJ_FIELD_DESC = new org.apache.thrift.protocol.TField("obj", org.apache.thrift.protocol.TType.STRUCT, (short)2); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new CycleBDtoStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new CycleBDtoTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable java.lang.String bID; // required + public @org.apache.thrift.annotation.Nullable CycleADto obj; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + B_ID((short)1, "bID"), + OBJ((short)2, "obj"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // B_ID + return B_ID; + case 2: // OBJ + return OBJ; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.B_ID, new org.apache.thrift.meta_data.FieldMetaData("bID", org.apache.thrift.TFieldRequirementType.REQUIRED, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.OBJ, new org.apache.thrift.meta_data.FieldMetaData("obj", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, CycleADto.class))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(CycleBDto.class, metaDataMap); + } + + public CycleBDto() { + } + + public CycleBDto( + java.lang.String bID, + CycleADto obj) + { + this(); + this.bID = bID; + this.obj = obj; + } + + /** + * Performs a deep copy on other. + */ + public CycleBDto(CycleBDto other) { + if (other.isSetBID()) { + this.bID = other.bID; + } + if (other.isSetObj()) { + this.obj = new CycleADto(other.obj); + } + } + + public CycleBDto deepCopy() { + return new CycleBDto(this); + } + + @Override + public void clear() { + this.bID = null; + this.obj = null; + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getBID() { + return this.bID; + } + + public CycleBDto setBID(@org.apache.thrift.annotation.Nullable java.lang.String bID) { + this.bID = bID; + return this; + } + + public void unsetBID() { + this.bID = null; + } + + /** Returns true if field bID is set (has been assigned a value) and false otherwise */ + public boolean isSetBID() { + return this.bID != null; + } + + public void setBIDIsSet(boolean value) { + if (!value) { + this.bID = null; + } + } + + @org.apache.thrift.annotation.Nullable + public CycleADto getObj() { + return this.obj; + } + + public CycleBDto setObj(@org.apache.thrift.annotation.Nullable CycleADto obj) { + this.obj = obj; + return this; + } + + public void unsetObj() { + this.obj = null; + } + + /** Returns true if field obj is set (has been assigned a value) and false otherwise */ + public boolean isSetObj() { + return this.obj != null; + } + + public void setObjIsSet(boolean value) { + if (!value) { + this.obj = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case B_ID: + if (value == null) { + unsetBID(); + } else { + setBID((java.lang.String)value); + } + break; + + case OBJ: + if (value == null) { + unsetObj(); + } else { + setObj((CycleADto)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case B_ID: + return getBID(); + + case OBJ: + return getObj(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case B_ID: + return isSetBID(); + case OBJ: + return isSetObj(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that instanceof CycleBDto) + return this.equals((CycleBDto)that); + return false; + } + + public boolean equals(CycleBDto that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_bID = true && this.isSetBID(); + boolean that_present_bID = true && that.isSetBID(); + if (this_present_bID || that_present_bID) { + if (!(this_present_bID && that_present_bID)) + return false; + if (!this.bID.equals(that.bID)) + return false; + } + + boolean this_present_obj = true && this.isSetObj(); + boolean that_present_obj = true && that.isSetObj(); + if (this_present_obj || that_present_obj) { + if (!(this_present_obj && that_present_obj)) + return false; + if (!this.obj.equals(that.obj)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetBID()) ? 131071 : 524287); + if (isSetBID()) + hashCode = hashCode * 8191 + bID.hashCode(); + + hashCode = hashCode * 8191 + ((isSetObj()) ? 131071 : 524287); + if (isSetObj()) + hashCode = hashCode * 8191 + obj.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(CycleBDto other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.compare(isSetBID(), other.isSetBID()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetBID()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.bID, other.bID); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.compare(isSetObj(), other.isSetObj()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetObj()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.obj, other.obj); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("CycleBDto("); + boolean first = true; + + sb.append("bID:"); + if (this.bID == null) { + sb.append("null"); + } else { + sb.append(this.bID); + } + first = false; + if (!first) sb.append(", "); + sb.append("obj:"); + if (this.obj == null) { + sb.append("null"); + } else { + sb.append(this.obj); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + if (bID == null) { + throw new org.apache.thrift.protocol.TProtocolException("Required field 'bID' was not present! Struct: " + toString()); + } + // check for sub-struct validity + if (obj != null) { + obj.validate(); + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class CycleBDtoStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public CycleBDtoStandardScheme getScheme() { + return new CycleBDtoStandardScheme(); + } + } + + private static class CycleBDtoStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, CycleBDto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // B_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.bID = iprot.readString(); + struct.setBIDIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // OBJ + if (schemeField.type == org.apache.thrift.protocol.TType.STRUCT) { + struct.obj = new CycleADto(); + struct.obj.read(iprot); + struct.setObjIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, CycleBDto struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.bID != null) { + oprot.writeFieldBegin(B_ID_FIELD_DESC); + oprot.writeString(struct.bID); + oprot.writeFieldEnd(); + } + if (struct.obj != null) { + oprot.writeFieldBegin(OBJ_FIELD_DESC); + struct.obj.write(oprot); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class CycleBDtoTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public CycleBDtoTupleScheme getScheme() { + return new CycleBDtoTupleScheme(); + } + } + + private static class CycleBDtoTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, CycleBDto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + oprot.writeString(struct.bID); + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetObj()) { + optionals.set(0); + } + oprot.writeBitSet(optionals, 1); + if (struct.isSetObj()) { + struct.obj.write(oprot); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, CycleBDto struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + struct.bID = iprot.readString(); + struct.setBIDIsSet(true); + java.util.BitSet incoming = iprot.readBitSet(1); + if (incoming.get(0)) { + struct.obj = new CycleADto(); + struct.obj.read(iprot); + struct.setObjIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } +} + diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithCombinedSeedDto.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithCombinedSeedDto.java index 41cfb3677f..132c9a75e7 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithCombinedSeedDto.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithCombinedSeedDto.java @@ -7,7 +7,7 @@ package com.foo.rpc.examples.spring.customization; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-01-07") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-11-08") public class RequestWithCombinedSeedDto implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RequestWithCombinedSeedDto"); diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithSeedDto.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithSeedDto.java index 2cb865f538..268fb89254 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithSeedDto.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/java/com/foo/rpc/examples/spring/customization/RequestWithSeedDto.java @@ -7,7 +7,7 @@ package com.foo.rpc.examples.spring.customization; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-01-07") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.15.0)", date = "2022-11-08") public class RequestWithSeedDto implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RequestWithSeedDto"); diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/resources/schema/customization.thrift b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/resources/schema/customization.thrift index ce7871effe..ab712b40ce 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/resources/schema/customization.thrift +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/main/resources/schema/customization.thrift @@ -11,10 +11,22 @@ struct RequestWithSeedDto { 2: string info } +struct CycleADto{ + 1: required string aID, + 2: CycleBDto obj +} + +struct CycleBDto{ + 1: required string bID, + 2: CycleADto obj +} + service CustomizationService { i32 handleDependent(1:RequestWithSeedDto dto), i32 handleCombinedSeed(1:RequestWithCombinedSeedDto dto) + CycleADto handleCycleDto(1:CycleADto dto) + } \ No newline at end of file diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/com/foo/rpc/examples/spring/customization/CustomizationWithSeedController.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/com/foo/rpc/examples/spring/customization/CustomizationWithSeedController.java index 71704e8b07..7b13a3293f 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/com/foo/rpc/examples/spring/customization/CustomizationWithSeedController.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/com/foo/rpc/examples/spring/customization/CustomizationWithSeedController.java @@ -3,6 +3,8 @@ import org.evomaster.client.java.controller.api.dto.CustomizedRequestValueDto; import org.evomaster.client.java.controller.api.dto.KeyValuePairDto; import org.evomaster.client.java.controller.api.dto.KeyValuesDto; +import org.evomaster.client.java.controller.api.dto.problem.rpc.SeededRPCActionDto; +import org.evomaster.client.java.controller.api.dto.problem.rpc.SeededRPCTestDto; import java.util.Arrays; import java.util.List; @@ -44,4 +46,21 @@ public List getCustomizedValueInRequests() { }} ); } + + @Override + public List seedRPCTests() { + return Arrays.asList( + new SeededRPCTestDto(){{ + testName = "test_1"; + rpcFunctions = Arrays.asList( + new SeededRPCActionDto(){{ + interfaceName = CustomizationService.Iface.class.getName(); + functionName = "handleCycleDto"; + inputParams= Arrays.asList("{\"aID\":\"a\",\"obj\":{\"bID\":\"ab\",\"obj\":{\"aID\":\"aba\",\"obj\":{\"bID\":\"abab\",\"obj\":{\"aID\":\"ababa\",\"obj\":null}}}}}"); + inputParamTypes= Arrays.asList(CycleADto.class.getName()); + }} + ); + }} + ); + } } diff --git a/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/org/evomaster/e2etests/spring/rpc/examples/customization/CustomizationWithSeedEMTest.java b/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/org/evomaster/e2etests/spring/rpc/examples/customization/CustomizationWithSeedEMTest.java index af4d662cc1..8a99855b8b 100644 --- a/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/org/evomaster/e2etests/spring/rpc/examples/customization/CustomizationWithSeedEMTest.java +++ b/e2e-tests/spring-rpc/spring-rpc-thrift/src/test/java/org/evomaster/e2etests/spring/rpc/examples/customization/CustomizationWithSeedEMTest.java @@ -30,6 +30,8 @@ public void testRunEM() throws Throwable { "org.bar.CustomizationWithSeedEM", 300, (args) -> { + args.add("--seedTestCases"); + args.add("true"); Solution solution = initAndRun(args);