| // Copyright (c) 2013, 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. |
| |
| // ignore_for_file: inference_failure_on_collection_literal |
| // ignore_for_file: inference_failure_on_instance_creation |
| |
| import 'dart:convert'; |
| |
| import 'package:source_maps/source_maps.dart'; |
| import 'package:source_span/source_span.dart'; |
| import 'package:test/test.dart'; |
| |
| import 'common.dart'; |
| |
| const Map<String, dynamic> _mapWithNoSourceLocation = { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': ['input.dart'], |
| 'names': [], |
| 'mappings': 'A', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocation = { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': ['input.dart'], |
| 'names': [], |
| 'mappings': 'AAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocationAndMissingNames = { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': ['input.dart'], |
| 'mappings': 'AAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocationAndName = { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': ['input.dart'], |
| 'names': ['var'], |
| 'mappings': 'AAAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocationAndName1 = { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': ['input1.dart'], |
| 'names': ['var1'], |
| 'mappings': 'AAAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocationAndName2 = { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': ['input2.dart'], |
| 'names': ['var2'], |
| 'mappings': 'AAAAA', |
| 'file': 'output2.dart' |
| }; |
| |
| const Map<String, dynamic> _mapWithSourceLocationAndName3 = { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': ['input3.dart'], |
| 'names': ['var3'], |
| 'mappings': 'AAAAA', |
| 'file': '3/output.dart' |
| }; |
| |
| const _sourceMapBundle = [ |
| _mapWithSourceLocationAndName1, |
| _mapWithSourceLocationAndName2, |
| _mapWithSourceLocationAndName3, |
| ]; |
| |
| void main() { |
| test('parse', () { |
| var mapping = parseJson(expectedMap); |
| check(outputVar1, mapping, inputVar1, false); |
| check(outputVar2, mapping, inputVar2, false); |
| check(outputFunction, mapping, inputFunction, false); |
| check(outputExpr, mapping, inputExpr, false); |
| }); |
| |
| test('parse + json', () { |
| var mapping = parse(jsonEncode(expectedMap)); |
| check(outputVar1, mapping, inputVar1, false); |
| check(outputVar2, mapping, inputVar2, false); |
| check(outputFunction, mapping, inputFunction, false); |
| check(outputExpr, mapping, inputExpr, false); |
| }); |
| |
| test('parse with file', () { |
| var mapping = parseJson(expectedMap); |
| check(outputVar1, mapping, inputVar1, true); |
| check(outputVar2, mapping, inputVar2, true); |
| check(outputFunction, mapping, inputFunction, true); |
| check(outputExpr, mapping, inputExpr, true); |
| }); |
| |
| test('parse with no source location', () { |
| var map = parse(jsonEncode(_mapWithNoSourceLocation)) as SingleMapping; |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| var entry = map.lines.first.entries.first; |
| |
| expect(entry.column, 0); |
| expect(entry.sourceUrlId, null); |
| expect(entry.sourceColumn, null); |
| expect(entry.sourceLine, null); |
| expect(entry.sourceNameId, null); |
| }); |
| |
| test('parse with source location and no name', () { |
| var map = parse(jsonEncode(_mapWithSourceLocation)) as SingleMapping; |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| var entry = map.lines.first.entries.first; |
| |
| expect(entry.column, 0); |
| expect(entry.sourceUrlId, 0); |
| expect(entry.sourceColumn, 0); |
| expect(entry.sourceLine, 0); |
| expect(entry.sourceNameId, null); |
| }); |
| |
| test('parse with source location and missing names entry', () { |
| var map = parse(jsonEncode(_mapWithSourceLocationAndMissingNames)) |
| as SingleMapping; |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| var entry = map.lines.first.entries.first; |
| |
| expect(entry.column, 0); |
| expect(entry.sourceUrlId, 0); |
| expect(entry.sourceColumn, 0); |
| expect(entry.sourceLine, 0); |
| expect(entry.sourceNameId, null); |
| }); |
| |
| test('parse with source location and name', () { |
| var map = parse(jsonEncode(_mapWithSourceLocationAndName)) as SingleMapping; |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| var entry = map.lines.first.entries.first; |
| |
| expect(entry.sourceUrlId, 0); |
| expect(entry.sourceUrlId, 0); |
| expect(entry.sourceColumn, 0); |
| expect(entry.sourceLine, 0); |
| expect(entry.sourceNameId, 0); |
| }); |
| |
| test('parse with source root', () { |
| var inputMap = Map.from(_mapWithSourceLocation); |
| inputMap['sourceRoot'] = '/pkg/'; |
| var mapping = parseJson(inputMap) as SingleMapping; |
| expect(mapping.spanFor(0, 0)?.sourceUrl, Uri.parse('/pkg/input.dart')); |
| expect( |
| mapping |
| .spanForLocation( |
| SourceLocation(0, sourceUrl: Uri.parse('ignored.dart'))) |
| ?.sourceUrl, |
| Uri.parse('/pkg/input.dart')); |
| |
| var newSourceRoot = '/new/'; |
| |
| mapping.sourceRoot = newSourceRoot; |
| inputMap['sourceRoot'] = newSourceRoot; |
| |
| expect(mapping.toJson(), equals(inputMap)); |
| }); |
| |
| test('parse with map URL', () { |
| var inputMap = Map.from(_mapWithSourceLocation); |
| inputMap['sourceRoot'] = 'pkg/'; |
| var mapping = parseJson(inputMap, mapUrl: 'file:///path/to/map'); |
| expect(mapping.spanFor(0, 0)?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input.dart')); |
| }); |
| |
| group('parse with bundle', () { |
| var mapping = |
| parseJsonExtended(_sourceMapBundle, mapUrl: 'file:///path/to/map'); |
| |
| test('simple', () { |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.file('/path/to/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.file('/path/to/output2.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.file('/path/to/3/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| |
| expect( |
| mapping.spanFor(0, 0, uri: 'file:///path/to/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect( |
| mapping.spanFor(0, 0, uri: 'file:///path/to/output2.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect( |
| mapping |
| .spanFor(0, 0, uri: 'file:///path/to/3/output.dart') |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| |
| test('package uris', () { |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('package:1/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('package:2/output2.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('package:3/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| |
| expect(mapping.spanFor(0, 0, uri: 'package:1/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect(mapping.spanFor(0, 0, uri: 'package:2/output2.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect(mapping.spanFor(0, 0, uri: 'package:3/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| |
| test('unmapped path', () { |
| var span = mapping.spanFor(0, 0, uri: 'unmapped_output.dart')!; |
| expect(span.sourceUrl, Uri.parse('unmapped_output.dart')); |
| expect(span.start.line, equals(0)); |
| expect(span.start.column, equals(0)); |
| |
| span = mapping.spanFor(10, 5, uri: 'unmapped_output.dart')!; |
| expect(span.sourceUrl, Uri.parse('unmapped_output.dart')); |
| expect(span.start.line, equals(10)); |
| expect(span.start.column, equals(5)); |
| }); |
| |
| test('missing path', () { |
| expect(() => mapping.spanFor(0, 0), throwsA(anything)); |
| }); |
| |
| test('incomplete paths', () { |
| expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| |
| test('parseExtended', () { |
| var mapping = parseExtended(jsonEncode(_sourceMapBundle), |
| mapUrl: 'file:///path/to/map'); |
| |
| expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| |
| test('build bundle incrementally', () { |
| var mapping = MappingBundle(); |
| |
| mapping.addMapping(parseJson(_mapWithSourceLocationAndName1, |
| mapUrl: 'file:///path/to/map') as SingleMapping); |
| expect(mapping.spanFor(0, 0, uri: 'output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| |
| expect(mapping.containsMapping('output2.dart'), isFalse); |
| mapping.addMapping(parseJson(_mapWithSourceLocationAndName2, |
| mapUrl: 'file:///path/to/map') as SingleMapping); |
| expect(mapping.containsMapping('output2.dart'), isTrue); |
| expect(mapping.spanFor(0, 0, uri: 'output2.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| |
| expect(mapping.containsMapping('3/output.dart'), isFalse); |
| mapping.addMapping(parseJson(_mapWithSourceLocationAndName3, |
| mapUrl: 'file:///path/to/map') as SingleMapping); |
| expect(mapping.containsMapping('3/output.dart'), isTrue); |
| expect(mapping.spanFor(0, 0, uri: '3/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| |
| // Test that the source map can handle cases where the uri passed in is |
| // not from the expected host but it is still unambiguous which source |
| // map should be used. |
| test('different paths', () { |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('http://localhost/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('http://localhost/output2.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect( |
| mapping |
| .spanForLocation(SourceLocation(0, |
| sourceUrl: Uri.parse('http://localhost/3/output.dart'))) |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| |
| expect( |
| mapping.spanFor(0, 0, uri: 'http://localhost/output.dart')?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input1.dart')); |
| expect( |
| mapping |
| .spanFor(0, 0, uri: 'http://localhost/output2.dart') |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input2.dart')); |
| expect( |
| mapping |
| .spanFor(0, 0, uri: 'http://localhost/3/output.dart') |
| ?.sourceUrl, |
| Uri.parse('file:///path/to/pkg/input3.dart')); |
| }); |
| }); |
| |
| test('parse and re-emit', () { |
| for (var expected in [ |
| expectedMap, |
| _mapWithNoSourceLocation, |
| _mapWithSourceLocation, |
| _mapWithSourceLocationAndName |
| ]) { |
| var mapping = parseJson(expected) as SingleMapping; |
| expect(mapping.toJson(), equals(expected)); |
| |
| mapping = parseJsonExtended(expected) as SingleMapping; |
| expect(mapping.toJson(), equals(expected)); |
| } |
| |
| var mapping = parseJsonExtended(_sourceMapBundle) as MappingBundle; |
| expect(mapping.toJson(), equals(_sourceMapBundle)); |
| }); |
| |
| test('parse extensions', () { |
| var map = Map.from(expectedMap); |
| map['x_foo'] = 'a'; |
| map['x_bar'] = [3]; |
| var mapping = parseJson(map) as SingleMapping; |
| expect(mapping.toJson(), equals(map)); |
| expect(mapping.extensions['x_foo'], equals('a')); |
| expect((mapping.extensions['x_bar'] as List).first, equals(3)); |
| }); |
| |
| group('source files', () { |
| group('from fromEntries()', () { |
| test('are null for non-FileLocations', () { |
| var mapping = SingleMapping.fromEntries([ |
| Entry(SourceLocation(10, line: 1, column: 8), outputVar1.start, null) |
| ]); |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test("use a file location's file", () { |
| var mapping = SingleMapping.fromEntries( |
| [Entry(inputVar1.start, outputVar1.start, null)]); |
| expect(mapping.files, equals([input])); |
| }); |
| }); |
| |
| group('from parse()', () { |
| group('are null', () { |
| test('with no sourcesContent field', () { |
| var mapping = parseJson(expectedMap) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test('with null sourcesContent values', () { |
| var map = Map.from(expectedMap); |
| map['sourcesContent'] = [null]; |
| var mapping = parseJson(map) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test('with a too-short sourcesContent', () { |
| var map = Map.from(expectedMap); |
| map['sourcesContent'] = []; |
| var mapping = parseJson(map) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| }); |
| |
| test('are parsed from sourcesContent', () { |
| var map = Map.from(expectedMap); |
| map['sourcesContent'] = ['hello, world!']; |
| var mapping = parseJson(map) as SingleMapping; |
| |
| var file = mapping.files[0]!; |
| expect(file.url, equals(Uri.parse('input.dart'))); |
| expect(file.getText(0), equals('hello, world!')); |
| }); |
| }); |
| }); |
| } |