blob: 9806292845f342d2245b8a3452e61f37ec21ec67 [file]
// 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 'dart:convert';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer_cli/src/ansi.dart' as ansi;
import 'package:analyzer_cli/src/error_formatter.dart';
import 'package:analyzer_cli/src/options.dart';
import 'package:analyzer_testing/src/analysis_rule/pub_package_resolution.dart';
import 'package:test/test.dart' hide ErrorFormatter;
import 'package:test_reflective_loader/test_reflective_loader.dart';
void main() {
defineReflectiveTests(ReporterTest);
}
@reflectiveTest
class ReporterTest extends PubPackageResolutionTest {
final StringBuffer out = StringBuffer();
final AnalysisStats stats = AnalysisStats();
@override
void setUp() {
super.setUp();
ansi.runningTests = true;
}
@override
Future<void> tearDown() async {
ansi.runningTests = false;
await super.tearDown();
}
Future<void> test_human_contextMessage_otherFile() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--dart-sdk=${sdkRoot.path}',
'--verbose',
'test.dart',
])!;
var reporter = HumanErrorFormatter(out, options, stats);
var libFile = newFile('$testPackageRootPath/lib/lib.dart', r'''
class C {
final int? foo;
C(this.foo);
}
''');
newFile(testFile.path, r'''
import 'lib.dart';
void f(C c) {
if (c.foo != null) {
c.foo.isEven;
}
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
expect(
out.toString().trim(),
contains(
"error • The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'. • package:test/test.dart:4:11 • unchecked_use_of_nullable_value",
),
);
expect(
out.toString().trim(),
contains(
" 'foo' refers to a public property so it couldn't be promoted. See https://dart.dev/go/non-promo-public-field at ${libFile.path}:2:14",
),
);
}
Future<void> test_human_error() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--dart-sdk=${sdkRoot.path}',
'test.dart',
])!;
var reporter = HumanErrorFormatter(out, options, stats);
newFile(testFile.path, r'''
void f() {
x;
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
expect(
out.toString().trim(),
"error • Undefined name 'x'. • package:test/test.dart:2:3 • undefined_identifier",
);
}
Future<void> test_human_hint() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--dart-sdk=${sdkRoot.path}',
'test.dart',
])!;
var reporter = HumanErrorFormatter(out, options, stats);
newFile(testFile.path, r'''
void f() {
return;
1;
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
expect(
out.toString().trim(),
'warning • Dead code. • package:test/test.dart:3:3 • dead_code',
);
}
Future<void> test_human_stats() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--dart-sdk=${sdkRoot.path}',
'test.dart',
])!;
var reporter = HumanErrorFormatter(out, options, stats);
newFile(testFile.path, r'''
void f() {
return;
1;
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
stats.print(out);
expect(
out.toString().trim(),
'warning • Dead code. • package:test/test.dart:3:3 • dead_code\n'
'1 warning found.',
);
}
Future<void> test_json_contextMessage_otherFile() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--format=json',
'--dart-sdk=${sdkRoot.path}',
'test.dart',
])!;
var reporter = JsonErrorFormatter(out, options, stats);
var libFile = newFile('$testPackageRootPath/lib/lib.dart', r'''
class C {
final int? foo;
C(this.foo);
}
''');
newFile(testFile.path, r'''
import 'lib.dart';
void f(C c) {
if (c.foo != null) {
c.foo.isEven;
}
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
var expected = {
'version': 1,
'diagnostics': [
{
'code': 'unchecked_use_of_nullable_value',
'severity': 'ERROR',
'type': 'COMPILE_TIME_ERROR',
'location': {
'file': testFile.path,
'range': {
'start': {'offset': 66, 'line': 4, 'column': 11},
'end': {'offset': 72, 'line': 4, 'column': 17},
},
},
'problemMessage': "The property 'isEven' can't be unconditionally accessed because the receiver can be 'null'.",
'correctionMessage': "Try making the access conditional (using '?.') or adding a null check to the target ('!').",
'contextMessages': [
{
'location': {
'file': libFile.path,
'range': {
'start': {'offset': 23, 'line': 2, 'column': 14},
'end': {'offset': 26, 'line': 2, 'column': 17},
},
},
'message': "'foo' refers to a public property so it couldn't be promoted. See https://dart.dev/go/non-promo-public-field",
},
],
'documentation':
'https://dart.dev/diagnostics/unchecked_use_of_nullable_value',
},
],
};
expect(json.decode(out.toString().trim()), expected);
}
Future<void> test_json_error() async {
var options = CommandLineOptions.parse(resourceProvider, [
'--format=json',
'--dart-sdk=${sdkRoot.path}',
'test.dart',
])!;
var reporter = JsonErrorFormatter(out, options, stats);
newFile(testFile.path, r'''
void f() {
x;
}
''');
var errorsResult = await _getErrorsResultForFile(testFile);
await reporter.formatErrors([errorsResult]);
reporter.flush();
var expected = {
'version': 1,
'diagnostics': [
{
'code': 'undefined_identifier',
'severity': 'ERROR',
'type': 'COMPILE_TIME_ERROR',
'location': {
'file': testFile.path,
'range': {
'start': {'offset': 13, 'line': 2, 'column': 3},
'end': {'offset': 14, 'line': 2, 'column': 4},
},
},
'problemMessage': "Undefined name 'x'.",
'correctionMessage': 'Try correcting the name to one that is defined, or defining the name.',
'documentation': 'https://dart.dev/diagnostics/undefined_identifier',
},
],
};
expect(out.toString().trim(), json.encode(expected));
}
Future<ErrorsResult> _getErrorsResultForFile(File file) async {
var errorsResult = await contextCollection
.contextFor(file.path)
.currentSession
.getErrors(file.path);
return errorsResult as ErrorsResult;
}
}