modeProblems method

List<String> modeProblems(
  1. List<MatrixApp> apps
)

The problems of the tests that read what says how the matrix generates an app of apps, the apps of a matrix, rather than what the app is: its name, its MatrixApp.roleOptions or its MatrixApp.modes. Each problem tells which of them a test read, what the test would do otherwise without it, and in which apps: apply to one of the two apps only, fill other values, generate other files or fail. The other app has another name, no role options or no modes, and the same modules and the same data and choices of its roles (MatrixApp.hook).

The name and the options of an app are how the matrix generates it, such as --clock-hours=12 for the app of another value of a mode option (see RoleOption.mode). What the app is, its roles chose: a role chooses the first value of a mode option for an app that gets no value of it, and an option may be given to an app whose roles do not read it. So a test takes the mode of an app from the choice of the role, with a function of the role that reads it from the input of its hooks (Role.hookInput), as it takes the route that the app starts on with routerRole.startIn(routerRole.hookInput(app.hook!)).

The rule is about where a test reads the mode, not about the apps that it runs in: a test may apply only to the apps in which a role chose one value, which it reads from the hook.

Implementation

List<String> modeProblems(List<MatrixApp> apps) {
  final problems = <String>[];
  for (final test in tests) {
    // The apps in which the test read each thing, with each effect, in
    // the order found.
    final seen = <(_CaseRead, _CaseEffect), List<String>>{};
    for (final app in apps) {
      for (final read in _readsOf(test, app)) {
        (seen[read] ??= []).add(app.name);
      }
    }
    for (final MapEntry(key: (read, effect), value: names) in seen.entries) {
      problems.add(_byCase(test, read, effect, names));
    }
  }
  return problems;
}