blob: bfa0ecfda97b8c3915cfafefd7f63bdbfa48ede8 [file] [log] [blame]
// Copyright 2020 The Dart Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@Timeout(Duration(minutes: 2))
import 'package:dwds/src/debugging/location.dart';
import 'package:dwds/src/utilities/dart_uri.dart';
import 'package:test/test.dart';
import 'fixtures/fakes.dart';
import 'fixtures/utilities.dart';
final sourceMapContents =
'{"version":3,"sourceRoot":"","sources":["main.dart"],"names":[],'
'"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUwB,IAAtB,WAAM;AAKJ,'
'IAHF,4BAAkB,aAAa,SAAC,GAAG;AACb,MAApB,WAAM;AACN,YAAgC,+CAAO,AAAK,oBAAO,'
'yCAAC,WAAW;IAChE;AAC0D,IAA3D,AAAS,AAAK,0DAAO;AAAe,kBAAO;;;AAEvC,gBAAQ;'
'AAGV,IAFI,kCAAqC,QAAC;AACX,MAA/B,WAAM,AAAwB,0BAAP,QAAF,AAAE,KAAK,GAAP;'
';EAEzB","file":"main.ddc.js"}';
void main() {
const lines = 100;
const lineLength = 150;
final assetReader = FakeAssetReader(sourceMap: sourceMapContents);
final toolConfiguration = TestToolConfiguration.withLoadStrategy(
loadStrategy: MockLoadStrategy(assetReader),
);
setGlobalsForTesting(
toolConfiguration: toolConfiguration,
);
final dartUri = DartUri('org-dartlang-app://web/main.dart');
final modules = FakeModules(module: _module);
final locations = Locations(assetReader, modules, '');
locations.initialize('fake_entrypoint');
group('JS locations |', () {
group('location |', () {
test('is zero based', () async {
final loc = JsLocation.fromZeroBased(_module, 0, 0);
expect(loc, _matchJsLocation(0, 0));
});
test('can compare to other location', () async {
final loc00 = JsLocation.fromZeroBased(_module, 0, 0);
final loc01 = JsLocation.fromZeroBased(_module, 0, 1);
final loc10 = JsLocation.fromZeroBased(_module, 1, 0);
final loc11 = JsLocation.fromZeroBased(_module, 1, 1);
expect(loc00.compareTo(loc01), isNegative);
expect(loc00.compareTo(loc10), isNegative);
expect(loc00.compareTo(loc10), isNegative);
expect(loc00.compareTo(loc11), isNegative);
expect(loc00.compareTo(loc00), isZero);
expect(loc11.compareTo(loc00), isPositive);
});
});
group('best location |', () {
test('does not return location for setup code', () async {
final location = await locations.locationForJs(_module, 0, 0);
expect(location, isNull);
});
test('prefers precise match', () async {
final location = await locations.locationForJs(_module, 37, 0);
expect(location, _matchLocationForJs(37, 0));
});
test('finds a match in the beginning of the line', () async {
final location = await locations.locationForJs(_module, 39, 4);
expect(location, _matchLocationForJs(39, 0));
});
test('finds a match in the middle of the line', () async {
final location = await locations.locationForJs(_module, 39, 10);
expect(location, _matchLocationForJs(39, 6));
});
test('finds a match on a previous line', () async {
final location = await locations.locationForJs(_module, 44, 0);
expect(location, _matchLocationForJs(43, 18));
});
test('finds a match on a previous line with a closer match after',
() async {
final location =
await locations.locationForJs(_module, 44, lineLength - 1);
expect(location, _matchLocationForJs(43, 18));
});
test('finds a match on the last line', () async {
final location =
await locations.locationForJs(_module, lines - 1, lineLength - 1);
expect(location, _matchLocationForJs(50, 2));
});
test('finds a match on invalid line', () async {
final location =
await locations.locationForJs(_module, lines, lineLength - 1);
expect(location, _matchLocationForJs(50, 2));
});
test('finds a match on invalid column on the same line', () async {
final location = await locations.locationForJs(_module, 50, lineLength);
expect(location, _matchLocationForJs(50, 2));
});
test('finds a match on invalid column on a previous line', () async {
final location =
await locations.locationForJs(_module, lines - 1, lineLength);
expect(location, _matchLocationForJs(50, 2));
});
});
});
group('Dart locations |', () {
group('location |', () {
test('is one based', () async {
final loc = DartLocation.fromZeroBased(dartUri, 0, 0);
expect(loc, _matchDartLocation(1, 1));
});
test('can compare to other locations', () async {
final loc00 = DartLocation.fromZeroBased(dartUri, 0, 0);
final loc01 = DartLocation.fromZeroBased(dartUri, 0, 1);
final loc10 = DartLocation.fromZeroBased(dartUri, 1, 0);
final loc11 = DartLocation.fromZeroBased(dartUri, 1, 1);
expect(loc00.compareTo(loc01), isNegative);
expect(loc00.compareTo(loc10), isNegative);
expect(loc00.compareTo(loc10), isNegative);
expect(loc00.compareTo(loc11), isNegative);
expect(loc00.compareTo(loc00), isZero);
expect(loc11.compareTo(loc00), isPositive);
});
});
group('best location |', () {
test('does not return location for dart lines not mapped to JS',
() async {
final location = await locations.locationForDart(dartUri, 0, 0);
expect(location, isNull);
});
test('returns location after on the same line', () async {
final location = await locations.locationForDart(dartUri, 11, 0);
expect(location, _matchLocationForDart(11, 3));
});
test('return null on invalid line', () async {
final location = await locations.locationForDart(dartUri, lines, 0);
expect(location, isNull);
});
test('return null on invalid column', () async {
final location =
await locations.locationForDart(dartUri, lines - 1, lineLength);
expect(location, isNull);
});
});
});
}
Matcher _matchLocationForDart(int line, int column) => isA<Location>().having(
(l) => l.dartLocation,
'dartLocation',
_matchDartLocation(line, column),
);
Matcher _matchLocationForJs(int line, int column) => isA<Location>()
.having((l) => l.jsLocation, 'jsLocation', _matchJsLocation(line, column));
Matcher _matchDartLocation(int line, int column) => isA<DartLocation>()
.having((l) => l.line, 'line', line)
.having((l) => l.column, 'column', column);
Matcher _matchJsLocation(int line, int column) => isA<JsLocation>()
.having((l) => l.line, 'line', line)
.having((l) => l.column, 'column', column);
const _module = 'packages/module';
const _serverPath = 'web/main.dart';
const _sourceMapPath = 'packages/module.js.map';
class MockLoadStrategy extends FakeStrategy {
MockLoadStrategy(super.assetReader);
@override
Future<String?> moduleForServerPath(
String entrypoint,
String serverPath,
) async =>
_module;
@override
Future<String> serverPathForModule(String entrypoint, String module) async =>
_serverPath;
@override
Future<String> sourceMapPathForModule(
String entrypoint,
String module,
) async =>
_sourceMapPath;
@override
String serverPathForAppUri(String appUri) => _serverPath;
}