diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 88979a6d68..80a8639b5c 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -1439,7 +1439,7 @@ sealed class SpringConfiguration(val fullDisplayName: String) { } sealed interface SpringSettings { - object AbsentSpringSettings : SpringSettings { + companion object AbsentSpringSettings : SpringSettings { // NOTE that overriding equals is required just because without it // we will lose equality for objects after deserialization override fun equals(other: Any?): Boolean = other is AbsentSpringSettings diff --git a/utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java b/utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java index c11ce197f0..c8e0213371 100644 --- a/utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java +++ b/utbot-framework-test/src/test/java/org/utbot/examples/manual/UtBotJavaApiTest.java @@ -1,12 +1,9 @@ package org.utbot.examples.manual; import kotlin.Pair; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.utbot.common.PathUtil; +import org.utbot.api.java.AbstractUtBotJavaApiTest; import org.utbot.examples.assemble.DirectAccess; import org.utbot.examples.assemble.PrimitiveFields; import org.utbot.examples.assemble.ArrayOfComplexArrays; @@ -20,69 +17,42 @@ import org.utbot.external.api.TestMethodInfo; import org.utbot.external.api.UnitTestBotLight; import org.utbot.external.api.UtBotJavaApi; -import org.utbot.external.api.UtModelFactory; -import org.utbot.framework.codegen.domain.ForceStaticMocking; -import org.utbot.framework.codegen.domain.Junit4; -import org.utbot.framework.codegen.domain.MockitoStaticMocking; -import org.utbot.framework.codegen.domain.ProjectType; +import org.utbot.framework.codegen.domain.*; +import org.utbot.framework.context.simple.SimpleApplicationContext; import org.utbot.framework.plugin.api.*; -import org.utbot.framework.plugin.api.util.UtContext; import org.utbot.framework.plugin.services.JdkInfoDefaultProvider; import org.utbot.framework.util.Snippet; import org.utbot.framework.util.SootUtils; -import java.io.File; import java.lang.reflect.Method; -import java.net.URISyntaxException; -import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import static java.util.Collections.*; import static org.utbot.external.api.UtModelFactoryKt.classIdForType; import static org.utbot.framework.plugin.api.MockFramework.MOCKITO; -import static org.utbot.framework.plugin.api.util.IdUtilKt.getIntArrayClassId; +import static org.utbot.framework.plugin.api.util.IdUtilKt.*; import static org.utbot.framework.util.TestUtilsKt.compileClassAndGetClassPath; import static org.utbot.framework.util.TestUtilsKt.compileClassFile; -class PredefinedGeneratorParameters { +/** + * Tests for UnitTestBot Java API (Examples at the same time) + */ +public class UtBotJavaApiTest extends AbstractUtBotJavaApiTest { - static String destinationClassName = "GeneratedTest"; - - static Method getMethodByName(Class clazz, String name, Class... parameters) { - try { - return clazz.getDeclaredMethod(name, parameters); - } catch (NoSuchMethodException ignored) { - Assertions.fail(); - } - throw new RuntimeException(); - } -} - -public class UtBotJavaApiTest { - private AutoCloseable context; - private UtModelFactory modelFactory; - - @BeforeEach - public void setUp() { - context = UtContext.Companion.setUtContext(new UtContext(PrimitiveFields.class.getClassLoader())); - modelFactory = new UtModelFactory(); - } - - @AfterEach - public void tearDown() { - try { - context.close(); - modelFactory = null; - } catch (Exception e) { - Assertions.fail(); - } - } + /** Uses {@link MultiMethodExample} as a class under test. Demonstrates how to gather information for multiple + * methods analysis and pass it to {@link UtBotJavaApi#generateTestSetsForMethods} in order to produce set + * of information needed for the test generation. After that shows how to use {@link UtBotJavaApi#generateTestCode} + * in order to generate tests code. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testMultiMethodClass() { @@ -95,58 +65,31 @@ public void testMultiMethodClass() { classIdForType(MultiMethodExample.class) ); - EnvironmentModels initialState = new EnvironmentModels( - classUnderTestModel, - Collections.emptyList(), - Collections.emptyMap() - ); - - EnvironmentModels thirdMethodState = new EnvironmentModels( - classUnderTestModel, - Collections.singletonList(new UtPrimitiveModel("some")), - Collections.emptyMap() - ); - + Method firstMethodUnderTest = getMethodByName(MultiMethodExample.class, "firstMethod"); + Method secondMethodUnderTest = getMethodByName(MultiMethodExample.class, "secondMethod"); + Method thirdMethodUnderTest = getMethodByName(MultiMethodExample.class, "thirdMethod", String.class); - Method firstMethodUnderTest = PredefinedGeneratorParameters.getMethodByName( - MultiMethodExample.class, - "firstMethod" - ); + // To find test sets, you need only {@link Method} instances + // and some configuration - Method secondMethodUnderTest = PredefinedGeneratorParameters.getMethodByName( - MultiMethodExample.class, - "secondMethod" - ); - - Method thirdMethodUnderTest = PredefinedGeneratorParameters.getMethodByName( - MultiMethodExample.class, - "thirdMethod", - String.class - ); - - TestMethodInfo firstTestMethodInfo = new TestMethodInfo( - firstMethodUnderTest, - initialState); - TestMethodInfo secondTestMethodInfo = new TestMethodInfo( - secondMethodUnderTest, - initialState); - TestMethodInfo thirdTestMethodInfo = new TestMethodInfo( - thirdMethodUnderTest, - thirdMethodState); - - List testSets = UtBotJavaApi.generateTestSets( - Arrays.asList(firstTestMethodInfo, secondTestMethodInfo, thirdTestMethodInfo), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Arrays.asList( + firstMethodUnderTest, + secondMethodUnderTest, + thirdMethodUnderTest + ), MultiMethodExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, MultiMethodExample.class, @@ -157,30 +100,64 @@ public void testMultiMethodClass() { MockitoStaticMocking.INSTANCE, false, ForceStaticMocking.DO_NOT_FORCE, - MultiMethodExample.class.getPackage().getName() + MultiMethodExample.class.getPackage().getName(), + new SimpleApplicationContext() + ); + + TestMethodInfo firstTestMethodInfo = buildTestMethodInfo( + firstMethodUnderTest, + classUnderTestModel, + emptyList(), + Collections.emptyMap() + ); + + TestMethodInfo secondTestMethodInfo = buildTestMethodInfo( + firstMethodUnderTest, + classUnderTestModel, + emptyList(), + Collections.emptyMap() + ); + + TestMethodInfo thirdTestMethodInfo = buildTestMethodInfo( + thirdMethodUnderTest, + classUnderTestModel, + Collections.singletonList(new UtPrimitiveModel("some")), + Collections.emptyMap() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Arrays.asList(firstTestMethodInfo, secondTestMethodInfo, thirdTestMethodInfo), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Arrays.asList( + firstTestMethodInfo, + secondTestMethodInfo, + thirdTestMethodInfo + ), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - MultiMethodExample.class + MultiMethodExample.class, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } + /** Uses {@link ClassRefExample} as a class under test. Demonstrates how to specify custom package name for the + * generate tests. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testCustomPackage() { UtBotJavaApi.setStopConcreteExecutorOnExit(false); - String classpath = getClassPath(DirectAccess.class); + String classpath = getClassPath(ClassRefExample.class); String dependencyClassPath = getDependencyClassPath(); HashMap fields = new HashMap<>(); @@ -193,35 +170,25 @@ public void testCustomPackage() { UtClassRefModel classRefModel = modelFactory.produceClassRefModel(Class.class); - EnvironmentModels initialState = new EnvironmentModels( - classUnderTestModel, - Collections.singletonList(classRefModel), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( ClassRefExample.class, "assertInstance", - Class.class - ); + Class.class); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), ClassRefExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ClassRefExample.class, @@ -232,20 +199,24 @@ public void testCustomPackage() { MockitoStaticMocking.INSTANCE, false, ForceStaticMocking.DO_NOT_FORCE, - "some.custom.name" + "some.custom.name", + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + TestMethodInfo testMethodInfo = buildTestMethodInfo( + methodUnderTest, + classUnderTestModel, + Collections.singletonList(classRefModel), + Collections.emptyMap() + ); + + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(testMethodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ClassRefExample.class, @@ -256,19 +227,27 @@ public void testCustomPackage() { MockitoStaticMocking.INSTANCE, false, ForceStaticMocking.DO_NOT_FORCE, - "some.custom.name" + "some.custom.name", + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } + /** Uses {@link AssignedArrayExample} as a class under test. Demonstrates how to specify custom package name for the + * generate tests. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testOnObjectWithAssignedArrayField() { UtBotJavaApi.setStopConcreteExecutorOnExit(false); - String classpath = getClassPath(DirectAccess.class); + String classpath = getClassPath(AssignedArray.class); String dependencyClassPath = getDependencyClassPath(); ClassId classIdAssignedArray = classIdForType(AssignedArray.class); @@ -293,36 +272,26 @@ public void testOnObjectWithAssignedArrayField() { classIdForType(AssignedArrayExample.class) ); - EnvironmentModels initialState = new EnvironmentModels( - classUnderTestModel, - Collections.singletonList(compositeModel), - Collections.emptyMap() - ); - - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( AssignedArrayExample.class, "foo", AssignedArray.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), AssignedArrayExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, AssignedArrayExample.class, @@ -332,129 +301,53 @@ public void testOnObjectWithAssignedArrayField() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, - classpath, - dependencyClassPath, - AssignedArrayExample.class, - ProjectType.PureJvm, - Junit4.INSTANCE, - MOCKITO, - CodegenLanguage.JAVA, - MockitoStaticMocking.INSTANCE, - false, - ForceStaticMocking.DO_NOT_FORCE - ); - - Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); - } - - @Test - public void testClassRef() { - - UtBotJavaApi.setStopConcreteExecutorOnExit(false); - - String classpath = getClassPath(DirectAccess.class); - String dependencyClassPath = getDependencyClassPath(); - - HashMap fields = new HashMap<>(); - fields.put("stringClass", modelFactory.produceClassRefModel(String.class)); - - UtCompositeModel classUnderTestModel = modelFactory.produceCompositeModel( - classIdForType(ClassRefExample.class), - fields - ); - - UtClassRefModel classRefModel = modelFactory.produceClassRefModel(Class.class); - - EnvironmentModels initialState = new EnvironmentModels( + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, classUnderTestModel, - Collections.singletonList(classRefModel), + Collections.singletonList(compositeModel), Collections.emptyMap() ); - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( - ClassRefExample.class, - "assertInstance", - Class.class - ); - - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - ClassRefExample.class, - classpath, - dependencyClassPath, - MockStrategyApi.OTHER_PACKAGES, - 3000L - ); - - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), - testSets, - PredefinedGeneratorParameters.destinationClassName, - classpath, - dependencyClassPath, - ClassRefExample.class, - ProjectType.PureJvm, - Junit4.INSTANCE, - MOCKITO, - CodegenLanguage.JAVA, - MockitoStaticMocking.INSTANCE, - false, - ForceStaticMocking.DO_NOT_FORCE - ); - - - Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - ClassRefExample.class, + AssignedArrayExample.class, ProjectType.PureJvm, Junit4.INSTANCE, MOCKITO, CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } + /** Uses {@link DirectAccessExample} as a class under test. Demonstrates how to test objects with public fields. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testObjectWithPublicFields() { UtBotJavaApi.setStopConcreteExecutorOnExit(false); - String classpath = getClassPath(DirectAccess.class); + String classpath = getClassPath(DirectAccessExample.class); String dependencyClassPath = getDependencyClassPath(); ClassId testClassId = classIdForType(DirectAccess.class); @@ -486,36 +379,26 @@ public void testObjectWithPublicFields() { classIdForType(DirectAccessExample.class) ); - EnvironmentModels initialState = new EnvironmentModels( - classUnderTestModel, - Collections.singletonList(compositeModel), - Collections.emptyMap() - ); - - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( DirectAccessExample.class, "foo", DirectAccess.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), DirectAccessExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, DirectAccessExample.class, @@ -525,102 +408,24 @@ public void testObjectWithPublicFields() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, - classpath, - dependencyClassPath, - DirectAccessExample.class, - ProjectType.PureJvm, - Junit4.INSTANCE, - MOCKITO, - CodegenLanguage.JAVA, - MockitoStaticMocking.INSTANCE, - false, - ForceStaticMocking.DO_NOT_FORCE - ); - - Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); - } - - @Test - public void testObjectWithPublicFieldsWithAssembleModel() { - - UtBotJavaApi.setStopConcreteExecutorOnExit(false); - - String classpath = getClassPath(DirectAccess.class); - String dependencyClassPath = getDependencyClassPath(); - - ClassId testClassId = classIdForType(DirectAccess.class); - ClassId innerClassId = classIdForType(PrimitiveFields.class); - - HashMap primitiveFields = new HashMap<>(); - primitiveFields.put("a", new UtPrimitiveModel(2)); - primitiveFields.put("b", new UtPrimitiveModel(4)); - - HashMap fields = new HashMap<>(); - fields.put("a", new UtPrimitiveModel(2)); - fields.put("b", new UtPrimitiveModel(4)); - fields.put("s", - modelFactory.produceCompositeModel( - innerClassId, - primitiveFields, - Collections.emptyMap() - ) - ); - - UtCompositeModel compositeModel = modelFactory.produceCompositeModel( - testClassId, - fields, - Collections.emptyMap() - ); - - // This class does not contain any fields. Using overloads - UtCompositeModel classUnderTestModel = modelFactory.produceCompositeModel( - classIdForType(DirectAccessExample.class) - ); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); - EnvironmentModels initialState = new EnvironmentModels( + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, classUnderTestModel, Collections.singletonList(compositeModel), Collections.emptyMap() ); - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( - DirectAccessExample.class, - "foo", - DirectAccess.class - ); - - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - DirectAccessExample.class, - classpath, - dependencyClassPath, - MockStrategyApi.OTHER_PACKAGES, - 3000L - ); - - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), - testSets, - PredefinedGeneratorParameters.destinationClassName, + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, DirectAccessExample.class, @@ -630,14 +435,21 @@ public void testObjectWithPublicFieldsWithAssembleModel() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); - Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); + Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } - + /** Uses {@link ArrayOfPrimitiveArraysExample} as a class under test. Demonstrates how to test code that uses arrays of primitives + * inside arrays. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testOnObjectWithArrayOfPrimitiveArrays() { @@ -673,44 +485,35 @@ public void testOnObjectWithArrayOfPrimitiveArrays() { enclosingArrayParameters ); - UtCompositeModel cmArrayOfPrimitiveArrays = modelFactory.produceCompositeModel( + UtCompositeModel compositeModelArrayOfPrimitiveArrays = modelFactory.produceCompositeModel( classIdArrayOfPrimitiveArraysClass, Collections.singletonMap("array", enclosingArrayOfPrimitiveArrayModel) ); - UtCompositeModel testClassCompositeModel = modelFactory.produceCompositeModel( + UtCompositeModel classUnderTestModel = modelFactory.produceCompositeModel( cidArrayOfPrimitiveArraysTest ); - EnvironmentModels initialState = new EnvironmentModels( - testClassCompositeModel, - Collections.singletonList(cmArrayOfPrimitiveArrays), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( ArrayOfPrimitiveArraysExample.class, "assign10", ArrayOfPrimitiveArrays.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), ArrayOfPrimitiveArraysExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ArrayOfPrimitiveArraysExample.class, @@ -720,20 +523,24 @@ public void testOnObjectWithArrayOfPrimitiveArrays() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet); - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + classUnderTestModel, + Collections.singletonList(compositeModelArrayOfPrimitiveArrays), + Collections.emptyMap() + ); + + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ArrayOfPrimitiveArraysExample.class, @@ -743,15 +550,19 @@ public void testOnObjectWithArrayOfPrimitiveArrays() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } - /** - * The test is inspired by the API customers + /** Example provided by customers. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. */ @Test public void testProvided3() { @@ -779,36 +590,27 @@ public void testProvided3() { Collections.singletonMap("b0", bClassModel) ); - EnvironmentModels environmentModels = new EnvironmentModels( - demo9Model, - Collections.singletonList(bClassModel), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( Demo9.class, "test", B.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - environmentModels - ) - ), + + List testSets = UtBotJavaApi.generateTestSetsForMethods( + singletonList(methodUnderTest), Demo9.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, Demo9.class, @@ -818,70 +620,72 @@ public void testProvided3() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - environmentModels - ) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); + + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + demo9Model, + Collections.singletonList(bClassModel), + Collections.emptyMap() + ); + + + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - Demo9.class + Demo9.class, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } + /** Trivial example. + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testCustomAssertion() { + String classpath = getClassPath(Trivial.class); String dependencyClassPath = getDependencyClassPath(); - UtCompositeModel model = modelFactory. + UtCompositeModel trivialModel = modelFactory. produceCompositeModel( classIdForType(Trivial.class) ); - EnvironmentModels environmentModels = new EnvironmentModels( - model, - Collections.singletonList(new UtPrimitiveModel(2)), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( Trivial.class, "aMethod", int.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - environmentModels - ) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), Trivial.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, Trivial.class, @@ -891,21 +695,24 @@ public void testCustomAssertion() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResult2 = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - environmentModels - ) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); + + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + trivialModel, + Collections.singletonList(new UtPrimitiveModel(2)), + Collections.emptyMap() + ); + + String generationResult2 = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, Trivial.class, @@ -915,11 +722,12 @@ public void testCustomAssertion() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResult2); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } /** @@ -960,42 +768,26 @@ public void testProvided3Reused() { Assertions.fail("Failed to load the class"); } - UtCompositeModel demo9Model = modelFactory. - produceCompositeModel( - classIdForType(compiledClass), - Collections.emptyMap() - ); - - EnvironmentModels environmentModels = new EnvironmentModels( - demo9Model, - Collections.singletonList(new UtPrimitiveModel(3)), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUderTest = getMethodByName( compiledClass, "test", int.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - environmentModels - ) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUderTest), compiledClass, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, compiledClass, @@ -1005,11 +797,12 @@ public void testProvided3Reused() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet); // The test compiles and everything goes well. // Let's recompile the initial clas file @@ -1039,37 +832,26 @@ public void testProvided3Reused() { Assertions.fail("Failed to load the class after recompilation"); } - EnvironmentModels environmentModels2 = new EnvironmentModels( - demo9Model, - Arrays.asList(new UtPrimitiveModel(4), new UtPrimitiveModel("Some String")), - Collections.emptyMap() - ); - - Method methodUnderTest2 = PredefinedGeneratorParameters.getMethodByName( + Method recompiledMethod = getMethodByName( recompiledClass, "test", - int.class, - String.class + int.class, String.class ); - List testSets1 = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest2, - environmentModels - ) - ), + List testSets1 = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(recompiledMethod), recompiledClass, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResultWithConcreteExecutionOnly2 = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResultWithConcreteExecutionOnly2 = UtBotJavaApi.generateTestCode( + emptyList(), testSets1, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, recompiledClass, @@ -1079,13 +861,20 @@ public void testProvided3Reused() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly2); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } + /** A test provided by our customer. Demonstrates how to use the API in + *
+ * The tests are generated with and without concrete execution. + *
+ * Note, that you can use the {@code Snippet} instance in order to evaluate the test generation result. + */ @Test public void testProvided1() { @@ -1106,36 +895,26 @@ public void testProvided1() { new UtPrimitiveModel("Some Text") ); - EnvironmentModels initialState = new EnvironmentModels( - providedTestModel, - parameters, - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( ProvidedExample.class, "test0", int.class, int.class, String.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState - ) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), ProvidedExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ProvidedExample.class, @@ -1145,28 +924,32 @@ public void testProvided1() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState - ) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); + + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + providedTestModel, + parameters, + Collections.emptyMap() + ); + + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - ProvidedExample.class + ProvidedExample.class, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } @Test @@ -1183,36 +966,26 @@ public void testOnObjectWithArrayOfComplexArrays() { classIdForType(ArrayOfComplexArraysExample.class) ); - EnvironmentModels initialState = new EnvironmentModels( - testClassCompositeModel, - Collections.singletonList(cmArrayOfComplexArrays), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( ArrayOfComplexArraysExample.class, "getValue", ArrayOfComplexArrays.class ); - List testSets = UtBotJavaApi.generateTestSets( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState - ) - ), + List testSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(methodUnderTest), ArrayOfComplexArraysExample.class, classpath, dependencyClassPath, MockStrategyApi.OTHER_PACKAGES, - 3000L + 3000L, + new SimpleApplicationContext() ); - String generationResult = UtBotJavaApi.generate( - Collections.emptyList(), + String generationResult = UtBotJavaApi.generateTestCode( + emptyList(), testSets, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, ArrayOfComplexArraysExample.class, @@ -1222,28 +995,33 @@ public void testOnObjectWithArrayOfComplexArrays() { CodegenLanguage.JAVA, MockitoStaticMocking.INSTANCE, false, - ForceStaticMocking.DO_NOT_FORCE + ForceStaticMocking.DO_NOT_FORCE, + new SimpleApplicationContext() ); Snippet snippet1 = new Snippet(CodegenLanguage.JAVA, generationResult); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet1); - - String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generate( - Collections.singletonList( - new TestMethodInfo( - methodUnderTest, - initialState - ) - ), - Collections.emptyList(), - PredefinedGeneratorParameters.destinationClassName, + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet1); + + + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + testClassCompositeModel, + Collections.singletonList(cmArrayOfComplexArrays), + Collections.emptyMap() + ); + + String generationResultWithConcreteExecutionOnly = UtBotJavaApi.generateTestCode( + Collections.singletonList(methodInfo), + emptyList(), + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - ArrayOfComplexArraysExample.class + ArrayOfComplexArraysExample.class, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generationResultWithConcreteExecutionOnly); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } @Test @@ -1258,27 +1036,14 @@ public void testFuzzingSimple() { classIdForType(StringSwitchExample.class) ); - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName(StringSwitchExample.class, "validate", String.class, int.class, int.class); - - IdentityHashMap models = modelFactory.produceAssembleModel( - methodUnderTest, + Method methodUnderTest = getMethodByName( StringSwitchExample.class, - Collections.singletonList(classUnderTestModel) - ); - - EnvironmentModels methodState = new EnvironmentModels( - models.get(classUnderTestModel), - Arrays.asList(new UtPrimitiveModel("initial model"), new UtPrimitiveModel(-10), new UtPrimitiveModel(0)), - Collections.emptyMap() + "validate", + String.class, int.class, int.class ); - TestMethodInfo methodInfo = new TestMethodInfo( - methodUnderTest, - methodState); List testSets1 = UtBotJavaApi.fuzzingTestSets( - Collections.singletonList( - methodInfo - ), + Collections.singletonList(methodUnderTest), StringSwitchExample.class, classpath, dependencyClassPath, @@ -1289,53 +1054,31 @@ public void testFuzzingSimple() { return Arrays.asList(0, Integer.MIN_VALUE, Integer.MAX_VALUE); } return null; - } + }, + new SimpleApplicationContext() + ); + + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + classUnderTestModel, + Arrays.asList(new UtPrimitiveModel("Some"), new UtPrimitiveModel(-10), new UtPrimitiveModel(0)), + Collections.emptyMap() ); - String generate = UtBotJavaApi.generate( + String generate = UtBotJavaApi.generateTestCode( Collections.singletonList(methodInfo), testSets1, - PredefinedGeneratorParameters.destinationClassName, + GENERATED_TEST_CLASS_NAME, classpath, dependencyClassPath, - StringSwitchExample.class + StringSwitchExample.class, + new SimpleApplicationContext() ); Snippet snippet2 = new Snippet(CodegenLanguage.JAVA, generate); - compileClassFile(PredefinedGeneratorParameters.destinationClassName, snippet2); - } - - @NotNull - private String getClassPath(Class clazz) { - try { - return normalizePath(clazz.getProtectionDomain().getCodeSource().getLocation()); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - - @NotNull - private String normalizePath(URL url) throws URISyntaxException { - return new File(url.toURI()).getPath(); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet2); } - @NotNull - private String getDependencyClassPath() { - - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - URL[] urls = PathUtil.getUrlsFromClassLoader(contextClassLoader); - - - return Arrays.stream(urls).map(url -> - { - try { - return new File(url.toURI()).toString(); - } catch (URISyntaxException e) { - Assertions.fail(e); - } - throw new RuntimeException(); - }).collect(Collectors.joining(File.pathSeparator)); - } public UtCompositeModel createArrayOfComplexArraysModel() { ClassId classIdOfArrayOfComplexArraysClass = classIdForType(ArrayOfComplexArrays.class); ClassId classIdOfComplexArray = classIdForType(ComplexArray.class); @@ -1397,24 +1140,22 @@ public void testUnitTestBotLight() { classIdForType(Trivial.class) ); - EnvironmentModels environmentModels = new EnvironmentModels( - model, - Collections.singletonList(new UtPrimitiveModel(2)), - Collections.emptyMap() - ); - - Method methodUnderTest = PredefinedGeneratorParameters.getMethodByName( + Method methodUnderTest = getMethodByName( Trivial.class, "aMethod", int.class ); + TestMethodInfo methodInfo = buildTestMethodInfo( + methodUnderTest, + model, + Collections.singletonList(new UtPrimitiveModel(2)), + Collections.emptyMap() + ); + UnitTestBotLight.run( (engine, state) -> System.err.println("Got a call:" + state.getStmt()), - new TestMethodInfo( - methodUnderTest, - environmentModels - ), + methodInfo, classpath, dependencyClassPath ); diff --git a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt index 4963223b84..ecfb1c1634 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/external/api/UtBotJavaApi.kt @@ -3,28 +3,14 @@ package org.utbot.external.api import org.utbot.common.FileUtil import org.utbot.common.nameOfPackage import org.utbot.framework.UtSettings -import org.utbot.framework.codegen.domain.ForceStaticMocking -import org.utbot.framework.codegen.domain.Junit5 -import org.utbot.framework.codegen.domain.NoStaticMocking -import org.utbot.framework.codegen.domain.ProjectType -import org.utbot.framework.codegen.domain.StaticsMocking -import org.utbot.framework.codegen.domain.TestFramework -import org.utbot.framework.codegen.generator.CodeGenerator +import org.utbot.framework.codegen.domain.* import org.utbot.framework.codegen.generator.CodeGeneratorParams import org.utbot.framework.codegen.services.language.CgLanguageAssistant -import org.utbot.framework.context.simple.SimpleApplicationContext +import org.utbot.framework.context.ApplicationContext import org.utbot.framework.context.utils.transformValueProvider import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionData import org.utbot.instrumentation.instrumentation.execution.UtConcreteExecutionResult import org.utbot.instrumentation.instrumentation.execution.UtExecutionInstrumentation -import org.utbot.framework.plugin.api.ClassId -import org.utbot.framework.plugin.api.CodegenLanguage -import org.utbot.framework.plugin.api.MockFramework -import org.utbot.framework.plugin.api.MockStrategyApi -import org.utbot.framework.plugin.api.TestCaseGenerator -import org.utbot.framework.plugin.api.UtMethodTestSet -import org.utbot.framework.plugin.api.UtPrimitiveModel -import org.utbot.framework.plugin.api.UtSymbolicExecution import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.executableId import org.utbot.framework.plugin.api.util.id @@ -36,26 +22,53 @@ import org.utbot.framework.plugin.api.util.stringClassId import org.utbot.framework.plugin.api.util.withUtContext import org.utbot.framework.plugin.api.util.wrapperByPrimitive import org.utbot.framework.plugin.services.JdkInfoDefaultProvider -import org.utbot.fuzzer.FuzzedType import org.utbot.fuzzer.FuzzedValue -import org.utbot.fuzzing.FuzzedDescription import org.utbot.fuzzing.JavaValueProvider import org.utbot.fuzzing.Seed -import org.utbot.fuzzing.ValueProvider import org.utbot.instrumentation.ConcreteExecutor import org.utbot.instrumentation.execute -import org.utbot.instrumentation.instrumentation.execution.SimpleUtExecutionInstrumentation -import java.io.File import kotlin.reflect.jvm.kotlinFunction +import org.utbot.framework.codegen.domain.StaticsMocking +import org.utbot.framework.plugin.api.* +import java.lang.reflect.Method object UtBotJavaApi { + /** + * For running tests it could be reasonable to reuse the same concrete executor + */ @JvmStatic var stopConcreteExecutorOnExit: Boolean = true + /** + * Generates test code + * @param methodsForGeneration specify methods that are supposed to be executed concretely. + * In order to execute method you are supposed to provide some + * values to pass in it this is why we use [TestMethodInfo] here. + * @param generatedTestCases specify [UtMethodTestSet]s that are used for test code + * generation. By comparison with the first parameter, + * {@code UtMethodTestSet} contains more information about + * test, including result of the executions. Note, that + * you can get the object with any sort of analysis, + * for instance, symbolic or fuzz execution. + * @param destinationClassName the name of containing class for the generated tests + * @param classpath classpath that are used to build the class under test + * @param dependencyClassPath class path including dependencies required for the code generation + * @param classUnderTest for this class test should be generated + * @param projectType JVM, Spring, Python, or other type of project + * @param testFramework test framework that is going to be used for running generated tests + * @param mockFramework framework that will be used in the generated tests + * @param codegenLanguage the target language of the test generation. It can be different from the source language. + * @param staticsMocking the approach to the statics mocking + * @param generateWarningsForStaticMocking enable generation of warning about forced static mocking in comments + * of generated tests. + * @param forceStaticMocking enables static mocking + * @param testClassPackageName package name for the generated class with the tests + * @param applicationContext specify application context here + */ @JvmStatic @JvmOverloads - fun generate( + fun generateTestCode( methodsForGeneration: List, generatedTestCases: List = mutableListOf(), destinationClassName: String, @@ -69,16 +82,18 @@ object UtBotJavaApi { staticsMocking: StaticsMocking = NoStaticMocking, generateWarningsForStaticMocking: Boolean = false, forceStaticMocking: ForceStaticMocking = ForceStaticMocking.DO_NOT_FORCE, - testClassPackageName: String = classUnderTest.nameOfPackage + testClassPackageName: String = classUnderTest.nameOfPackage, + applicationContext: ApplicationContext ): String { - val utContext = UtContext(classUnderTest.classLoader) - val testSets: MutableList = generatedTestCases.toMutableList() val concreteExecutor = ConcreteExecutor( - SimpleUtExecutionInstrumentation.Factory(pathsToUserClasses = classpath.split(File.pathSeparator).toSet()), - classpath, + applicationContext.createConcreteExecutionContext( + fullClasspath = dependencyClassPath, + classpathWithoutDependencies = classpath + ).instrumentationFactory, + classpath ) testSets.addAll(generateUnitTests(concreteExecutor, methodsForGeneration, classUnderTest)) @@ -87,8 +102,8 @@ object UtBotJavaApi { concreteExecutor.close() } - return withUtContext(utContext) { - val codeGenerator = CodeGenerator( + return withUtContext(UtContext(classUnderTest.classLoader)) { + applicationContext.createCodeGenerator( CodeGeneratorParams( classUnderTest = classUnderTest.id, projectType = projectType, @@ -99,11 +114,9 @@ object UtBotJavaApi { staticsMocking = staticsMocking, forceStaticMocking = forceStaticMocking, generateWarningsForStaticMocking = generateWarningsForStaticMocking, - testClassPackageName = testClassPackageName + testClassPackageName = testClassPackageName, ) - ) - - codeGenerator.generateAsString(testSets, destinationClassName) + ).generateAsString(testSets, destinationClassName) } } @@ -114,29 +127,36 @@ object UtBotJavaApi { */ @JvmStatic @JvmOverloads - fun generateTestSets( - methodsForAutomaticGeneration: List, + fun generateTestSetsForMethods( + methodsToAnalyze: List, classUnderTest: Class<*>, classpath: String, dependencyClassPath: String, mockStrategyApi: MockStrategyApi = MockStrategyApi.OTHER_PACKAGES, - generationTimeoutInMillis: Long = UtSettings.utBotGenerationTimeoutInMillis + generationTimeoutInMillis: Long = UtSettings.utBotGenerationTimeoutInMillis, + applicationContext: ApplicationContext ): MutableList { + assert(methodsToAnalyze.all {classUnderTest.declaredMethods.contains(it)}) + { "Some methods are absent in the ${classUnderTest.name} class." } + val utContext = UtContext(classUnderTest.classLoader) val testSets: MutableList = mutableListOf() testSets.addAll(withUtContext(utContext) { val buildPath = FileUtil.isolateClassFiles(classUnderTest).toPath() - TestCaseGenerator(listOf(buildPath), classpath, dependencyClassPath, jdkInfo = JdkInfoDefaultProvider().info) - .generate( - methodsForAutomaticGeneration.map { - it.methodToBeTestedFromUserInput.executableId - }, - mockStrategyApi, - chosenClassesToMockAlways = emptySet(), - generationTimeoutInMillis - ) + TestCaseGenerator( + listOf(buildPath), + classpath, + dependencyClassPath, + jdkInfo = JdkInfoDefaultProvider().info, + applicationContext = applicationContext + ).generate( + methodsToAnalyze.map { it.executableId }, + mockStrategyApi, + chosenClassesToMockAlways = emptySet(), + generationTimeoutInMillis + ) }) return testSets @@ -145,19 +165,24 @@ object UtBotJavaApi { /** * Generates test cases using only fuzzing workflow. * - * @see [generateTestSets] + * @see [generateTestSetsForMethods] */ @JvmStatic @JvmOverloads fun fuzzingTestSets( - methodsForAutomaticGeneration: List, + methodsToAnalyze: List, classUnderTest: Class<*>, classpath: String, dependencyClassPath: String, mockStrategyApi: MockStrategyApi = MockStrategyApi.OTHER_PACKAGES, generationTimeoutInMillis: Long = UtSettings.utBotGenerationTimeoutInMillis, - primitiveValuesSupplier: CustomFuzzerValueSupplier = CustomFuzzerValueSupplier { null } + primitiveValuesSupplier: CustomFuzzerValueSupplier = CustomFuzzerValueSupplier { null }, + applicationContext: ApplicationContext ): MutableList { + + assert(methodsToAnalyze.all {classUnderTest.declaredMethods.contains(it)}) + { "Some methods are absent in the ${classUnderTest.name} class." } + fun createPrimitiveModels(supplier: CustomFuzzerValueSupplier, classId: ClassId): Sequence = supplier .takeIf { classId.isPrimitive || classId.isPrimitiveWrapper || classId == stringClassId } @@ -189,14 +214,12 @@ object UtBotJavaApi { classpath, dependencyClassPath, jdkInfo = JdkInfoDefaultProvider().info, - applicationContext = SimpleApplicationContext().transformValueProvider { defaultModelProvider -> + applicationContext = applicationContext.transformValueProvider { defaultModelProvider -> customModelProvider.withFallback(defaultModelProvider) } ) .generate( - methodsForAutomaticGeneration.map { - it.methodToBeTestedFromUserInput.executableId - }, + methodsToAnalyze.map{ it.executableId }, mockStrategyApi, chosenClassesToMockAlways = emptySet(), generationTimeoutInMillis, diff --git a/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyService.java b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyService.java new file mode 100644 index 0000000000..7e9f49b37e --- /dev/null +++ b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyService.java @@ -0,0 +1,5 @@ +package org.utbot.examples.spring.app; + +public interface MyService { + String getName(); +} diff --git a/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceImpl.java b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceImpl.java new file mode 100644 index 0000000000..6f711df70b --- /dev/null +++ b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceImpl.java @@ -0,0 +1,11 @@ +package org.utbot.examples.spring.app; + +import org.springframework.stereotype.Service; + +@Service +public class MyServiceImpl implements MyService { + @Override + public String getName() { + return "impl"; + } +} diff --git a/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceUser.java b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceUser.java new file mode 100644 index 0000000000..d1db7260c2 --- /dev/null +++ b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/MyServiceUser.java @@ -0,0 +1,18 @@ +package org.utbot.examples.spring.app; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MyServiceUser { + private final MyService myService; + + @Autowired + public MyServiceUser(MyService myService) { + this.myService = myService; + } + + public String useMyService() { + return myService.getName(); + } +} diff --git a/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/SpringExampleApp.java b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/SpringExampleApp.java new file mode 100644 index 0000000000..32f4cd0c94 --- /dev/null +++ b/utbot-spring-sample/src/main/java/org/utbot/examples/spring/app/SpringExampleApp.java @@ -0,0 +1,7 @@ +package org.utbot.examples.spring.app; + +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringExampleApp { +} diff --git a/utbot-spring-test/src/test/java/org/utbot/api/java/SpringUtBotJavaApiTest.java b/utbot-spring-test/src/test/java/org/utbot/api/java/SpringUtBotJavaApiTest.java new file mode 100644 index 0000000000..09a5594bc1 --- /dev/null +++ b/utbot-spring-test/src/test/java/org/utbot/api/java/SpringUtBotJavaApiTest.java @@ -0,0 +1,105 @@ +package org.utbot.api.java; + +import org.utbot.examples.spring.app.MyServiceImpl; +import org.junit.jupiter.api.Test; +import org.utbot.examples.spring.app.MyServiceUser; +import org.utbot.examples.spring.app.SpringExampleApp; +import org.utbot.examples.spring.config.pure.ExamplePureSpringConfig; +import org.utbot.external.api.UtBotJavaApi; +import org.utbot.external.api.UtBotSpringApi; +import org.utbot.framework.codegen.domain.ForceStaticMocking; +import org.utbot.framework.codegen.domain.Junit4; +import org.utbot.framework.codegen.domain.MockitoStaticMocking; +import org.utbot.framework.codegen.domain.ProjectType; +import org.utbot.framework.context.ApplicationContext; +import org.utbot.framework.context.spring.SpringApplicationContext; +import org.utbot.framework.plugin.api.*; +import org.utbot.framework.util.Snippet; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.*; + +import static org.utbot.framework.plugin.api.MockFramework.MOCKITO; +import static org.utbot.framework.util.TestUtilsKt.compileClassFile; + +public class SpringUtBotJavaApiTest extends AbstractUtBotJavaApiTest { + + /** + * We are using the environment to check spring generation the only difference in the data supplied by the argument + * @param applicationContext returns Spring settings to run the generation with + */ + private void supplyConfigurationAndRunSpringTest(ApplicationContext applicationContext) { + + UtBotJavaApi.setStopConcreteExecutorOnExit(false); + + String classpath = getClassPath(MyServiceImpl.class); + String dependencyClassPath = getDependencyClassPath(); + + Method getNameMethod = getMethodByName( + MyServiceImpl.class, + "getName" + ); + + Method useMyServiceMethod = getMethodByName( + MyServiceUser.class, + "useMyService" + ); + + List myServiceUserTestSets = UtBotJavaApi.generateTestSetsForMethods( + Collections.singletonList(useMyServiceMethod), + MyServiceUser.class, + classpath, + dependencyClassPath, + MockStrategyApi.OTHER_PACKAGES, + 60000L, + applicationContext + ); + + String generationResult = UtBotJavaApi.generateTestCode( + Collections.emptyList(), + myServiceUserTestSets, + GENERATED_TEST_CLASS_NAME, + classpath, + dependencyClassPath, + MyServiceUser.class, + ProjectType.Spring, + Junit4.INSTANCE, + MOCKITO, + CodegenLanguage.JAVA, + MockitoStaticMocking.INSTANCE, + false, + ForceStaticMocking.DO_NOT_FORCE, + MyServiceUser.class.getPackage().getName(), + applicationContext + ); + + Snippet snippet = new Snippet(CodegenLanguage.JAVA, generationResult); + compileClassFile(GENERATED_TEST_CLASS_NAME, snippet); + } + + @Test + public void testUnitTestWithoutSettings() { + supplyConfigurationAndRunSpringTest(UtBotSpringApi.createSpringApplicationContext( + SpringSettings.AbsentSpringSettings, + SpringTestType.UNIT_TEST, + Collections.emptyList())); + } + + @Test + public void testUnitTestWithSettings() { + SpringConfiguration configuration = + UtBotSpringApi.createJavaSpringConfiguration(SpringExampleApp.class); + + SpringSettings springSettings = + new SpringSettings.PresentSpringSettings(configuration, Arrays.asList("test1", "test2")); + + ApplicationContext applicationContext = UtBotSpringApi.createSpringApplicationContext( + springSettings, + SpringTestType.UNIT_TEST, + Arrays.asList(getDependencyClassPath().split(File.pathSeparator)) + ); + + supplyConfigurationAndRunSpringTest(applicationContext); + } +} diff --git a/utbot-spring-test/src/test/java/org/utbot/examples/spring/manual/UtBotSpringApiTest.java b/utbot-spring-test/src/test/java/org/utbot/examples/spring/manual/UtBotSpringApiTest.java index 94a62cbc0f..7e318a3c03 100644 --- a/utbot-spring-test/src/test/java/org/utbot/examples/spring/manual/UtBotSpringApiTest.java +++ b/utbot-spring-test/src/test/java/org/utbot/examples/spring/manual/UtBotSpringApiTest.java @@ -28,7 +28,7 @@ public class UtBotSpringApiTest { public void testOnAbsentSpringSettings() { SpringApplicationContext springApplicationContext = UtBotSpringApi.createSpringApplicationContext( - SpringSettings.AbsentSpringSettings.INSTANCE, + SpringSettings.AbsentSpringSettings, SpringTestType.UNIT_TEST, new ArrayList<>() ); @@ -147,14 +147,14 @@ public void testOnXmlConfig() throws IOException { assertEquals(expected, actual); } - private List getBeansFromSampleProject( + static List getBeansFromSampleProject( SpringConfiguration configuration, List profiles ) { return getBeansFromSampleProject(configuration, profiles, new ArrayList<>()); } - private List getBeansFromSampleProject( + static List getBeansFromSampleProject( SpringConfiguration configuration, List profiles, List additionalClasspath diff --git a/utbot-testing/src/main/java/org/utbot/api/java/AbstractUtBotJavaApiTest.java b/utbot-testing/src/main/java/org/utbot/api/java/AbstractUtBotJavaApiTest.java new file mode 100644 index 0000000000..90b81bdb51 --- /dev/null +++ b/utbot-testing/src/main/java/org/utbot/api/java/AbstractUtBotJavaApiTest.java @@ -0,0 +1,114 @@ +package org.utbot.api.java; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.utbot.common.PathUtil; +import org.utbot.external.api.TestMethodInfo; +import org.utbot.external.api.UtModelFactory; +import org.utbot.framework.plugin.api.*; +import org.utbot.framework.plugin.api.util.UtContext; + +import java.io.File; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.utbot.framework.plugin.api.util.IdUtilKt.getExecutableId; + +/** + * Extracted to share between modules + */ +public class AbstractUtBotJavaApiTest { + + public static final String GENERATED_TEST_CLASS_NAME = "GeneratedTest"; + + public static Method getMethodByName(Class clazz, String name, Class... parameters) { + try { + return clazz.getDeclaredMethod(name, parameters); + } catch (NoSuchMethodException ignored) { + Assertions.fail(); + } + throw new RuntimeException(); + } + + private AutoCloseable context; + // Helpful hand to create models for classes + protected UtModelFactory modelFactory; + + @BeforeEach + public void setUp() { + context = UtContext.Companion.setUtContext(new UtContext(UtContext.class.getClassLoader())); + modelFactory = new UtModelFactory(); + } + + @AfterEach + public void tearDown() { + try { + context.close(); + modelFactory = null; + } catch (Exception e) { + Assertions.fail(); + } + } + + protected static TestMethodInfo buildTestMethodInfo( + Method methodUnderTest, + UtCompositeModel classUnderTestModel, + List parametersModels, + Map staticsModels + ) { + + ExecutableId methodExecutableId = getExecutableId(methodUnderTest); + EnvironmentModels methodState = new EnvironmentModels( + classUnderTestModel, + parametersModels, + staticsModels, + methodExecutableId + ); + + return new TestMethodInfo(methodUnderTest, methodState); + } + + /** + * Utility method to get class path of the class + */ + @NotNull + protected static String getClassPath(Class clazz) { + try { + return normalizePath(clazz.getProtectionDomain().getCodeSource().getLocation()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @NotNull + protected static String normalizePath(URL url) throws URISyntaxException { + return new File(url.toURI()).getPath(); + } + + /** + * @return classpath of the current thread. For testing environment only. + */ + @NotNull + protected static String getDependencyClassPath() { + + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + URL[] urls = PathUtil.getUrlsFromClassLoader(contextClassLoader); + + return Arrays.stream(urls).map(url -> + { + try { + return new File(url.toURI()).toString(); + } catch (URISyntaxException e) { + Assertions.fail(e); + } + throw new RuntimeException(); + }).collect(Collectors.joining(File.pathSeparator)); + } +}