in src/jvm/main/org/jetbrains/kotlinx/lincheck/CTestStructure.java [110:194]
private static void readTestStructureFromClass(
Class<?> clazz,
Map<String, OperationGroup> groupConfigs,
List<ActorGenerator> actorGenerators,
Map<Class<?>, ParameterGenerator<?>> parameterGeneratorsMap,
List<Actor> validationFunctions,
List<Method> stateRepresentations,
RandomProvider randomProvider
) {
// Read named parameter generators (declared for class)
Map<String, ParameterGenerator<?>> namedGens = createNamedGens(clazz, randomProvider);
// Create map for default (not named) gens
Map<Class<?>, ParameterGenerator<?>> defaultGens = createDefaultGenerators(randomProvider);
// Read group configurations
for (org.jetbrains.kotlinx.lincheck.annotations.OpGroupConfig opGroupConfigAnn :
clazz.getAnnotationsByType(org.jetbrains.kotlinx.lincheck.annotations.OpGroupConfig.class))
{
groupConfigs.put(
opGroupConfigAnn.name(),
new OperationGroup(opGroupConfigAnn.name(), opGroupConfigAnn.nonParallel())
);
}
// Process class methods
for (Method m : getDeclaredMethodSorted(clazz)) {
// Operation
OperationConfig opConfig = parseOperationAnnotation(m);
if (opConfig != null) {
boolean isSuspendableMethod = isSuspendable(m);
// Check that params() in @Operation is empty or has the same size as the method
if (opConfig.getParams().length > 0 && opConfig.getParams().length != m.getParameterCount()) {
throw new IllegalArgumentException("Invalid count of parameter generators for " + m);
}
// Construct a list of parameter generators
final List<ParameterGenerator<?>> gens = new ArrayList<>();
int nParameters = m.getParameterCount() - (isSuspendableMethod ? 1 : 0);
for (int i = 0; i < nParameters; i++) {
String nameInOperation = opConfig.getParams().length > 0 ? opConfig.getParams()[i] : null;
Parameter parameter = m.getParameters()[i];
ParameterGenerator<?> parameterGenerator = getOrCreateGenerator(m,
parameter,
nameInOperation,
namedGens,
defaultGens,
randomProvider
);
parameterGeneratorsMap.putIfAbsent(parameter.getType(), parameterGenerator);
gens.add(parameterGenerator);
}
ActorGenerator actorGenerator = new ActorGenerator(m, gens, opConfig.isRunOnce(),
opConfig.isCancellableOnSuspension(), opConfig.isBlocking(), opConfig.isCausesBlocking(),
opConfig.isPromptCancellation());
actorGenerators.add(actorGenerator);
// Get list of groups and add this operation to specified ones
String opGroup = opConfig.getGroup();
if (!opGroup.isEmpty()) {
OperationGroup operationGroup = groupConfigs.get(opGroup);
if (operationGroup == null)
throw new IllegalStateException("Operation group " + opGroup + " is not configured");
operationGroup.actors.add(actorGenerator);
}
String opNonParallelGroupName = opConfig.getNonParallelGroup();
if (!opNonParallelGroupName.isEmpty()) { // is `nonParallelGroup` specified?
groupConfigs.computeIfAbsent(opNonParallelGroupName, name -> new OperationGroup(name, true));
groupConfigs.get(opNonParallelGroupName).actors.add(actorGenerator);
}
}
ValidateConfig validateConfig = parseValidateAnnotation(m);
if (validateConfig != null) {
if (m.getParameterCount() != 0)
throw new IllegalStateException("Validation function " + m.getName() + " should not have parameters");
validationFunctions.add(new Actor(m, Collections.emptyList()));
}
StateRepresentationConfig stateRepConfig = parseStateRepresentationAnnotation(m);
if (stateRepConfig != null) {
if (m.getParameterCount() != 0)
throw new IllegalStateException("State representation function " + m.getName() + " should not have parameters");
if (m.getReturnType() != String.class)
throw new IllegalStateException("State representation function " + m.getName() + " should have String return type");
stateRepresentations.add(m);
}
}
}