test sweep: icons, log.trace, DialogHost, FilesDropped getters (T-91)
Three small additions to push coverage toward the 90% target: - test/widgets/icons_test.dart: one sweep test calling .paint() on every custom ClideIconPainter (Check, ChevronRight, ChevronDown, Dot, Folder, Gear, GitBranch, Plug, Search, Terminal, Warning). - log_test: Logger.trace covered at minLevel.trace + filtered out at minLevel.info. - services_bigger_test: DialogRouter.current getter; DialogHost widget rendered with backdrop + inner builder, then dismissed through the router. Plus FilesDropped subsystem/kind getters exercised through the existing notifyDropped test. Coverage 89.08% -> 89.93%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,5 +67,18 @@ void main() {
|
|||||||
expect(a, hasLength(1));
|
expect(a, hasLength(1));
|
||||||
expect(b, hasLength(1));
|
expect(b, hasLength(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('trace records emit at minLevel.trace + are filtered above it', () {
|
||||||
|
final got = <LogRecord>[];
|
||||||
|
final log = Logger(minLevel: LogLevel.trace, sinks: [got.add]);
|
||||||
|
log.trace('s', 'low-level detail');
|
||||||
|
expect(got, hasLength(1));
|
||||||
|
expect(got.first.level, LogLevel.trace);
|
||||||
|
// Same call at info-level is filtered.
|
||||||
|
got.clear();
|
||||||
|
final filtered = Logger(minLevel: LogLevel.info, sinks: [got.add]);
|
||||||
|
filtered.trace('s', 'still detail');
|
||||||
|
expect(got, isEmpty);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,46 @@ void main() {
|
|||||||
r.dismiss(1); // close
|
r.dismiss(1); // close
|
||||||
expect(calls, 2);
|
expect(calls, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('current getter exposes the active builder while open', () {
|
||||||
|
final r = DialogRouter();
|
||||||
|
expect(r.current, isNull);
|
||||||
|
r.show<int>((ctx, _) => const SizedBox());
|
||||||
|
expect(r.current, isNotNull);
|
||||||
|
r.dismiss();
|
||||||
|
expect(r.current, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('DialogHost renders the child + the dialog over a backdrop', (tester) async {
|
||||||
|
final r = DialogRouter();
|
||||||
|
await tester.pumpWidget(Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: DialogHost(
|
||||||
|
router: r,
|
||||||
|
child: const ColoredBox(color: Color(0xFF111111), child: SizedBox.expand()),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
await tester.pump();
|
||||||
|
// No dialog open yet — backdrop + modal not present.
|
||||||
|
expect(find.byType(GestureDetector), findsNothing);
|
||||||
|
// Open one.
|
||||||
|
final future = r.show<String>((ctx, dismiss) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => dismiss('inner'),
|
||||||
|
child: const SizedBox(width: 100, height: 100),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await tester.pump();
|
||||||
|
// Backdrop + inner-wrapper + my own each add a GestureDetector.
|
||||||
|
expect(find.byType(GestureDetector), findsAtLeast(2));
|
||||||
|
// Dismiss programmatically — the future completes with null.
|
||||||
|
r.dismiss();
|
||||||
|
final result = await future;
|
||||||
|
expect(result, isNull);
|
||||||
|
// After dismiss, no GestureDetector remains.
|
||||||
|
await tester.pump();
|
||||||
|
expect(find.byType(GestureDetector), findsNothing);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('FileServices stub', () {
|
group('FileServices stub', () {
|
||||||
@@ -70,6 +110,8 @@ void main() {
|
|||||||
final e = await got.timeout(const Duration(seconds: 1));
|
final e = await got.timeout(const Duration(seconds: 1));
|
||||||
expect(e.paths, ['/a.txt', '/b.txt']);
|
expect(e.paths, ['/a.txt', '/b.txt']);
|
||||||
expect(e.slot, Slots.workspace);
|
expect(e.slot, Slots.workspace);
|
||||||
|
expect(e.subsystem, 'files');
|
||||||
|
expect(e.kind, 'dropped');
|
||||||
expect(e.payload()['slot'], Slots.workspace.value);
|
expect(e.payload()['slot'], Slots.workspace.value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/// Smoke tests for the custom paint icons under `lib/widgets/src/icons/`.
|
||||||
|
/// Each paint() call runs against a real PictureRecorder canvas to verify
|
||||||
|
/// it doesn't throw and to fill in lcov.
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:clide/widgets/src/icons/check.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/chevron.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/dot.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/folder.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/gear.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/git_branch.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/plug.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/search.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/terminal_icon.dart';
|
||||||
|
import 'package:clide/widgets/src/icons/warning.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
Canvas _canvas() => Canvas(PictureRecorder());
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const color = Color(0xFF000000);
|
||||||
|
|
||||||
|
test('every custom icon painter renders without throwing', () {
|
||||||
|
const painters = [
|
||||||
|
CheckIcon(),
|
||||||
|
ChevronRightIcon(),
|
||||||
|
ChevronDownIcon(),
|
||||||
|
DotIcon(),
|
||||||
|
FolderIcon(),
|
||||||
|
GearIcon(),
|
||||||
|
GitBranchIcon(),
|
||||||
|
PlugIcon(),
|
||||||
|
SearchIcon(),
|
||||||
|
TerminalIcon(),
|
||||||
|
WarningIcon(),
|
||||||
|
];
|
||||||
|
for (final p in painters) {
|
||||||
|
p.paint(_canvas(), color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user