import 'package:pipe/pipe.dart'; import 'package:test/test.dart'; const String fixturePath = 'test/fixtures/stuck_loading'; /// The project default is to WIRE UP: an unreachable state, handler or control is /// usually an unfinished feature, so guidance must lead with making it reachable /// and treat removal as the exception. `--policy remove` flips that for teams /// that would rather delete. void main() { late ProjectAnalysis analysis; setUpAll(() async { final project = await loadProject(fixturePath); analysis = await analyzeProject(project, concurrency: 1); }); tearDownAll(() async { await analysis.dispose(); }); FindingReport reportWith(FixPolicy policy) => runChecks(flow: analysis.flow, policy: policy); String briefWith(FixPolicy policy) => buildGuidance( root: '/root', flow: analysis.flow, report: reportWith(policy), budgetChars: 200000, maxFindings: 50, policy: policy, ).brief; test('wire-up is the default and leads the dead-handler remediation', () { final dead = reportWith( FixPolicy.wireUp, ).findings.where((finding) => finding.rule == ruleDeadHandler).toList(); expect(dead, isNotEmpty); expect(dead.first.remediation, startsWith('Wire it up')); expect(dead.first.remediation, contains('explicit approval')); }); test('the default also leads the unread-member remediation', () { final unread = reportWith(FixPolicy.wireUp).findings .where((finding) => finding.rule == ruleNotifierFieldUnread) .toList(); expect(unread, isNotEmpty); expect(unread.first.remediation, startsWith('Wire it up')); }); test('remove flips the wording', () { final dead = reportWith( FixPolicy.remove, ).findings.where((finding) => finding.rule == ruleDeadHandler).toList(); expect(dead.first.remediation, startsWith('Remove the dead handler')); final unread = reportWith(FixPolicy.remove).findings .where((finding) => finding.rule == ruleNotifierFieldUnread) .toList(); expect(unread.first.remediation, isNot(startsWith('Wire it up'))); }); test('the brief defaults to wiring up an unwired union', () { final brief = briefWith(FixPolicy.wireUp); // The fixture's ItemState is emitted but rendered nowhere, and nothing // outside the bloc references it, so the guidance must say to wire it up. expect(brief, contains('wire it up')); expect(brief, isNot(contains('safe to delete'))); }); test('the brief says removal only under the remove policy', () { final brief = briefWith(FixPolicy.remove); expect(brief, contains('safe to delete')); expect(brief, isNot(contains('wire it up'))); }); test('the dead-handler section is framed by the policy', () { expect( briefWith(FixPolicy.wireUp), contains('Unreachable handlers'), reason: 'wire-up frames dead handlers as needing a dispatching control', ); expect(briefWith(FixPolicy.remove), contains('Cleanly deletable')); }); test('the legend follows the policy too', () { // The legend's fixes were one constant map that ignored --policy, so under // wire-up it still led with "Remove the dead handler" while every finding // said removal needed explicit approval. expect(ruleFixFor(FixPolicy.wireUp)[ruleDeadHandler], startsWith('Wire')); expect( ruleFixFor(FixPolicy.wireUp)[ruleEmittedNotRendered], startsWith('Wire'), ); expect( ruleFixFor(FixPolicy.remove)[ruleDeadHandler], startsWith('Remove the dead handler'), ); expect(briefWith(FixPolicy.wireUp), isNot(contains('Fix: Remove'))); expect(ruleFixFor(FixPolicy.wireUp).keys, containsAll(allRules)); expect(ruleFixFor(FixPolicy.remove).keys, containsAll(allRules)); }); test('removal claims are scoped to the scanned directories', () { // The scan defaults to --dir lib, so "nothing outside the bloc references // it" and "safe even without product context" claimed more than was // checked: a handler dispatched only from test/ read as safe to delete. for (final policy in FixPolicy.values) { final brief = briefWith(policy); expect(brief, contains('nothing under lib'), reason: '$policy'); expect(brief, isNot(contains('without product context'))); expect(brief, isNot(contains('nothing outside the bloc'))); } final dead = reportWith( FixPolicy.remove, ).findings.firstWhere((finding) => finding.rule == ruleDeadHandler); expect(dead.remediation, contains('nothing outside lib')); }); }