Files
clide/test/builtin/output/output_controller_test.dart
T
jpmschweitzerandClaude Opus 4.8 432a5f2d5a feat(log): live verbosity toggle — dock Level chip + clide log level (T-433)
The boot-time toggle (CLIDE_LOG / app.log.level) existed; this makes it
adjustable at runtime, from the two surfaces that fit — D-6 parity — and NOT a
Claude-composer slash command (log verbosity isn't a Claude-session concept).

- Output dock Level chip: was a view-only filter; now also drives the kernel
  Logger.minLevel and persists app.log.level, so the choice is real (changes
  what's captured) and survives restart. Initialized from the logger's current
  level so it reflects a CLI change. A null callback keeps it a pure view
  filter (tests / no kernel).
- `clide log level [<level>]` (lib/src/daemon/log_commands.dart): no arg reports
  the level + vocabulary; a valid level sets the live logger and persists;
  unknown → bad_arg (code 64), logger untouched. Wired in buildDispatcher with
  the kernel logger + settings (captured post-boot).

Tested: the command (get/set/case-insensitive/bad-arg, live + persist) and the
controller (initial level, callback fires, same-level no-op, filter-only when
unwired). Coverage gate 95.05%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:32:56 +02:00

51 lines
1.8 KiB
Dart

import 'package:clide/builtin/output/src/output_controller.dart';
import 'package:clide/kernel/src/log.dart';
import 'package:clide/kernel/src/log_ring.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('OutputController Level chip (T-433)', () {
test('initialLevel sets the starting level (reflects the kernel logger)', () {
final c = OutputController(LogRing(), initialLevel: LogLevel.warn);
expect(c.minLevel, LogLevel.warn);
c.dispose();
});
test('defaults to debug when no initial level is given', () {
final c = OutputController(LogRing());
expect(c.minLevel, LogLevel.debug);
c.dispose();
});
test('setMinLevel updates the level, fires onMinLevelChanged + notifies', () {
final changes = <LogLevel>[];
var notified = 0;
final c = OutputController(LogRing(), initialLevel: LogLevel.info, onMinLevelChanged: changes.add)..addListener(() => notified++);
c.setMinLevel(LogLevel.warn);
expect(c.minLevel, LogLevel.warn);
expect(changes, [LogLevel.warn]); // the chip drove the kernel + persist hook
expect(notified, 1);
c.dispose();
});
test('setting the same level is a no-op (no kernel write, no notify)', () {
final changes = <LogLevel>[];
var notified = 0;
final c = OutputController(LogRing(), initialLevel: LogLevel.info, onMinLevelChanged: changes.add)..addListener(() => notified++);
c.setMinLevel(LogLevel.info);
expect(changes, isEmpty);
expect(notified, 0);
c.dispose();
});
test('with no callback the chip is a pure view filter (no throw)', () {
final c = OutputController(LogRing(), initialLevel: LogLevel.info);
expect(() => c.setMinLevel(LogLevel.error), returnsNormally);
expect(c.minLevel, LogLevel.error);
c.dispose();
});
});
}