diff --git a/tool/dart_hooks/lib/src/dart_analyze_hook.dart b/tool/dart_hooks/lib/src/dart_analyze_hook.dart index 4a587a2..e2449f9 100644 --- a/tool/dart_hooks/lib/src/dart_analyze_hook.dart +++ b/tool/dart_hooks/lib/src/dart_analyze_hook.dart @@ -27,8 +27,11 @@ class DartAnalyzeHook extends BaseHook { @override String get hookName => 'dart analyze'; + /// The key in `dart_hooks.yaml` that enables this hook. + static const String configKeyName = 'DartAnalyzeHook'; + @override - String get configKey => 'DartAnalyzeHook'; + String get configKey => configKeyName; @override Future executeCommand(List files) { diff --git a/tool/dart_hooks/lib/src/dart_format_hook.dart b/tool/dart_hooks/lib/src/dart_format_hook.dart index 45e402c..68e48e5 100644 --- a/tool/dart_hooks/lib/src/dart_format_hook.dart +++ b/tool/dart_hooks/lib/src/dart_format_hook.dart @@ -27,8 +27,11 @@ class DartFormatHook extends BaseHook { @override String get hookName => 'dart format'; + /// The key in `dart_hooks.yaml` that enables this hook. + static const String configKeyName = 'DartFormatHook'; + @override - String get configKey => 'DartFormatHook'; + String get configKey => configKeyName; @override Future executeCommand(List files) { diff --git a/tool/dart_hooks/test/example_config_test.dart b/tool/dart_hooks/test/example_config_test.dart new file mode 100644 index 0000000..c1d8b75 --- /dev/null +++ b/tool/dart_hooks/test/example_config_test.dart @@ -0,0 +1,70 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:io'; +import 'package:dart_hooks/src/dart_analyze_hook.dart'; +import 'package:dart_hooks/src/dart_format_hook.dart'; +import 'package:path/path.dart' as path; +import 'package:test/test.dart'; +import 'package:yaml/yaml.dart'; + +/// Verifies that the `dart_hooks.yaml` files committed to the repository +/// actually enable the hooks. The committed files are the examples users copy, +/// and a key that does not match a hook's `configKey` leaves that hook silently +/// disabled (see https://github.com/flutter/skills/issues/150). +/// +/// This mirrors the enablement gate in `BaseHook.run()` +/// (`yaml.containsKey(configKey)` && `yaml[configKey] == true`) and reads the +/// keys from the same `configKeyName` constants the hooks use, so the shipped +/// files, the code, and this test cannot drift apart. +void main() { + group('Shipped dart_hooks.yaml examples', () { + // `dart test` runs with the package root as the current directory. The + // committed example files live there and at the surrounding monorepo + // locations. + final String packageRoot = Directory.current.path; + final candidatePaths = [ + path.join(packageRoot, 'dart_hooks.yaml'), + path.join(packageRoot, '..', 'dart_hooks.yaml'), + path.join(packageRoot, '..', '..', 'dart_hooks.yaml'), + path.join(packageRoot, '..', 'dart_skills_lint', 'dart_hooks.yaml'), + ]; + + final List existingPaths = candidatePaths.where((p) => File(p).existsSync()).toList(); + + test('at least one shipped example was found to verify', () { + // Guards against a wrong working directory silently passing the suite. + expect( + existingPaths, + isNotEmpty, + reason: + 'No committed dart_hooks.yaml files were found relative to ' + '$packageRoot. Checked: $candidatePaths', + ); + }); + + for (final filePath in existingPaths) { + test('$filePath enables both hooks', () { + final dynamic yaml = loadYaml(File(filePath).readAsStringSync()); + expect(yaml, isA>(), reason: '$filePath is not a YAML map.'); + final yamlMap = yaml as Map; + + expect( + yamlMap[DartFormatHook.configKeyName], + isTrue, + reason: + '$filePath must enable the format hook with ' + '"${DartFormatHook.configKeyName}: true".', + ); + expect( + yamlMap[DartAnalyzeHook.configKeyName], + isTrue, + reason: + '$filePath must enable the analyze hook with ' + '"${DartAnalyzeHook.configKeyName}: true".', + ); + }); + } + }); +} diff --git a/tool/dart_hooks/test/test_utils.dart b/tool/dart_hooks/test/test_utils.dart index 70f1f6f..7924163 100644 --- a/tool/dart_hooks/test/test_utils.dart +++ b/tool/dart_hooks/test/test_utils.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:io'; +import 'package:dart_hooks/src/dart_analyze_hook.dart'; +import 'package:dart_hooks/src/dart_format_hook.dart'; import 'package:dart_hooks/src/process_runner.dart'; /// A mock implementation of [ProcessRunner] that delegates to a function. @@ -31,7 +33,7 @@ class MockProcessRunner implements ProcessRunner { } /// Returns a YAML configuration string enabling or disabling the analyze hook. -String mockAnalyzeConfig(bool enabled) => 'DartAnalyzeHook: $enabled\n'; +String mockAnalyzeConfig(bool enabled) => '${DartAnalyzeHook.configKeyName}: $enabled\n'; /// Returns a YAML configuration string enabling or disabling the format hook. -String mockFormatConfig(bool enabled) => 'DartFormatHook: $enabled\n'; +String mockFormatConfig(bool enabled) => '${DartFormatHook.configKeyName}: $enabled\n';