dart_arch_test 0.3.1
dart_arch_test: ^0.3.1 copied to clipboard
ArchUnit-inspired architecture testing for Dart & Flutter. Enforce layer boundaries, slice isolation, cycles, coupling metrics, and violation baselines — all in plain Dart tests.
Changelog #
0.3.1 #
Bug fixes / performance:
- Cycle detection performance —
Collector.cyclesnow uses adoneset (DFS memoisation) to avoid re-exploring already-completed subtrees, reducing worst-case complexity from O(n!) to O(n + e). _globMatchrefactor —assertions.dartnow delegates to the sharedmatchesGlobhelper inpattern.dart, removing duplicated glob logic.
0.3.0 #
New features:
-
Variadic
union()— now accepts 2–5 selectors instead of exactly 2, eliminating the need for deep nesting:// Before (0.2.x) union(a, union(b, union(c, d))) // Now union(a, b, c, d) -
difference(a, b)— new top-level set operation returning libraries inabut not inb:// All feature files except generated code difference(filesMatching('features/**'), filesMatching('features/**/*.g.dart')) -
except:parameter on all assertion functions — exclude a subset of subjects from a rule without splitting it into two tests:shouldNotDependOn( filesMatching('shared/**'), filesMatching('features/**'), graph, except: filesMatching('shared/guards/**'), // guards are a bridge by design ); shouldNotTransitivelyDependOn(subject, object, graph, except: filesMatching('...')); shouldOnlyDependOn(subject, allowed, graph, except: filesMatching('...')); shouldNotBeCalledBy(object, callers, graph, except: filesMatching('...')); shouldOnlyBeCalledBy(object, allowed, graph, except: filesMatching('...')); -
Content-based selectors (
extending,implementing,withAnnotation) — select libraries by what their classes declare, not just by file path:// Every ChangeNotifier subclass must live in a providers/ folder shouldHaveUriMatching(extending('ChangeNotifier'), '**/providers/**', graph); // UnreadCountSource implementations must stay in shared/ shouldNotDependOn(implementing('UnreadCountSource'), filesMatching('features/**'), graph); // @immutable models must not import services shouldNotTransitivelyDependOn(withAnnotation('immutable'), filesMatching('**/services/**'), graph);Root path is inferred from the nearest
pubspec.yamlwalking up from CWD, or overridden via theDART_ARCH_TEST_ROOTenvironment variable.
Exports: difference, extending, implementing, withAnnotation are now exported from package:dart_arch_test/dart_arch_test.dart.
0.2.2 #
Bug fix:
- Fixed
Collector.buildGraphcrashing underflutter testwithPathNotFoundExceptiononartifacts/engine/versionandlib/_internal/libraries.dart. Underflutter test,Platform.resolvedExecutableisflutter_tester(notdart), so theanalyzerpackage'sgetSdkPath()resolved to the wrong directory.Collectornow walks up the directory tree to find the real Dart SDK (bin/cache/dart-sdk/) before falling back to the previous behaviour.
0.2.1 #
Bug fix:
Collector.buildGraphnow compiles against analyzer ≥9.0.0: switched fromresult.element2(experimental in 7.x, removed in 9.x) toresult.element(deprecated in 7.x, stable in 9.x). The// ignore: deprecated_member_usesuppression keeps the code clean on both analyzer ranges.
0.2.0 #
New features:
-
Metrics— Robert C. Martin coupling metrics from the import graph:Metrics.coupling(uri, graph)— afferent coupling (Ca), efferent coupling (Ce), instability, abstractness, distance for a single libraryMetrics.instability(uri, graph)— convenience shorthand forCe / (Ca + Ce)Metrics.martin(pattern, graph)— bulk report for all libraries matching a glob patternCouplingMetrics— immutable data class holding all five metric fields
-
Freeze— violation baseline / snapshot support:freeze(ruleId, () { ... })— top-level convenience function; passes if violations match the baseline, fails withFreezeFailureon new violationsFreeze.freeze(ruleId, assertion, {storeDir})— class-based API with optional custom store directoryFreeze.updateFreeze()— returnstruewhenDART_ARCH_TEST_UPDATE_FREEZE=1is setFreeze.storePath()— returns the baseline directory (envDART_ARCH_TEST_FREEZE_STOREortest/arch_test_violations/)FreezeFailure— exception type thrown when new violations are detected
-
Slicesadditions:allLibrariesCoveredBy(scope, graph, {except})— asserts every library inscopebelongs to at least one declared slice;exceptaccepts glob patterns to skipsliceCycles(graph)— returns all dependency cycles at the slice levelshouldBeFreeOfSliceCycles(graph)— throwsArchTestFailureif any slice-level cycle exists
Exports: CouplingMetrics, Metrics, Freeze, FreezeFailure, freeze are now exported from package:dart_arch_test/dart_arch_test.dart.
0.1.0 #
Initial release.
Core features:
Collector.buildGraph— builds an import-graph from Dart source using theanalyzerpackage; cached after first callfilesMatching(pattern)/allFiles()— glob selectors for library URIsshouldNotDependOn/shouldOnlyDependOn— direct import rulesshouldNotTransitivelyDependOn— transitive import rulesshouldNotBeCalledBy/shouldOnlyBeCalledBy— caller-side rulesshouldNotExist— forbid libraries matching a patternshouldBeFreeOfCycles— DFS-based cycle detectionshouldHaveUriMatching— URI naming conventionsdefineLayers+enforceDirection— layered architecturedefineOnion+enforceOnionRules— onion/hexagonal architecturedefineSlices+allowDependency+enforceIsolation+shouldNotDependOnEachOther— bounded-context / modulith isolationArchTestFailure— collects all violations before throwing