| // 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. |
| |
| library test.parser_test; |
| |
| import 'dart:convert'; |
| import 'package:test/test.dart'; |
| import 'package:source_maps/source_maps.dart'; |
| import 'package:source_span/source_span.dart'; |
| import 'common.dart'; |
| |
| const Map<String, dynamic> MAP_WITH_NO_SOURCE_LOCATION = const { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': const ['input.dart'], |
| 'names': const [], |
| 'mappings': 'A', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION = const { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': const ['input.dart'], |
| 'names': const [], |
| 'mappings': 'AAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION_AND_NAME = const { |
| 'version': 3, |
| 'sourceRoot': '', |
| 'sources': const ['input.dart'], |
| 'names': const ['var'], |
| 'mappings': 'AAAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION_AND_NAME_1 = const { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': const ['input1.dart'], |
| 'names': const ['var1'], |
| 'mappings': 'AAAAA', |
| 'file': 'output.dart' |
| }; |
| |
| const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION_AND_NAME_2 = const { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': const ['input2.dart'], |
| 'names': const ['var2'], |
| 'mappings': 'AAAAA', |
| 'file': 'output2.dart' |
| }; |
| |
| const Map<String, dynamic> MAP_WITH_SOURCE_LOCATION_AND_NAME_3 = const { |
| 'version': 3, |
| 'sourceRoot': 'pkg/', |
| 'sources': const ['input3.dart'], |
| 'names': const ['var3'], |
| 'mappings': 'AAAAA', |
| 'file': '3/output.dart' |
| }; |
| |
| const List SOURCE_MAP_BUNDLE = const [ |
| MAP_WITH_SOURCE_LOCATION_AND_NAME_1, |
| MAP_WITH_SOURCE_LOCATION_AND_NAME_2, |
| MAP_WITH_SOURCE_LOCATION_AND_NAME_3, |
| ]; |
| |
| main() { |
| test('parse', () { |
| var mapping = parseJson(EXPECTED_MAP); |
| 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(EXPECTED_MAP)); |
| 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(EXPECTED_MAP); |
| 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', () { |
| SingleMapping map = parse(jsonEncode(MAP_WITH_NO_SOURCE_LOCATION)); |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| TargetEntry 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', () { |
| SingleMapping map = parse(jsonEncode(MAP_WITH_SOURCE_LOCATION)); |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| TargetEntry 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', () { |
| SingleMapping map = parse(jsonEncode(MAP_WITH_SOURCE_LOCATION_AND_NAME)); |
| expect(map.lines.length, 1); |
| expect(map.lines.first.entries.length, 1); |
| TargetEntry 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 = new Map.from(MAP_WITH_SOURCE_LOCATION); |
| inputMap['sourceRoot'] = '/pkg/'; |
| var mapping = parseJson(inputMap) as SingleMapping; |
| expect(mapping.spanFor(0, 0).sourceUrl, Uri.parse("/pkg/input.dart")); |
| expect( |
| mapping |
| .spanForLocation( |
| new 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 = new Map.from(MAP_WITH_SOURCE_LOCATION); |
| 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(SOURCE_MAP_BUNDLE, mapUrl: "file:///path/to/map"); |
| |
| test('simple', () { |
| expect( |
| mapping |
| .spanForLocation(new SourceLocation(0, |
| sourceUrl: new Uri.file('/path/to/output.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input1.dart")); |
| expect( |
| mapping |
| .spanForLocation(new SourceLocation(0, |
| sourceUrl: new Uri.file('/path/to/output2.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input2.dart")); |
| expect( |
| mapping |
| .spanForLocation(new SourceLocation(0, |
| sourceUrl: new 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(new SourceLocation(0, |
| sourceUrl: Uri.parse('package:1/output.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input1.dart")); |
| expect( |
| mapping |
| .spanForLocation(new SourceLocation(0, |
| sourceUrl: Uri.parse('package:2/output2.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input2.dart")); |
| expect( |
| mapping |
| .spanForLocation(new 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), throws); |
| }); |
| |
| 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(SOURCE_MAP_BUNDLE), |
| 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 = new MappingBundle(); |
| |
| mapping.addMapping(parseJson(MAP_WITH_SOURCE_LOCATION_AND_NAME_1, |
| mapUrl: "file:///path/to/map")); |
| 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(MAP_WITH_SOURCE_LOCATION_AND_NAME_2, |
| mapUrl: "file:///path/to/map")); |
| 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(MAP_WITH_SOURCE_LOCATION_AND_NAME_3, |
| mapUrl: "file:///path/to/map")); |
| 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(new SourceLocation(0, |
| sourceUrl: Uri.parse('http://localhost/output.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input1.dart")); |
| expect( |
| mapping |
| .spanForLocation(new SourceLocation(0, |
| sourceUrl: Uri.parse('http://localhost/output2.dart'))) |
| .sourceUrl, |
| Uri.parse("file:///path/to/pkg/input2.dart")); |
| expect( |
| mapping |
| .spanForLocation(new 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 [ |
| EXPECTED_MAP, |
| MAP_WITH_NO_SOURCE_LOCATION, |
| MAP_WITH_SOURCE_LOCATION, |
| MAP_WITH_SOURCE_LOCATION_AND_NAME |
| ]) { |
| SingleMapping mapping = parseJson(expected); |
| expect(mapping.toJson(), equals(expected)); |
| |
| mapping = parseJsonExtended(expected); |
| expect(mapping.toJson(), equals(expected)); |
| } |
| // Invalid for this case |
| expect(() => parseJson(SOURCE_MAP_BUNDLE as dynamic), throws); |
| |
| var mapping = parseJsonExtended(SOURCE_MAP_BUNDLE) as MappingBundle; |
| expect(mapping.toJson(), equals(SOURCE_MAP_BUNDLE)); |
| }); |
| |
| group("source files", () { |
| group("from fromEntries()", () { |
| test("are null for non-FileLocations", () { |
| var mapping = new SingleMapping.fromEntries([ |
| new Entry(new SourceLocation(10, line: 1, column: 8), |
| outputVar1.start, null) |
| ]); |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test("use a file location's file", () { |
| var mapping = new SingleMapping.fromEntries( |
| [new 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(EXPECTED_MAP) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test("with null sourcesContent values", () { |
| var map = new Map.from(EXPECTED_MAP); |
| map["sourcesContent"] = [null]; |
| var mapping = parseJson(map) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| |
| test("with a too-short sourcesContent", () { |
| var map = new Map.from(EXPECTED_MAP); |
| map["sourcesContent"] = []; |
| var mapping = parseJson(map) as SingleMapping; |
| expect(mapping.files, equals([null])); |
| }); |
| }); |
| |
| test("are parsed from sourcesContent", () { |
| var map = new Map.from(EXPECTED_MAP); |
| 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!")); |
| }); |
| }); |
| }); |
| } |