| // Copyright 2014 The Flutter Authors. 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:async'; | |
| import 'dart:io'; | |
| import 'package:logging/logging.dart'; | |
| import 'package:path/path.dart' as path; | |
| import 'package:skills_lint/skills_lint.dart'; | |
| import 'package:test/test.dart'; | |
| import 'check_backticks_relative_paths_rule.dart'; | |
| const String _configFileName = 'skills_lint.yaml'; | |
| Directory _findSkillsDir() { | |
| Directory dir = Directory.current; | |
| while (dir.path != dir.parent.path) { | |
| final skillsDir = Directory(path.join(dir.path, '.agents', 'skills')); | |
| if (skillsDir.existsSync()) { | |
| return skillsDir; | |
| } | |
| dir = dir.parent; | |
| } | |
| throw StateError( | |
| 'Could not find .agents/skills directory starting from ${Directory.current.path}', | |
| ); | |
| } | |
| void main() { | |
| final Directory skillsDir = _findSkillsDir(); | |
| final String skillsDirectory = skillsDir.path; | |
| final Directory repoRoot = skillsDir.parent.parent; | |
| final String reidbakerSkillsDirectory = path.join( | |
| repoRoot.path, | |
| '.agents', | |
| 'agents', | |
| 'reidbaker-agent', | |
| 'skills', | |
| ); | |
| late Level oldLevel; | |
| StreamSubscription<LogRecord>? subscription; | |
| setUp(() { | |
| oldLevel = Logger.root.level; | |
| Logger.root.level = Level.ALL; | |
| subscription = Logger.root.onRecord.listen((record) { | |
| print(record.message); | |
| }); | |
| }); | |
| tearDown(() async { | |
| Logger.root.level = oldLevel; | |
| await subscription?.cancel(); | |
| }); | |
| test('Validate Flutter Skills', () async { | |
| final Configuration config = await ConfigParser.loadConfig( | |
| path: path.join(repoRoot.path, 'dev', 'tools', _configFileName), | |
| ); | |
| final bool isValid = await validateSkills( | |
| skillDirPaths: [skillsDirectory, reidbakerSkillsDirectory], | |
| config: config, | |
| ); | |
| expect(isValid, isTrue, reason: 'Skills validation failed. See above for details.'); | |
| }); | |
| test('Relative to root paths are not in backticks', () async { | |
| final valid2SegmentPaths = <String>{}; | |
| final List<FileSystemEntity> entities = repoRoot.listSync(); | |
| for (final entity in entities) { | |
| if (entity is Directory) { | |
| final String dirName = path.basename(entity.path); | |
| if (dirName.startsWith('.')) { | |
| continue; | |
| } | |
| final List<FileSystemEntity> subEntities = entity.listSync(); | |
| for (final subEntity in subEntities) { | |
| if (subEntity is Directory) { | |
| final String subDirName = path.basename(subEntity.path); | |
| if (subDirName.startsWith('.')) { | |
| continue; | |
| } | |
| valid2SegmentPaths.add('$dirName/$subDirName'); | |
| } | |
| } | |
| } | |
| } | |
| final bool isValid = await validateSkills( | |
| skillDirPaths: [skillsDirectory, reidbakerSkillsDirectory], | |
| customRules: [CheckBackticksRelativePathsRule(valid2SegmentPaths, repoRoot.path)], | |
| resolvedRuleConfigs: { | |
| 'check-absolute-paths': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'check-relative-paths': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'check-trailing-whitespace': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'description-too-long': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'disallowed-field': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'invalid-skill-name': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| 'valid-yaml-metadata': const RuleConfigPatch(severity: AnalysisSeverity.disabled), | |
| }, | |
| ); | |
| expect(isValid, isTrue, reason: 'Skills validation failed. See above for details.'); | |
| }); | |
| test('CheckBackticksRelativePathsRule handles Windows paths', () async { | |
| final rule = CheckBackticksRelativePathsRule({'dev/tools'}, '/Users/reidbaker/flutter-work'); | |
| final context = SkillContext( | |
| directory: Directory('/Users/reidbaker/flutter-work/.agents/skills/test-skill'), | |
| rawContent: r'Use `dev\tools\test.dart` to test.', | |
| ); | |
| final List<ValidationError> errors = await rule.validate(context); | |
| expect(errors, hasLength(1)); | |
| expect(errors.first.message, contains('[test.dart](../../../dev/tools/test.dart)')); | |
| }); | |
| } |