Files
sdk/pkg/analyzer/test/source/error_processor_test.dart
Konstantin Shcheglov 5d17e0aa92 CQ. Stop using mocks of Source in analyzer/.
Use FileSource backed by analyzer_testing resources instead of the
test-only Source implementations in analyzer tests.

Update the lightweight TestAnalysisContext to receive a
ResourceProviderMixin and install a URI resolver that produces real
FileSource instances for the dart: and package: URIs used by mock SDK
elements. Convert scanner, diagnostic, options, constant, type system,
and workspace tests to create sources from in-memory files.

Remove the remaining Source mock helpers, including TestSource,
TestSourceWithUri, local Source mocks, and the unused TestTypeProvider.
This keeps test sources closer to production Source behavior and avoids
partial mock implementations that rely on noSuchMethod stubs.

Change-Id: Iad600fb7f5ea00d2c015191df548e0d66a424940
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/499422
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
2026-04-30 12:39:38 -07:00

228 lines
6.7 KiB
Dart

// Copyright (c) 2015, 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:analyzer/dart/analysis/analysis_options.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/source/file_source.dart';
import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/dart/analysis/analysis_options.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer_testing/resource_provider_mixin.dart';
import 'package:collection/collection.dart';
import 'package:test/test.dart';
import 'package:yaml/yaml.dart';
import '../src/util/yaml_test.dart';
main() {
var testSources = _TestSources();
Diagnostic invalid_assignment = Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: diag.invalidAssignment,
arguments: [
['x'],
['y'],
],
);
Diagnostic assignment_of_do_not_store = Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: diag.assignmentOfDoNotStore,
arguments: [
['x'],
],
);
Diagnostic unused_local_variable = Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: diag.unusedLocalVariable,
arguments: [
['x'],
],
);
Diagnostic use_of_void_result = Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: diag.useOfVoidResult,
);
// We in-line a lint code here in order to avoid adding a dependency on the
// linter package.
Diagnostic annotate_overrides = Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: LintCode(
'annotate_overrides',
'',
uniqueName: 'LintCode.annotate_overrides',
),
);
group('ErrorProcessor', () {
late _TestContext context;
setUp(() {
context = _TestContext();
});
test('configureOptions', () {
context.configureOptions('''
analyzer:
errors:
invalid_assignment: error # severity ERROR
assignment_of_do_not_store: false # ignore
unused_local_variable: true # skipped
use_of_void_result: unsupported_action # skipped
''');
expect(
context.getProcessor(invalid_assignment)!.severity,
DiagnosticSeverity.ERROR,
);
expect(
context.getProcessor(assignment_of_do_not_store)!.severity,
isNull,
);
expect(context.getProcessor(unused_local_variable), isNull);
expect(context.getProcessor(use_of_void_result), isNull);
});
test('does not upgrade other warnings to errors in strong mode', () {
context.configureOptions('''
analyzer:
strong-mode: true
''');
expect(context.getProcessor(unused_local_variable), isNull);
});
test('applies to analyzer warning even if lower case', () {
var errorProcessor = ErrorProcessor('cast_from_null_always_fails');
expect(
errorProcessor.appliesTo(
Diagnostic.tmp(
source: testSources.source(),
offset: 0,
length: 1,
diagnosticCode: diag.castFromNullAlwaysFails,
),
),
true,
);
});
});
group('ErrorConfig', () {
var config = '''
analyzer:
errors:
invalid_assignment: unsupported_action # should be skipped
assignment_of_do_not_store: false
unused_local_variable: error
''';
group('processing', () {
test('yaml map', () {
var options = AnalysisOptionsProvider(
SourceFactoryImpl([]),
).getOptionsFromString(config);
var errorConfig = ErrorConfig(
(options['analyzer'] as YamlMap)['errors'] as YamlNode?,
);
expect(errorConfig.processors, hasLength(2));
// ignore
var missingReturnProcessor = errorConfig.processors.firstWhere(
(p) => p.appliesTo(assignment_of_do_not_store),
);
expect(missingReturnProcessor.severity, isNull);
// error
var unusedLocalProcessor = errorConfig.processors.firstWhere(
(p) => p.appliesTo(unused_local_variable),
);
expect(unusedLocalProcessor.severity, DiagnosticSeverity.ERROR);
// skip
var invalidAssignmentProcessor = errorConfig.processors
.firstWhereOrNull((p) => p.appliesTo(invalid_assignment));
expect(invalidAssignmentProcessor, isNull);
});
test('string map', () {
var options = wrap({
'invalid_assignment': 'unsupported_action', // should be skipped
'assignment_of_do_not_store': 'false',
'unused_local_variable': 'error',
});
var errorConfig = ErrorConfig(options);
expect(errorConfig.processors, hasLength(2));
// ignore
var missingReturnProcessor = errorConfig.processors.firstWhere(
(p) => p.appliesTo(assignment_of_do_not_store),
);
expect(missingReturnProcessor.severity, isNull);
// error
var unusedLocalProcessor = errorConfig.processors.firstWhere(
(p) => p.appliesTo(unused_local_variable),
);
expect(unusedLocalProcessor.severity, DiagnosticSeverity.ERROR);
// skip
var invalidAssignmentProcessor = errorConfig.processors
.firstWhereOrNull((p) => p.appliesTo(invalid_assignment));
expect(invalidAssignmentProcessor, isNull);
});
});
test('configure lints', () {
var options = AnalysisOptionsProvider(SourceFactoryImpl([]))
.getOptionsFromString(
'analyzer:\n errors:\n annotate_overrides: warning\n',
);
var errorConfig = ErrorConfig(
(options['analyzer'] as YamlMap)['errors'] as YamlNode?,
);
expect(errorConfig.processors, hasLength(1));
ErrorProcessor processor = errorConfig.processors.first;
expect(processor.appliesTo(annotate_overrides), true);
expect(processor.severity, DiagnosticSeverity.WARNING);
});
});
}
class _TestContext {
late AnalysisOptions analysisOptions;
void configureOptions(String options) {
analysisOptions = AnalysisOptionsImpl.fromYaml(
optionsMap: AnalysisOptionsProvider(
SourceFactoryImpl([]),
).getOptionsFromString(options),
);
}
ErrorProcessor? getProcessor(Diagnostic diagnostic) {
return ErrorProcessor.getProcessor(analysisOptions, diagnostic);
}
}
class _TestSources with ResourceProviderMixin {
FileSource source() => FileSource(newFile('/test.dart', ''));
}