| // Copyright (c) 2019, 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 'package:analysis_server/src/services/correction/sort_members.dart'; |
| import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; |
| import 'package:analyzer/dart/analysis/results.dart'; |
| import 'package:analyzer/dart/analysis/session.dart'; |
| import 'package:analyzer/file_system/file_system.dart'; |
| import 'package:analyzer/file_system/physical_file_system.dart'; |
| import 'package:analyzer_testing/package_root.dart'; |
| import 'package:test/test.dart'; |
| |
| /// The purpose of this test is to validate that all elements |
| /// (classes, enums, etc, methods, functions, fields, operators, etc.) are |
| /// sorted alphabetically by name (either manually or via an IDE, e.g. |
| /// VS Code 'Dart: Sort Members' command or IntelliJ 'Sort Members' |
| /// context menu.) |
| /// Pass `--update` as argument to this script to have the sorted files |
| /// written back. |
| void main([List<String> args = const <String>[]]) { |
| if (args.contains('--update')) { |
| updateUnsorted = true; |
| } |
| |
| group('analysis_server', () { |
| buildTestsForAnalysisServer(); |
| }); |
| |
| group('analyzer', () { |
| buildTestsForAnalyzer(); |
| }); |
| |
| group('analyzer_cli', () { |
| buildTestsForAnalyzerCli(); |
| }); |
| |
| group('analyzer_plugin', () { |
| buildTestsForAnalyzerPlugin(); |
| }); |
| |
| group('linter', () { |
| buildTestsForLinter(); |
| }); |
| } |
| |
| bool updateUnsorted = false; |
| |
| void buildTests({ |
| required String packagePath, |
| required List<String> excludedPaths, |
| }) { |
| var provider = PhysicalResourceProvider.INSTANCE; |
| var pkgRootPath = provider.pathContext.normalize(packageRoot); |
| |
| packagePath = _toPlatformPath(pkgRootPath, packagePath); |
| excludedPaths = |
| excludedPaths.map((e) { |
| return _toPlatformPath(packagePath, e); |
| }).toList(); |
| |
| var collection = AnalysisContextCollection( |
| includedPaths: <String>[packagePath], |
| excludedPaths: excludedPaths, |
| resourceProvider: provider, |
| ); |
| for (var context in collection.contexts) { |
| buildTestsIn( |
| context.currentSession, |
| packagePath, |
| excludedPaths, |
| provider.getFolder(packagePath), |
| ); |
| } |
| } |
| |
| void buildTestsForAnalysisServer() { |
| var excludedPaths = <String>[ |
| // TODO(brianwilkerson): Fix the generator to sort the generated files and |
| // remove these exclusions. |
| 'lib/protocol/protocol_constants.dart', |
| 'lib/protocol/protocol_generated.dart', |
| 'integration_test/support/integration_test_methods.dart', |
| 'integration_test/support/protocol_matchers.dart', |
| // The following are not generated, but can't be sorted because they contain |
| // ignore comments in the directives, which sorting deletes. |
| 'lib/src/services/kythe/schema.dart', |
| ]; |
| |
| buildTests(packagePath: 'analysis_server', excludedPaths: excludedPaths); |
| } |
| |
| void buildTestsForAnalyzer() { |
| buildTests( |
| packagePath: 'analyzer', |
| excludedPaths: [ |
| 'lib/src/context/packages.dart', |
| 'lib/src/summary/format.dart', |
| 'lib/src/wolf/ir/ir.g.dart', |
| 'test/generated/test_all.dart', |
| ], |
| ); |
| } |
| |
| void buildTestsForAnalyzerCli() { |
| buildTests(packagePath: 'analyzer_cli', excludedPaths: ['test/data']); |
| } |
| |
| void buildTestsForAnalyzerPlugin() { |
| // TODO(brianwilkerson): Fix the generator to sort the generated files and |
| // remove these exclusions. |
| var excludedPaths = <String>[ |
| 'lib/protocol/protocol_common.dart', |
| 'lib/protocol/protocol_generated.dart', |
| 'test/integration/support/integration_test_methods.dart', |
| 'test/integration/support/protocol_matchers.dart', |
| ]; |
| |
| buildTests(packagePath: 'analyzer_plugin', excludedPaths: excludedPaths); |
| } |
| |
| void buildTestsForLinter() { |
| buildTests(packagePath: 'linter', excludedPaths: ['test_data']); |
| } |
| |
| void buildTestsIn( |
| AnalysisSession session, |
| String testDirPath, |
| List<String> excludedPath, |
| Folder directory, |
| ) { |
| var pathContext = session.resourceProvider.pathContext; |
| var children = directory.getChildren(); |
| children.sort((first, second) => first.shortName.compareTo(second.shortName)); |
| for (var child in children) { |
| if (child is Folder) { |
| if (!excludedPath.contains(child.path)) { |
| buildTestsIn(session, testDirPath, excludedPath, child); |
| } |
| } else if (child is File && child.shortName.endsWith('.dart')) { |
| var path = child.path; |
| if (excludedPath.contains(path)) { |
| continue; |
| } |
| var relativePath = pathContext.relative(path, from: testDirPath); |
| test(relativePath, () { |
| var result = session.getParsedUnit(path); |
| if (result is! ParsedUnitResult) { |
| fail('Could not parse $path'); |
| } |
| var code = result.content; |
| var unit = result.unit; |
| var diagnostics = result.diagnostics; |
| if (diagnostics.isNotEmpty) { |
| fail('Diagnostics found when parsing $path'); |
| } |
| var sorter = MemberSorter( |
| code, |
| unit, |
| result.analysisOptions.codeStyleOptions, |
| result.lineInfo, |
| ); |
| var edits = sorter.sort(); |
| if (edits.isNotEmpty) { |
| if (updateUnsorted) { |
| var newCode = code; |
| for (var edit in edits) { |
| newCode = edit.apply(newCode); |
| } |
| child.writeAsStringSync(newCode); |
| } else { |
| fail('Unsorted file $path'); |
| } |
| } |
| }); |
| } |
| } |
| } |
| |
| String _toPlatformPath(String pathPath, String relativePosixPath) { |
| var pathContext = PhysicalResourceProvider.INSTANCE.pathContext; |
| return pathContext.joinAll([pathPath, ...relativePosixPath.split('/')]); |
| } |