matrixOf function
- List<
SmfModule> modules, { - Map<
String, String?> roleOptions = const {}, - EveryModuleSelection everyModuleApps = EveryModuleCombinations.all,
The apps of the matrix of modules: every app that the contract harness
builds for them, which covers every module and every provider with each
subset of the roles it uses, and the apps with every module, one for each
combination of the providers of roles that take one
(see everyModuleAppsOf).
Each app gets roleOptions, the values of role options for every app,
the options of its case, and the answers of the harness to the
questions of the roles that they leave open (see
ContractResult.answers), such as --start with the first of several
screens that can start the app: smf create then makes the same
choices without a terminal. It gets no answer to the question of a mode
option (see RoleOption.mode): the role chooses the first value of
such an option without it, in a terminal and in a run without one, as
the harness checks. So smf create generates an app with the first
value without the option, as for a user who does not give it, and an
app of another value with the option of its case. Each app gets the
choices too, with the data and roles of its case (MatrixApp.hook).
The harness renders each app in memory first, so a case that it finds
errors in is among the failed ones, since its app could not be
generated.
An app with every module that another case built already is that app,
which then has the MatrixApp.everyModuleWith of the app with every
module. The apps with every module are those of everyModuleApps, such
as a pairwise covering of them; the contract harness checks all of them
anyway, and those that fail are among the failed ones.
The last apps are the apps with every module for the other values of
the mode options of the roles (modeAppsOf), those that
everyModuleApps takes next to its apps with every module (see
EveryModuleSelection.selectModes). They come after every other app,
so that the others have the same positions, and with them the same
numbers in a run, whichever of these apps a selection takes.
Implementation
Future<({List<MatrixApp> apps, List<ContractResult> failed})> matrixOf(
List<SmfModule> modules, {
Map<String, String?> roleOptions = const {},
EveryModuleSelection everyModuleApps = EveryModuleCombinations.all,
}) async {
final harness = ContractHarness(
ModuleRegistry(modules),
roleOptions: roleOptions,
);
final apps = <MatrixApp>[];
final failed = <ContractResult>[];
for (final result in await harness.checkAll()) {
switch (_appOf(result, harness)) {
case final app?:
apps.add(app);
case null:
failed.add(result);
}
}
final everyModule = await everyModuleAppsOf(
modules,
roleOptions: roleOptions,
);
final modes = await modeAppsOf(modules, roleOptions: roleOptions);
failed
..addAll(everyModule.failed)
..addAll(modes.failed);
final selected = everyModuleApps.select(everyModule.apps, modules);
for (final app in [
...selected,
...everyModuleApps.selectModes(modes.apps, selected, modules),
]) {
final index = apps.indexWhere((other) => _keyOf(other) == _keyOf(app));
if (index < 0) {
apps.add(app);
} else {
apps[index] = apps[index]._with(everyModuleWith: app.everyModuleWith);
}
}
return (apps: apps, failed: failed);
}