@@ -12,12 +12,89 @@ import org.utbot.fuzzer.providers.PrimitiveDefaultsModelProvider
12
12
import org.utbot.fuzzer.providers.EnumModelProvider
13
13
import org.utbot.fuzzer.providers.PrimitiveWrapperModelProvider
14
14
import java.lang.IllegalArgumentException
15
+ import java.util.IdentityHashMap
15
16
import java.util.concurrent.atomic.AtomicInteger
16
- import java.util.function.IntSupplier
17
17
import kotlin.random.Random
18
18
19
19
private val logger by lazy { KotlinLogging .logger {} }
20
20
21
+ /* *
22
+ * Identifier generator interface for fuzzer model providers.
23
+ *
24
+ * Provides fresh identifiers for generated models.
25
+ *
26
+ * Warning: specific generators are not guaranteed to be thread-safe.
27
+ *
28
+ * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers)
29
+ */
30
+ interface IdGenerator <Id > {
31
+ /* *
32
+ * Create a fresh identifier. Each subsequent call should return a different value.
33
+ *
34
+ * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee.
35
+ */
36
+ fun createId (): Id
37
+ }
38
+
39
+ /* *
40
+ * Identity preserving identifier generator interface.
41
+ *
42
+ * It allows to optionally save identifiers assigned to specific objects and later get the same identifiers
43
+ * for these objects instead of fresh identifiers. This feature is necessary, for example, to implement reference
44
+ * equality for enum models.
45
+ *
46
+ * Warning: specific generators are not guaranteed to be thread-safe.
47
+ *
48
+ * @param Id the identifier type (e.g., [Int] for [UtReferenceModel] providers)
49
+ */
50
+ interface IdentityPreservingIdGenerator <Id > : IdGenerator <Id > {
51
+ /* *
52
+ * Return an identifier for a specified non-null object. If an identifier has already been assigned
53
+ * to an object, subsequent calls should return the same identifier for this object.
54
+ *
55
+ * Note: the interface does not specify whether reference equality or regular `equals`/`compareTo` equality
56
+ * will be used to compare objects. Each implementation may provide these guarantees by itself.
57
+ *
58
+ * The method is not guaranteed to be thread-safe, unless an implementation makes such a guarantee.
59
+ */
60
+ fun getOrCreateIdForValue (value : Any ): Id
61
+ }
62
+
63
+ /* *
64
+ * An identity preserving id generator for fuzzer value providers that returns identifiers of type [Int].
65
+ *
66
+ * When identity-preserving identifier is requested, objects are compared by reference.
67
+ * The generator is not thread-safe.
68
+ *
69
+ * @param lowerBound an integer value so that any generated identifier is strictly greater than it.
70
+ *
71
+ * Warning: when generating [UtReferenceModel] identifiers, no identifier should be equal to zero,
72
+ * as this value is reserved for [UtNullModel]. To guarantee it, [lowerBound] should never be negative.
73
+ * Avoid using custom lower bounds (maybe except fuzzer unit tests), use the predefined default value instead.
74
+ */
75
+ class ReferencePreservingIntIdGenerator (lowerBound : Int = DEFAULT_LOWER_BOUND ) : IdentityPreservingIdGenerator<Int> {
76
+ private val lastId: AtomicInteger = AtomicInteger (lowerBound)
77
+ private val cache: IdentityHashMap <Any ?, Int > = IdentityHashMap ()
78
+
79
+ override fun getOrCreateIdForValue (value : Any ): Int {
80
+ return cache.getOrPut(value) { createId() }
81
+ }
82
+
83
+ override fun createId (): Int {
84
+ return lastId.incrementAndGet()
85
+ }
86
+
87
+ companion object {
88
+ /* *
89
+ * The default lower bound (all generated integer identifiers will be greater than it).
90
+ *
91
+ * It is defined as a large value because all synthetic [UtModel] instances
92
+ * must have greater identifiers than the real models.
93
+ */
94
+ const val DEFAULT_LOWER_BOUND : Int = 1500_000_000
95
+ }
96
+ }
97
+
21
98
fun fuzz (description : FuzzedMethodDescription , vararg modelProviders : ModelProvider ): Sequence <List <FuzzedValue >> {
22
99
if (modelProviders.isEmpty()) {
23
100
throw IllegalArgumentException (" At least one model provider is required" )
@@ -42,7 +119,7 @@ fun fuzz(description: FuzzedMethodDescription, vararg modelProviders: ModelProvi
42
119
/* *
43
120
* Creates a model provider from a list of default providers.
44
121
*/
45
- fun defaultModelProviders (idGenerator : IntSupplier = SimpleIdGenerator () ): ModelProvider {
122
+ fun defaultModelProviders (idGenerator : IdentityPreservingIdGenerator < Int > ): ModelProvider {
46
123
return ModelProvider .of(
47
124
ObjectModelProvider (idGenerator),
48
125
CollectionModelProvider (idGenerator),
@@ -59,7 +136,7 @@ fun defaultModelProviders(idGenerator: IntSupplier = SimpleIdGenerator()): Model
59
136
/* *
60
137
* Creates a model provider for [ObjectModelProvider] that generates values for object constructor.
61
138
*/
62
- fun objectModelProviders (idGenerator : IntSupplier = SimpleIdGenerator () ): ModelProvider {
139
+ fun objectModelProviders (idGenerator : IdentityPreservingIdGenerator < Int > ): ModelProvider {
63
140
return ModelProvider .of(
64
141
CollectionModelProvider (idGenerator),
65
142
ArrayModelProvider (idGenerator),
@@ -71,8 +148,3 @@ fun objectModelProviders(idGenerator: IntSupplier = SimpleIdGenerator()): ModelP
71
148
PrimitiveWrapperModelProvider ,
72
149
)
73
150
}
74
-
75
- class SimpleIdGenerator : IntSupplier {
76
- private val id = AtomicInteger ()
77
- override fun getAsInt () = id.incrementAndGet()
78
- }
0 commit comments