blob: 4ec75d0dc537c5d1ed517b52cce68559171210c6 [file] [log] [blame]
// 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.
/// Visualization of source mappings generated and tested in
/// 'source_mapping_test.dart'.
library source_mapping.test.viewer;
import 'dart:async';
import 'package:_fe_analyzer_shared/src/util/filenames.dart';
import '../helpers/sourcemap_helper.dart';
import '../helpers/sourcemap_html_helper.dart';
import '../helpers/sourcemap_html_templates.dart';
import 'source_mapping_tester.dart';
const String DEFAULT_OUTPUT_PATH = 'out.js.map.html';
main(List<String> arguments) async {
bool measure = false;
bool missingOnly = false;
String outputPath = DEFAULT_OUTPUT_PATH;
Set<String> configurations = Set<String>();
Map<String, Uri> tests = <String, Uri>{};
for (String argument in arguments) {
if (argument.startsWith('-')) {
if (argument == '-m') {
// Measure instead of reporting the number of missing code points.
measure = true;
} else if (argument.startsWith('--out=')) {
// Generate visualization for the first configuration.
outputPath = argument.substring('--out='.length);
} else if (argument.startsWith('-o')) {
// Generate visualization for the first configuration.
outputPath = argument.substring('-o'.length);
} else if (argument == '--missing') {
missingOnly = true;
} else if (argument == '--file' || argument == '--exclude') {
// Handled by [parseArguments].
} else {
print("Unknown option '$argument'.");
return;
}
}
}
if (!parseArguments(arguments, configurations, tests, measure: measure)) {
return;
}
OutputConfigurations outputConfigurations = OutputConfigurations(
configurations,
tests.keys,
);
bool generateMultiConfigs = false;
if (configurations.length > 1 || tests.length > 1) {
for (String config in configurations) {
for (String file in tests.keys) {
String path = '$outputPath.$config.$file';
Uri uri = Uri.base.resolve(nativeToUriPath(path));
outputConfigurations.registerPathUri(config, file, path, uri);
}
}
generateMultiConfigs = true;
} else {
outputConfigurations.registerPathUri(
configurations.first,
tests.keys.first,
outputPath,
Uri.base.resolve(nativeToUriPath(outputPath)),
);
}
List<Measurement> measurements = <Measurement>[];
for (String config in configurations) {
for (String file in tests.keys) {
List<String> options = TEST_CONFIGURATIONS[config]!;
Measurement measurement = await runTest(
config,
file,
tests[file]!,
options,
outputUri: outputConfigurations.getUri(config, file),
verbose: !measure,
missingOnly: missingOnly,
);
measurements.add(measurement);
}
}
for (Measurement measurement in measurements) {
print(measurement);
}
if (generateMultiConfigs) {
outputMultiConfigs(Uri.base.resolve(outputPath), outputConfigurations);
}
}
class OutputConfigurations implements Configurations {
@override
final Iterable<String> configs;
@override
final Iterable<String> files;
final Map<(String, String), String> pathMap = {};
final Map<(String, String), Uri> uriMap = {};
OutputConfigurations(this.configs, this.files);
void registerPathUri(String config, String file, String path, Uri uri) {
var key = (config, file);
pathMap[key] = path;
uriMap[key] = uri;
}
Uri? getUri(String config, String file) => uriMap[(config, file)];
@override
String getPath(String config, String file) => pathMap[(config, file)]!;
}
Future<Measurement> runTest(
String config,
String filename,
Uri uri,
List<String> options, {
Uri? outputUri,
required bool verbose,
bool missingOnly = false,
}) async {
TestResult result = await runTests(
config,
filename,
uri,
options,
verbose: verbose,
);
if (outputUri != null) {
if (result.missingCodePointsMap.isNotEmpty) {
result.printMissingCodePoints();
}
if (result.multipleNodesMap.isNotEmpty) {
result.printMultipleNodes();
}
if (result.multipleOffsetsMap.isNotEmpty) {
result.printMultipleOffsets();
}
List<SourceMapInfo> infoList = result.userInfoList;
if (missingOnly) {
infoList = infoList
.where((info) => result.missingCodePointsMap.containsKey(info))
.toList();
}
createTraceSourceMapHtml(outputUri, result.processor, infoList);
}
return Measurement(
config,
filename,
result.missingCodePointsMap.values.fold(0, (s, i) => s + i.length),
result.userInfoList.fold(0, (s, i) => s + i.codePoints.length),
);
}
class Measurement {
final String config;
final String filename;
final int missing;
final int count;
Measurement(this.config, this.filename, this.missing, this.count);
@override
String toString() {
double percentage = 100 * missing / count;
return "Config '${config}', file: '${filename}': "
"$missing of $count ($percentage%) missing";
}
}