import 'bloc.dart'; // --- state: one variant is declared but never emitted --------------------- abstract class GapState { const GapState(); } class GapIdle extends GapState { const GapIdle(); } /// Declared and rendered, but [GapBloc] never emits it: dead UI. class GapGhost extends GapState { const GapGhost(); } // --- events: one unhandled, one never dispatched ------------------------- abstract class HandlerGapEvent { const HandlerGapEvent(); } /// Dispatched, but no `on` exists: the tap does nothing. class UnhandledTap extends HandlerGapEvent { const UnhandledTap(); } /// Handled, but nothing ever dispatches it: dead handler. class NeverDispatched extends HandlerGapEvent { const NeverDispatched(); } /// Handled AND dispatched: the negative control for both event rules. Without a /// case like this, asserting "HandledTap is never reported as unhandled" proves /// nothing, because an event that is never handled could never be reported. class HandledTap extends HandlerGapEvent { const HandledTap(); } // --- a variant name shared with another union --------------------------- // // UI matching is by UNQUALIFIED name, so a project-wide mention set would // cross-credit: matching DuplicatedName for AlphaState would silently mark // BetaState's identically named variant as rendered too. This pair is the // regression guard for scoping mentions per union. class AlphaEvent {} sealed class AlphaState { const AlphaState(); } class DuplicatedName extends AlphaState { const DuplicatedName(); } class AlphaBloc extends Bloc { AlphaBloc() : super(const DuplicatedName()); void go() => emit(const DuplicatedName()); } class GapBloc extends Bloc { GapBloc() : super(const GapIdle()); void register() { on((event, emit) => emit(const GapIdle())); on((event, emit) => emit(const GapIdle())); } void tap() { // No on is registered anywhere. add(const UnhandledTap()); } void tapHandled() { add(const HandledTap()); } }