appTestsReport function

Future<List<Map<String, Object>>> appTestsReport(
  1. List<MatrixAppTest> tests, {
  2. required List<SmfModule> modules,
  3. required Map<ModuleId, String> packages,
  4. required Future<List<MatrixApp>> apps(),
  5. FileSystem fileSystem = const LocalFileSystem(),
})

What the checks of the repository need to know of each of tests, as JSON, which the matrix tools print with --app-tests --json (tools/app_tests_test.dart):

  • directory, the directory of its files;
  • modules, the ids of the modules of the matrix that the package whose app_tests holds the directory declares, by packages, the package of each module of the matrix, such as smf_home_flutter for home;
  • appliesWithout, the names of the apps of the matrix that it applies to once those modules are taken out of their modules, and out of their MatrixApp.everyModuleWith, with the same name, role options and hook;
  • uses, the modules of the matrix whose ids it uses: those that, with another id in their place in an app of the matrix, change whether it applies to the app, the values of its files there or the files it generates there. Each has the id of the module (module), its package (package) and the names of those apps (apps), in the order of the apps;
  • roles, the ids of the roles whose contract it checks (MatrixAppTest.roles), such as router;
  • roleFunctionUses, the uses, in its Dart files, of the functions of the roles of modules, the modules of the matrix, that an app can have several providers of. Each has the path of the file from the directory and the function (use), such as test/a_test.dart: createCrashReporter() of lib/core/crash_reporting/crash_reporter.dart, and the id of the role of the function (role), such as crash_reporting.

The app tests that a package of modules keeps test its modules, so they apply only to the apps that have one of them, whichever other modules the matrix has: a check of the start of every app that the provider of the app entry kept would reach no app with another provider. And what they depend on of the other modules of an app comes from its roles (MatrixApp.hook), not from the ids of its modules: the screen that an app starts on is the choice of the router role, which a second feature that can start the app, or --start, changes while the app keeps the modules it had. apps gives the apps of the matrix, which it builds once, if there are tests.

An app test of a module runs in every app with its module, whatever else the app has, so it uses no function of a role that reaches every provider of the role, such as createCrashReporter(), whose reporter reports to all of them: what another provider does, only the tests of its own module know. A test of the contract of such a role calls them, since what the role does with every provider is its contract, and looks only at what reaches the providers that it knows; the checks of the repository tell it from the others by its roles and the role of each use. Such functions are the public top-level functions of the files of the interface of each role that an app can have several providers of, in the app of each of its providers that the contract harness renders first, and a use is a call or a tear-off through an import of their file as package:{{app_name}}/..., with a prefix or without. Throws a StateError if the harness renders no such app, or one without a file of the interface of the role.

Implementation

Future<List<Map<String, Object>>> appTestsReport(
  List<MatrixAppTest> tests, {
  required List<SmfModule> modules,
  required Map<ModuleId, String> packages,
  required Future<List<MatrixApp>> Function() apps,
  FileSystem fileSystem = const LocalFileSystem(),
}) async {
  final path = const LocalFileSystem().path;
  final appTests = {
    for (final package in {...packages.values})
      package: await appTestsDirectoryOf(package),
  };
  final functions = await _roleFunctionsOf(modules);
  List<MatrixApp>? all;
  final report = <Map<String, Object>>[];
  for (final test in tests) {
    final matrix = all ??= await apps();
    final ids = {
      for (final MapEntry(key: id, value: package) in packages.entries)
        if (path.isWithin(appTests[package]!, test.directory)) id,
    };
    report.add({
      'directory': test.directory,
      'modules': [for (final id in ids) id.value],
      'appliesWithout':
          ids.isEmpty ? const <String>[] : _appliesWithout(test, ids, matrix),
      'uses': [
        for (final MapEntry(key: id, value: names)
            in _usesOf(test, matrix).entries)
          {'module': id.value, 'package': packages[id]!, 'apps': names},
      ],
      'roles': [for (final role in test.roles) role.id],
      'roleFunctionUses': _roleFunctionUses(
        test.directory,
        functions,
        fileSystem,
      ),
    });
  }
  return report;
}