plugins library
What a flutter3d plugin has to do, as checks it runs against itself.
The other half of this package. flutter3d_conformance.dart holds a
backend to what flutter3d_hardware cannot say in a signature; this holds
a plugin to what flutter3d_plugin_api cannot: that it says what it is,
that switching it off takes back everything it added, that a step it runs
gives one answer, that it runs where it says it runs, and that it costs
what it says it costs, and that a substance it brings is one the engine
can trust. Decision 20 of tasks/0.9-plugins.md.
import 'package:flutter3d_conformance/plugins.dart';
void main() => runPluginConformance(
WindPlugin.new,
harness: PluginHarness(
setUp: (loop) => loop
..snapshots.add(world.snapshotPart)
..addSystem('world', LoopPhase.physics, world.step),
),
);
The 8 plugin checks
- plugin.manifest — the id is well formed, the plugin API version installs on this engine, every permission is one the engine knows, a budget reads, the manifest is the same written out and read back, and the plugin installs: a view plugin that adds a step system is refused here, with the loop's own sentence.
- plugin.switch — switched off at a step boundary, the loop's phases, systems, declared events, fields and subsystems are exactly those of a loop without it; switched back on, exactly those with it; both journalled at the step they were made.
- plugin.names — every phase, system, event, field and subsystem it adds to
the loop is in its namespace,
<namespace>.<name>; the engine's own packages are not held to one. - plugin.determinism — every step run twice from one state by the loop's
DeterminismCheck, which names the system that diverged; and two fresh runs publish the same events and leave the same world, step by step. - plugin.backends — installed and stepped on every backend the manifest names (on none and all four when it names none), and switched off with a reason on one it does not.
- plugin.budget — no step publishes more events than the manifest's budget
allows, and the median cost of a step with the plugin, less without it,
is within its
stepMicroseconds. - plugin.materials — every physical material it adds to the engine's
MaterialCatalogis under its own id, names a source for each group, says a liquid's or a gas's density and viscosity and keeps every number in SI within what anything real has (PhysicalMaterial.problems); every pair it measures has one of its own in it and a source; and all of it is gone when it is switched off. A plugin that brings none passes. - plugin.render — installed on the software backend with the
harness's registries, whether the plugin places nodes in the frame:
one that does names
render.nodesin its outcome'srequires, and the render suite's checks oncpuare then part of its badge.
The badge
flutter3d conformant@1.0: checkPluginConformance passes every check
of suite 1.0 on every declared backend, with a world given to determinism
and a budget declared and kept, on the plugin API version in its
manifest. earnsBadge answers it and badgeFor names it. A declined
check — no world, no budget, assertions off — is never green and keeps
the badge away, because a check that was not asked has not been passed.
Render conformance counts for a plugin that draws. A plugin that
places nodes in the frame (plugin.render) earns the badge only with the
render checks it requires passed on the software backend, cpu
(runPluginRenderConformance of flutter3d_conformance_render), and a
plugin of any kind keeps it only while no render check it ran failed on
any backend. The two suites write one report: each keeps the other's
outcomes in <package>.conformance.json and replaces its own, so the
badge in it is judged on both, whichever ran last.
The badge names the suite it was earned against. A check added later
joins a new suite version, never an old one, so a plugin that earned
conformant@1.0 keeps it when this package grows; it earns
conformant@1.1 by passing the larger suite.

Classes
- PluginBudget
-
What a plugin promises to cost, read from its manifest's
budget. - PluginCheckOutcome
- What one check found, on one backend where the check is per backend.
- PluginHarness
- What a plugin's conformance run is given besides the plugin: the world it acts on, the registries it asks for, and the application around it.
Constants
- conformanceReportFormat → const FormatSpec
- The conformance report's format: what conformanceReport writes and a catalogue or a CI job reads.
-
conformanceSuites
→ const Map<
String, List< String> > - Every suite version, with the checks it is made of.
- conformanceSuiteVersion → const String
- The suite this package's checks make up: the version a badge earned with them names.
-
pluginCheckNames
→ const List<
String> - The checks' names, in the order they are reported.
- renderBadgeBackend → const String
- The backend a render check a badge requires is passed on: the software rasteriser, which every machine has and CI runs on every change.
Functions
-
badgeFor(
List< PluginCheckOutcome> outcomes) → String? -
The badge
outcomesearn, as it is written —conformant@1.0— for the newest suite they pass; null when they pass none. -
checkPluginConformance(
Flutter3dPlugin create(), {PluginHarness harness = const PluginHarness()}) → List< PluginCheckOutcome> -
Runs every plugin check against the plugin
createmakes, and returns what each found — one outcome per check, and one per backend for the backends check. -
conformanceReport(
String plugin, List< PluginCheckOutcome> outcomes) → Map<String, Object?> -
outcomesas a JSON document in the format envelope: the suite, the badge, and each outcome. -
earnsBadge(
List< PluginCheckOutcome> outcomes, {String suite = conformanceSuiteVersion}) → bool -
Whether
outcomesearn the badge ofsuite: every check of that suite ran, every one passed and none declined; every check an outcome PluginCheckOutcome.requires — the render checks of a plugin that draws — passed on the software backend,cpu, and was not declined there; and no render check failed on any backend. -
mergedOutcomes(
String plugin, List< PluginCheckOutcome> ran, {required bool isOurs(PluginCheckOutcome outcome)}) → List<PluginCheckOutcome> -
ranin place of the outcomes ofisOursin the report already in the package, if there is one: what a suite writes, so the plugin suite and the render suite, each in a test file of its own, leave one report holding both, judged by earnsBadge on both. -
recordRenderOutcomes(
String plugin, List< PluginCheckOutcome> ran) → void -
Writes
ran, the render checks' outcomes ofpluginon the backends they ran on, into the package's<package>.conformance.json, beside the plugin suite's and replacing the render outcomes of those backends, with the badge judged again on all of them. WhatrunPluginRenderConformancecalls once its checks are done. -
runPluginConformance(
Flutter3dPlugin create(), {PluginHarness harness = const PluginHarness()}) → void - Registers the plugin checks as tests: one per check, and one per backend for the backends check, named "plugin.backends on webgl".