matrixOf function

Future<({List<MatrixApp> apps, List<ContractResult> failed})> matrixOf(
  1. List<SmfModule> modules, {
  2. Map<String, String?> roleOptions = const {},
})

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 ContractHarness.casesOfAll).

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. 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.

Implementation

Future<({List<MatrixApp> apps, List<ContractResult> failed})> matrixOf(
  List<SmfModule> modules, {
  Map<String, String?> roleOptions = const {},
}) async {
  final harness = ContractHarness(
    ModuleRegistry(modules),
    roleOptions: roleOptions,
  );
  final results = [
    ...await harness.checkAll(),
    for (final contractCase in harness.casesOfAll())
      await harness.check(contractCase),
  ];
  final apps = <MatrixApp>[];
  final failed = <ContractResult>[];
  final keys = <String>{};
  for (final result in results) {
    final resolution = result.resolution;
    if (result.errors.isNotEmpty || resolution == null) {
      failed.add(result);
      continue;
    }
    if (!keys.add(result.appKey!)) continue;
    apps.add(
      MatrixApp(
        '${result.contractCase}',
        [for (final module in resolution.modules) module.id],
        roleOptions: {
          ...roleOptions,
          ...result.contractCase.roleOptions,
          ...result.answers,
        },
      ),
    );
  }
  return (apps: apps, failed: failed);
}