pipe/test/fixtures/stuck_loading/lib/item_bloc.dart
trvon 3c91db2946
Some checks failed
Tests / Static Analysis (push) Has been cancelled
Tests / Tests (push) Has been cancelled
fix: act on the external audit - 5 defects, 5 vacuous tests, a real fixture exclusion bug
An independent Gemini 3.8 Flash audit of this repo found real problems. Each was
reproduced before being fixed.

Confirmed defects:
- tool/adjudicate.py crashed with KeyError once R001 started grouping variants
  under 'variants' instead of 'variant'. Fixing that exposed a second bug of my
  own: it then divided verified VARIANTS by FINDINGS and reported 216% precision.
  Counts are now coherent (findings vs variant-level checks) and a clean repo
  reports 0/0 rather than a fake 100%.
- GuideCommand called _readPolicy but never registered --policy, so
   exited 64 despite the README documenting it.
- loading-flag-not-reset treated a constructor-invoked method as inheriting the
  loading flag without checking flag.defaultsTrue, so a default-FALSE flag was
  reported as in flight.
- Finding.fingerprint embedded the line number for rules whose only identity was
  , so moving code broke baseline entries.  is now a
  discriminating key; only loading-not-reset, which can emit two findings from one
  method, carries an explicit catchLine.
- suggest grouped unrelated provider-read-in-build findings by file; the group key,
  label and target list now use valueType/call.

Recall defect found while checking the auditor's own claim: UI variant mentions
were collected project-wide by unqualified name, so ExportSuccess - which appears
in FOUR unions on nuwayze - was cross-credited. Mentions are now scoped per union
to files that also name the state type or its owner, which surfaced
ArtistStoreManagementState[ExportSuccess] as a real finding.

Five negative controls could not fail (an event that is never handled can never be
reported as unhandled; a union with no render sites can never be reported as
rendered-not-emitted). Added fixture cases that make each one bite: HandledTap
(handled AND dispatched), PatternState render sites, GuardedCubit (guarded loading
path), QuietCubit._warmUp (constructor-invoked await on a default-false flag).

Root cause of a recurring mystery: this repo EXCLUDED test/fixtures/** from
analysis, which made any analyzer running in the repo context parse the fixture
without resolving its imports and report phantom undefined-class errors. I had
dismissed these as stale cache several times; they were my own exclusion. The
exclude is gone and the fixture governs itself. A new test asserts the fixture has
zero analyzer errors, not merely that it resolves, so IR distortion cannot hide.

84 tests (was 81).
2026-09-20 20:45:58 -06:00

79 lines
2.1 KiB
Dart

import 'dart:async';
import 'bloc.dart';
// --- state union ---------------------------------------------------------
abstract class ItemState {}
class ItemLoading extends ItemState {}
class ItemLoaded extends ItemState {}
class ItemError extends ItemState {}
// --- events --------------------------------------------------------------
abstract class ItemEvent {}
class LoadItems extends ItemEvent {}
class LoadItemsSafely extends ItemEvent {}
// --- bloc ----------------------------------------------------------------
class ItemBloc extends Bloc<ItemEvent, ItemState> {
ItemBloc() : super(ItemLoaded());
/// Two swallowed catches in ONE method: the loading state is in flight and
/// neither catch resolves it. They must be two distinct findings, which is why
/// this rule's identity carries the catch position.
Future<void> twoSwallowedAwaits() async {
emit(ItemLoading());
try {
await Future<void>.delayed(Duration.zero);
} catch (error) {
// swallowed
}
try {
await Future<void>.delayed(Duration.zero);
} catch (error) {
// swallowed too
}
}
void register() {
// BAD: a loading state is emitted, the awaited call fails, and the catch
// neither emits a terminal state nor rethrows, so the spinner sticks.
on<LoadItems>((event, emit) async {
emit(ItemLoading());
try {
await Future<void>.delayed(Duration.zero);
emit(ItemLoaded());
} catch (error) {
// swallowed on purpose: this is the bug pipe must find.
}
});
// GOOD: the catch resolves the loading state.
on<LoadItemsSafely>((event, emit) async {
emit(ItemLoading());
try {
await Future<void>.delayed(Duration.zero);
emit(ItemLoaded());
} catch (error) {
emit(ItemError());
}
});
// GOOD: deliberate graceful degradation that leaves no loading state
// outstanding and does not concern the user.
on<LoadItemsSafely>((event, emit) async {
try {
await Future<void>.delayed(Duration.zero);
} catch (_) {
// best-effort call; nothing was in flight for the user.
}
});
}
}