Files
sdk/pkg/nnbd_migration/test/front_end/region_renderer_test.dart
T
Paul Berry 68c50f7f92 Migration: re-work test_informationalRegion_containsTraceLinks_separateDrive.
Previously, we were switching test paths to drive `D` at the start of
the test, after the `package_config.json` file had already been
generated to drive `C`; as a result, it didn't apply.  We will need
the `package_config.json` to apply when we flip the null safety flag
(so that the inputs to the migration tool are considered opted out
prior to migration).  This CL reworks the test so that the paths are
modified as part of test set-up, so `package_config.json` gets put in
the right place.

Fixes #43883.

Bug: https://github.com/dart-lang/sdk/issues/43883
Change-Id: I08f79ddb07d7a5ecf640370a32334a7ceb92ceff
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169421
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
2020-10-28 16:35:30 +00:00

200 lines
7.4 KiB
Dart

// Copyright (c) 2020, 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:nnbd_migration/src/front_end/migration_info.dart';
import 'package:nnbd_migration/src/front_end/path_mapper.dart';
import 'package:nnbd_migration/src/front_end/region_renderer.dart';
import 'package:nnbd_migration/src/front_end/web/edit_details.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'nnbd_migration_test_base.dart';
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(RegionRendererTest);
defineReflectiveTests(RegionRendererTestDriveD);
});
}
@reflectiveTest
class RegionRendererTest extends RegionRendererTestBase {
/// Returns the basename of [testFile], used in traces.
String get _testFileBasename =>
resourceProvider.pathContext.basename(testFile);
Future<void> test_informationalRegion_containsTrace() async {
await buildInfoForSingleTestFile('f(int a) => a.isEven;',
migratedContent: 'f(int a) => a.isEven;');
var response = renderRegion(5);
expect(response.traces, hasLength(1));
var trace = response.traces[0];
expect(trace.description, equals('Non-nullability reason'));
}
Future<void> test_informationalRegion_containsTraceEntryDescriptions() async {
await buildInfoForSingleTestFile('f(int a) => a.isEven;',
migratedContent: 'f(int a) => a.isEven;');
var response = renderRegion(5);
expect(response.traces, hasLength(1));
var trace = response.traces[0];
expect(trace.entries, hasLength(2));
expect(trace.entries[0].description,
equals('parameter 0 of f ($_testFileBasename:1:3)'));
expect(trace.entries[1].description, equals('data flow'));
}
Future<void> test_informationalRegion_containsTraceLinks() async {
await buildInfoForSingleTestFile('f(int a) => a.isEven;',
migratedContent: 'f(int a) => a.isEven;');
var response = renderRegion(5);
expect(response.traces, hasLength(1));
var trace = response.traces[0];
var entry = trace.entries[0];
expect(entry.link, isNotNull);
var testFileUriPath = resourceProvider.pathContext.toUri(testFile).path;
expect(entry.link.href,
equals('$testFileUriPath?offset=2&line=1&authToken=AUTH_TOKEN'));
expect(entry.link.path,
equals(resourceProvider.pathContext.toUri(_testFileBasename).path));
}
Future<void> test_modifiedOutput_containsExplanation() async {
await buildInfoForSingleTestFile('int a = null;',
migratedContent: 'int? a = null;');
var response = renderRegion(3);
expect(response.explanation, equals("Changed type 'int' to be nullable"));
}
Future<void> test_modifiedOutput_containsPath() async {
await buildInfoForSingleTestFile('int a = null;',
migratedContent: 'int? a = null;');
var response = renderRegion(3);
expect(response.displayPath, equals(testFile));
expect(response.uriPath, equals(pathMapper.map(testFile)));
expect(response.line, equals(1));
}
Future<void> test_modifiedOutput_containsTraceForNullabilityReason() async {
await buildInfoForSingleTestFile('int a = null;',
migratedContent: 'int? a = null;');
var response = renderRegion(3);
expect(response.traces, hasLength(1));
var trace = response.traces[0];
expect(trace.description, equals('Nullability reason'));
expect(trace.entries, hasLength(4));
expect(trace.entries[0].description, equals('a ($_testFileBasename:1:1)'));
expect(trace.entries[1].description, equals('data flow'));
expect(trace.entries[2].description,
equals('null literal ($_testFileBasename:1:9)'));
expect(trace.entries[3].description, equals('literal expression'));
}
Future<void> test_unmodifiedOutput_containsExplanation() async {
await buildInfoForSingleTestFile('f(int a) => a.isEven;',
migratedContent: 'f(int a) => a.isEven;');
var response = renderRegion(5);
expect(response.explanation, equals("Type 'int' was not made nullable"));
}
Future<void> test_unmodifiedOutput_containsPath() async {
await buildInfoForSingleTestFile('f(int a) => a.isEven;',
migratedContent: 'f(int a) => a.isEven;');
var response = renderRegion(5);
expect(response.displayPath, equals(testFile));
expect(response.uriPath, equals(pathMapper.map(testFile)));
expect(response.line, equals(1));
}
}
class RegionRendererTestBase extends NnbdMigrationTestBase {
PathMapper pathMapper;
/// Render the region at [offset], using a [MigrationInfo] which knows only
/// about the library at `infos.single`.
EditDetails renderRegion(int offset) {
var migrationInfo =
MigrationInfo(infos, {}, resourceProvider.pathContext, projectPath);
var unitInfo = infos.single;
var region = unitInfo.regionAt(offset);
pathMapper = PathMapper(resourceProvider);
return RegionRenderer(
region, unitInfo, migrationInfo, pathMapper, 'AUTH_TOKEN')
.render();
}
}
@reflectiveTest
class RegionRendererTestDriveD extends RegionRendererTestBase {
@override
String get homePath => _switchToDriveD(super.homePath);
@override
void setUp() {
super.setUp();
}
Future<void>
test_informationalRegion_containsTraceLinks_separateDrive() async {
// See https://github.com/dart-lang/sdk/issues/43178. Linking from a file on
// one drive to a file on another drive can cause problems.
await buildInfoForSingleTestFile(r'''
f(List<int> a) {
if (1 == 2) List.from(a);
}
g() {
f(null);
}
''', migratedContent: r'''
f(List<int >? a) {
if (1 == 2) List.from(a!);
}
g() {
f(null);
}
''');
var response = renderRegion(44); // The inserted null-check.
expect(response.displayPath,
equals(_switchToDriveD(convertPath('/home/tests/bin/test.dart'))));
expect(response.traces, hasLength(2));
var trace = response.traces[1];
expect(trace.description, equals('Non-nullability reason'));
expect(trace.entries, hasLength(1));
var entry = trace.entries[0];
expect(entry.link, isNotNull);
var sdkCoreLib = convertPath('/sdk/lib/core/core.dart');
var sdkCoreLibUriPath = resourceProvider.pathContext.toUri(sdkCoreLib).path;
var coreLibText = resourceProvider.getFile(sdkCoreLib).readAsStringSync();
var expectedOffset =
'List.from'.allMatches(coreLibText).single.start + 'List.'.length;
var expectedLine =
'\n'.allMatches(coreLibText.substring(0, expectedOffset)).length + 1;
expect(
entry.link.href,
equals('$sdkCoreLibUriPath?'
'offset=$expectedOffset&'
'line=$expectedLine&'
'authToken=AUTH_TOKEN'));
// On Windows, the path will simply be the absolute path to the core
// library, because there is no relative route from C:\ to D:\. On Posix,
// the path is relative.
var expectedLinkPath = resourceProvider.pathContext.style == p.Style.windows
? sdkCoreLibUriPath
: '../../..$sdkCoreLibUriPath';
expect(entry.link.path, equals(expectedLinkPath));
}
/// On Windows, replace the C:\ relative root in [path] with the D:\ relative
/// root.
///
/// On Posix, nothing is be replaced.
String _switchToDriveD(String path) {
assert(resourceProvider.pathContext.isAbsolute(path));
return resourceProvider
.convertPath(path)
.replaceFirst(RegExp('^C:\\\\'), 'D:\\');
}
}