import 'dart:io'; import 'package:oto/oto/commands/command.dart'; import 'package:oto/oto/commands/command_registry.dart'; import 'package:test/test.dart'; void main() { setUpAll(() { registerAllCommands(); }); test('all command types are registered', () { final registered = Command.registeredTypes.toSet(); final missing = CommandType.values.where((t) => !registered.contains(t)).toList(); expect( missing, isEmpty, reason: 'CommandType values without a Command.register() call: $missing. ' 'Add registration in the relevant register*() function and call it from registerAllCommands().', ); }); test('all registered commands expose specs', () { final specs = Command.specs; final missing = Command.registeredTypes .where((t) => !specs.containsKey(t)) .toList(); expect( missing, isEmpty, reason: 'Registered commands without a CommandSpec: $missing. ' 'Pass spec: CommandSpec(...) to Command.register().', ); }); test('spec sample paths exist when provided', () { final missing = []; for (final entry in Command.specs.entries) { final sample = entry.value.samplePath; if (sample == null) continue; if (!File(sample).existsSync()) { missing.add('${entry.key} -> $sample'); } } expect( missing, isEmpty, reason: 'CommandSpec.samplePath must point to an existing file. ' 'Missing: $missing', ); }); test('spec sample paths contain the registered command', () { final mismatches = []; for (final entry in Command.specs.entries) { final sample = entry.value.samplePath; if (sample == null) continue; final file = File(sample); if (!file.existsSync()) continue; final commandName = entry.key.name; final pattern = RegExp(r'^\s*-\s*command:\s*' + RegExp.escape(commandName) + r'\s*$'); final hasCommand = file.readAsLinesSync().any((line) { final trimmed = line.trimLeft(); if (trimmed.startsWith('#')) return false; return pattern.hasMatch(line); }); if (!hasCommand) { mismatches.add('${entry.key} -> $sample'); } } expect( mismatches, isEmpty, reason: 'CommandSpec.samplePath must reference a sample that actually ' 'includes a non-commented `- command: ` line. Mismatches: ' '$mismatches', ); }); test('spec category and dataModel are non-empty', () { final bad = []; for (final entry in Command.specs.entries) { final spec = entry.value; if (spec.category.isEmpty || spec.dataModel.isEmpty) { bad.add('${entry.key}'); } } expect(bad, isEmpty, reason: 'CommandSpec.category and dataModel must be non-empty: $bad'); }); }