@@ -6,24 +6,32 @@ import org.utbot.framework.codegen.ParametrizedTestSource
6
6
import org.utbot.framework.codegen.RuntimeExceptionTestsBehaviour
7
7
import org.utbot.framework.codegen.StaticsMocking
8
8
import org.utbot.framework.codegen.TestFramework
9
+ import org.utbot.framework.codegen.model.constructor.builtin.TestClassUtilMethodProvider
10
+ import org.utbot.framework.codegen.model.constructor.builtin.UtilClassFileMethodProvider
9
11
import org.utbot.framework.codegen.model.constructor.CgMethodTestSet
10
12
import org.utbot.framework.codegen.model.constructor.context.CgContext
13
+ import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
11
14
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor
15
+ import org.utbot.framework.codegen.model.constructor.tree.CgUtilClassConstructor
12
16
import org.utbot.framework.codegen.model.constructor.tree.TestsGenerationReport
13
- import org.utbot.framework.codegen.model.tree.CgTestClassFile
17
+ import org.utbot.framework.codegen.model.tree.AbstractCgClassFile
18
+ import org.utbot.framework.codegen.model.tree.CgRegularClassFile
14
19
import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer
15
20
import org.utbot.framework.plugin.api.ClassId
16
21
import org.utbot.framework.plugin.api.CodegenLanguage
17
22
import org.utbot.framework.plugin.api.ExecutableId
18
23
import org.utbot.framework.plugin.api.MockFramework
19
24
import org.utbot.framework.plugin.api.UtMethodTestSet
20
25
import org.utbot.framework.codegen.model.constructor.TestClassModel
26
+ import org.utbot.framework.codegen.model.tree.CgComment
27
+ import org.utbot.framework.codegen.model.tree.CgSingleLineComment
21
28
22
29
class CodeGenerator (
23
30
private val classUnderTest : ClassId ,
24
31
paramNames : MutableMap <ExecutableId , List <String >> = mutableMapOf(),
32
+ generateUtilClassFile : Boolean = false ,
25
33
testFramework : TestFramework = TestFramework .defaultItem,
26
- mockFramework : MockFramework ? = MockFramework .defaultItem,
34
+ mockFramework : MockFramework = MockFramework .defaultItem,
27
35
staticsMocking : StaticsMocking = StaticsMocking .defaultItem,
28
36
forceStaticMocking : ForceStaticMocking = ForceStaticMocking .defaultItem,
29
37
generateWarningsForStaticMocking : Boolean = true ,
@@ -36,9 +44,10 @@ class CodeGenerator(
36
44
) {
37
45
private var context: CgContext = CgContext (
38
46
classUnderTest = classUnderTest,
47
+ generateUtilClassFile = generateUtilClassFile,
39
48
paramNames = paramNames,
40
49
testFramework = testFramework,
41
- mockFramework = mockFramework ? : MockFramework . MOCKITO ,
50
+ mockFramework = mockFramework,
42
51
codegenLanguage = codegenLanguage,
43
52
parametrizedTestSource = parameterizedTestSource,
44
53
staticsMocking = staticsMocking,
@@ -58,19 +67,23 @@ class CodeGenerator(
58
67
fun generateAsStringWithTestReport (
59
68
testSets : Collection <UtMethodTestSet >,
60
69
testClassCustomName : String? = null,
61
- ): TestsCodeWithTestReport {
70
+ ): CodeGeneratorResult {
62
71
val cgTestSets = testSets.map { CgMethodTestSet (it) }.toList()
63
72
return generateAsStringWithTestReport(cgTestSets, testClassCustomName)
64
73
}
65
74
66
75
private fun generateAsStringWithTestReport (
67
76
cgTestSets : List <CgMethodTestSet >,
68
77
testClassCustomName : String? = null,
69
- ): TestsCodeWithTestReport = withCustomContext(testClassCustomName) {
78
+ ): CodeGeneratorResult = withCustomContext(testClassCustomName) {
70
79
context.withTestClassFileScope {
71
80
val testClassModel = TestClassModel .fromTestSets(classUnderTest, cgTestSets)
72
81
val testClassFile = CgTestClassConstructor (context).construct(testClassModel)
73
- TestsCodeWithTestReport (renderClassFile(testClassFile), testClassFile.testsGenerationReport)
82
+ CodeGeneratorResult (
83
+ generatedCode = renderClassFile(testClassFile),
84
+ utilClassKind = UtilClassKind .fromCgContextOrNull(context),
85
+ testsGenerationReport = testClassFile.testsGenerationReport
86
+ )
74
87
}
75
88
}
76
89
@@ -92,12 +105,153 @@ class CodeGenerator(
92
105
}
93
106
}
94
107
95
- private fun renderClassFile (file : CgTestClassFile ): String {
108
+ private fun renderClassFile (file : AbstractCgClassFile < * > ): String {
96
109
val renderer = CgAbstractRenderer .makeRenderer(context)
97
110
file.accept(renderer)
98
111
return renderer.toString()
99
112
}
100
113
}
101
114
102
- data class TestsCodeWithTestReport (val generatedCode : String , val testsGenerationReport : TestsGenerationReport )
115
+ /* *
116
+ * @property generatedCode the source code of the test class
117
+ * @property utilClassKind the kind of util class if it is required, otherwise - null
118
+ * @property testsGenerationReport some info about test generation process
119
+ */
120
+ data class CodeGeneratorResult (
121
+ val generatedCode : String ,
122
+ // null if no util class needed, e.g. when we are generating utils directly into test class
123
+ val utilClassKind : UtilClassKind ? ,
124
+ val testsGenerationReport : TestsGenerationReport ,
125
+ )
126
+
127
+ /* *
128
+ * A kind of util class. See the description of each kind at their respective classes.
129
+ * @property utilMethodProvider a [UtilClassFileMethodProvider] containing information about
130
+ * utilities that come from a separately generated UtUtils class
131
+ * (as opposed to utils that are declared directly in the test class, for example).
132
+ * @property mockFrameworkUsed a flag indicating if a mock framework was used.
133
+ * For detailed description see [CgContextOwner.mockFrameworkUsed].
134
+ * @property mockFramework a framework used to create mocks
135
+ * @property priority when we generate multiple test classes, they can require different [UtilClassKind].
136
+ * We will generate an util class corresponding to the kind with the greatest priority.
137
+ * For example, one test class may not use mocks, but the other one does.
138
+ * Then we will generate an util class with mocks, because it has a greater priority (see [UtUtilsWithMockito]).
139
+ */
140
+ sealed class UtilClassKind (
141
+ internal val utilMethodProvider : UtilClassFileMethodProvider ,
142
+ internal val mockFrameworkUsed : Boolean ,
143
+ internal val mockFramework : MockFramework = MockFramework .MOCKITO ,
144
+ private val priority : Int
145
+ ) : Comparable<UtilClassKind> {
146
+
147
+ /* *
148
+ * The version of util class being generated.
149
+ * For more details see [UtilClassFileMethodProvider.UTIL_CLASS_VERSION].
150
+ */
151
+ val utilClassVersion: String
152
+ get() = UtilClassFileMethodProvider .UTIL_CLASS_VERSION
153
+
154
+ /* *
155
+ * The comment specifying the version of util class being generated.
156
+ *
157
+ * @see UtilClassFileMethodProvider.UTIL_CLASS_VERSION
158
+ */
159
+ val utilClassVersionComment: CgComment
160
+ get() = CgSingleLineComment (" $UTIL_CLASS_VERSION_COMMENT_PREFIX${utilClassVersion} " )
161
+
162
+
163
+ /* *
164
+ * The comment specifying the kind of util class being generated.
165
+ *
166
+ * @see utilClassKindCommentText
167
+ */
168
+ val utilClassKindComment: CgComment
169
+ get() = CgSingleLineComment (utilClassKindCommentText)
170
+
171
+ /* *
172
+ * The text of comment specifying the kind of util class.
173
+ * At the moment, there are two kinds: [RegularUtUtils] (without Mockito) and [UtUtilsWithMockito].
174
+ *
175
+ * This comment is needed when the plugin decides whether to overwrite an existing util class or not.
176
+ * When making that decision, it is important to determine if the existing class uses mocks or not,
177
+ * and this comment will help do that.
178
+ */
179
+ abstract val utilClassKindCommentText: String
103
180
181
+ /* *
182
+ * A kind of regular UtUtils class. "Regular" here means that this class does not use a mock framework.
183
+ */
184
+ object RegularUtUtils : UtilClassKind(UtilClassFileMethodProvider , mockFrameworkUsed = false , priority = 0 ) {
185
+ override val utilClassKindCommentText: String
186
+ get() = " This is a regular UtUtils class (without mock framework usage)"
187
+ }
188
+
189
+ /* *
190
+ * A kind of UtUtils class that uses a mock framework. At the moment the framework is Mockito.
191
+ */
192
+ object UtUtilsWithMockito : UtilClassKind(UtilClassFileMethodProvider , mockFrameworkUsed = true , priority = 1 ) {
193
+ override val utilClassKindCommentText: String
194
+ get() = " This is UtUtils class with Mockito support"
195
+ }
196
+
197
+ override fun compareTo (other : UtilClassKind ): Int {
198
+ return priority.compareTo(other.priority)
199
+ }
200
+
201
+ /* *
202
+ * Construct an util class file as a [CgRegularClassFile] and render it.
203
+ * @return the text of the generated util class file.
204
+ */
205
+ fun getUtilClassText (codegenLanguage : CodegenLanguage ): String {
206
+ val utilClassFile = CgUtilClassConstructor .constructUtilsClassFile(this )
207
+ val renderer = CgAbstractRenderer .makeRenderer(this , codegenLanguage)
208
+ utilClassFile.accept(renderer)
209
+ return renderer.toString()
210
+ }
211
+
212
+ companion object {
213
+
214
+ /* *
215
+ * Class UtUtils will contain a comment specifying the version of this util class
216
+ * (if we ever change util methods, then util class will be different, hence the update of its version).
217
+ * This is a prefix that will go before the version in the comment.
218
+ */
219
+ const val UTIL_CLASS_VERSION_COMMENT_PREFIX = " UtUtils class version: "
220
+
221
+ fun utilClassKindByCommentOrNull (comment : String ): UtilClassKind ? {
222
+ return when (comment) {
223
+ RegularUtUtils .utilClassKindCommentText -> RegularUtUtils
224
+ UtUtilsWithMockito .utilClassKindCommentText -> UtUtilsWithMockito
225
+ else -> null
226
+ }
227
+ }
228
+
229
+ /* *
230
+ * Check if an util class is required, and if so, what kind.
231
+ * @return `null` if [CgContext.utilMethodProvider] is not [UtilClassFileMethodProvider],
232
+ * because it means that util methods will be taken from some other provider (e.g. [TestClassUtilMethodProvider]).
233
+ */
234
+ internal fun fromCgContextOrNull (context : CgContext ): UtilClassKind ? {
235
+ if (context.requiredUtilMethods.isEmpty()) return null
236
+ if (! context.mockFrameworkUsed) {
237
+ return RegularUtUtils
238
+ }
239
+ return when (context.mockFramework) {
240
+ MockFramework .MOCKITO -> UtUtilsWithMockito
241
+ // in case we will add any other mock frameworks, newer Kotlin compiler versions
242
+ // will report a non-exhaustive 'when', so we will not forget to support them here as well
243
+ }
244
+ }
245
+
246
+ const val UT_UTILS_PACKAGE_NAME = " org.utbot.runtime.utils"
247
+ const val UT_UTILS_CLASS_NAME = " UtUtils"
248
+ const val PACKAGE_DELIMITER = " ."
249
+
250
+ /* *
251
+ * List of package names of UtUtils class.
252
+ * See whole package name at [UT_UTILS_PACKAGE_NAME].
253
+ */
254
+ val utilsPackages: List <String >
255
+ get() = UT_UTILS_PACKAGE_NAME .split(PACKAGE_DELIMITER )
256
+ }
257
+ }
0 commit comments