blob: 1c0de2ad98c5953ec00cf11af7da9c6ffbfea052 [file] [log] [blame] [edit]
// Copyright (c) 2024, 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:dart_style/src/analysis_options/analysis_options_file.dart';
import 'package:dart_style/src/testing/test_file_system.dart';
import 'package:test/test.dart';
import '../utils.dart';
void main() {
group('findAnalysisOptions()', () {
test('returns an empty map if no analysis options is found', () async {
var testFS = TestFileSystem();
var options = await findAnalysisOptions(
testFS,
TestFileSystemPath('dir|sub'),
);
expect(options, isEmpty);
});
test('finds a file in the given directory', () async {
var testFS = TestFileSystem({
'dir|analysis_options.yaml': analysisOptions(pageWidth: 100),
});
var options = await findAnalysisOptions(
testFS,
TestFileSystemPath('dir'),
);
expect(_pageWidth(options), equals(100));
});
test('stops at the nearest analysis options file', () async {
var testFS = TestFileSystem({
'dir|analysis_options.yaml': analysisOptions(pageWidth: 120),
'dir|sub|analysis_options.yaml': analysisOptions(pageWidth: 100),
});
var options = await findAnalysisOptions(
testFS,
TestFileSystemPath('dir|sub'),
);
expect(_pageWidth(options), equals(100));
});
test('uses the nearest file even if it doesn\'t have the '
'setting', () async {
var testFS = TestFileSystem({
'dir|analysis_options.yaml': analysisOptions(pageWidth: 120),
'dir|sub|analysis_options.yaml': analysisOptions(
other: {'other': 'stuff'},
),
});
var options = await findAnalysisOptions(
testFS,
TestFileSystemPath('dir|sub'),
);
expect(_pageWidth(options), isNull);
});
});
group('readAnalysisOptionsOptions()', () {
test('reads an analysis options file', () async {
var testFS = TestFileSystem({
'file.yaml': analysisOptions(pageWidth: 120),
});
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('file.yaml'),
);
expect(_pageWidth(options), 120);
});
test('yields an empty map if the file isn\'t a YAML map', () async {
var testFS = TestFileSystem({'file.yaml': '123'});
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('file.yaml'),
);
expect(options, isA<Map>());
expect(options, isEmpty);
});
test('merges included files', () async {
var testFS = TestFileSystem({
'dir|a.yaml': analysisOptions(
include: 'b.yaml',
other: {
'a': 'from a',
'ab': 'from a',
'ac': 'from a',
'abc': 'from a',
'ad': 'from a',
},
),
'dir|b.yaml': analysisOptions(
include: ['c.yaml', 'd.yaml'],
other: {
'ab': 'from b',
'abc': 'from b',
'b': 'from b',
'bc': 'from b',
'bd': 'from b',
},
),
'dir|c.yaml': analysisOptions(
other: {
'ac': 'from c',
'abc': 'from c',
'bc': 'from c',
'c': 'from c',
'cd': 'from c',
},
),
'dir|d.yaml': analysisOptions(
other: {'ad': 'from d', 'bd': 'from d', 'cd': 'from d'},
),
});
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('dir|a.yaml'),
);
expect(options['a'], 'from a');
expect(options['ab'], 'from a');
expect(options['ac'], 'from a');
expect(options['ad'], 'from a');
expect(options['abc'], 'from a');
expect(options['b'], 'from b');
expect(options['bc'], 'from b');
expect(options['bd'], 'from b');
expect(options['c'], 'from c');
expect(options['cd'], 'from d');
});
test('removes the include key after merging', () async {
var testFS = TestFileSystem({
'dir|main.yaml': analysisOptions(pageWidth: 120, include: 'a.yaml'),
'dir|a.yaml': analysisOptions(other: {'a': 123}),
});
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('dir|main.yaml'),
);
expect(options['include'], isNull);
});
test('locates includes relative to the parent directory', () async {
var testFS = TestFileSystem({
'dir|a.yaml': analysisOptions(
include: 'sub|b.yaml',
other: {'a': 'from a'},
),
'dir|sub|b.yaml': analysisOptions(
include: 'more|c.yaml',
other: {'b': 'from b'},
),
'dir|sub|more|c.yaml': analysisOptions(other: {'c': 'from c'}),
});
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('dir|a.yaml'),
);
expect(options['a'], 'from a');
expect(options['b'], 'from b');
expect(options['c'], 'from c');
});
test('resolves "package:" includes', () async {
var testFS = TestFileSystem({
'dir|a.yaml': analysisOptions(
include: 'package:b/b_options.yaml',
other: {'a': 'from a'},
),
'|b|b_options.yaml': analysisOptions(
include: 'package:c/c_options.yaml',
other: {'b': 'from b'},
),
'|c|c_options.yaml': analysisOptions(other: {'c': 'from c'}),
});
Future<String?> resolve(Uri packageUri) async {
return '|${packageUri.pathSegments.join('|')}';
}
var options = await readAnalysisOptions(
testFS,
TestFileSystemPath('dir|a.yaml'),
resolvePackageUri: resolve,
);
expect(options['a'], 'from a');
expect(options['b'], 'from b');
expect(options['c'], 'from c');
});
test('throws on a "package:" include with no package resolver', () async {
var testFS = TestFileSystem({
'options.yaml': analysisOptions(include: 'package:foo/options.yaml'),
});
expect(
readAnalysisOptions(testFS, TestFileSystemPath('options.yaml')),
throwsA(isA<PackageResolutionException>()),
);
});
test('throws on a "package:" resolution failure', () async {
var testFS = TestFileSystem({
'options.yaml': analysisOptions(include: 'package:foo/options.yaml'),
});
// A resolver that always fails.
Future<String?> failingResolver(Uri uri) async => null;
expect(
readAnalysisOptions(
testFS,
TestFileSystemPath('options.yaml'),
resolvePackageUri: failingResolver,
),
throwsA(isA<PackageResolutionException>()),
);
});
});
}
/// Reads the `formatter/page_width` key from [options] if present and returns
/// it or `null` if not found.
Object? _pageWidth(AnalysisOptions options) =>
(options['formatter'] as Map<Object?, Object?>?)?['page_width'];