20faaa5d94
Change-Id: Ib18f554c1076f27a3f7c0df5a36410da41a1f467 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148784 Reviewed-by: Paul Berry <paulberry@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com>
160 lines
5.7 KiB
Dart
160 lines
5.7 KiB
Dart
// Copyright (c) 2018, 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.
|
|
|
|
// @dart = 2.7
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'dart:convert';
|
|
|
|
import 'package:args/args.dart';
|
|
import 'package:async_helper/async_helper.dart';
|
|
import 'package:compiler/src/commandline_options.dart';
|
|
import 'package:dart2js_tools/src/dart2js_mapping.dart';
|
|
|
|
import '../helpers/d8_helper.dart';
|
|
import '../helpers/memory_compiler.dart';
|
|
import 'package:expect/expect.dart';
|
|
|
|
void main(List<String> args) {
|
|
ArgParser argParser = new ArgParser(allowTrailingOptions: true);
|
|
argParser.addFlag('continued', abbr: 'c', defaultsTo: false);
|
|
ArgResults argResults = argParser.parse(args);
|
|
Directory dataDir =
|
|
new Directory.fromUri(Platform.script.resolve('minified'));
|
|
print('Input folder: ${dataDir.uri}');
|
|
asyncTest(() async {
|
|
bool continuing = false;
|
|
await for (FileSystemEntity entity in dataDir.list()) {
|
|
String name = entity.uri.pathSegments.last;
|
|
if (!name.endsWith('.dart')) continue;
|
|
if (argResults.rest.isNotEmpty &&
|
|
!argResults.rest.contains(name) &&
|
|
!continuing) {
|
|
continue;
|
|
}
|
|
print('\ninput $name');
|
|
await runTest(await new File.fromUri(entity.uri).readAsString());
|
|
if (argResults['continued']) continuing = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Object to hold the expectations of a individual minified-name test.
|
|
class MinifiedNameTest {
|
|
/// Pattern used to find a minified name in the error message.
|
|
final RegExp pattern;
|
|
|
|
/// The kind of minified name, it can be global, instance, or other
|
|
/// (the first two correspond to the two namespaces that contain extra data in
|
|
/// the source-map file).
|
|
final String _kind;
|
|
|
|
/// Whether the minified name is from the global namespace.
|
|
bool get isGlobal => _kind == 'global';
|
|
|
|
/// Whether the minified name is from the instance namespace.
|
|
bool get isInstance => _kind == 'instance';
|
|
|
|
/// The deobfuscated name we expect to find.
|
|
final String expectedName;
|
|
|
|
/// The actual test code.
|
|
final String code;
|
|
|
|
MinifiedNameTest(this.pattern, this._kind, this.expectedName, this.code);
|
|
}
|
|
|
|
RegExp _patternMatcher = new RegExp("// Error pattern: (.*)\n");
|
|
RegExp _kindMatcher = new RegExp("// Kind of minified name: (.*)\n");
|
|
RegExp _nameMatcher = new RegExp("// Expected deobfuscated name: (.*)\n");
|
|
|
|
Future runTest(String code) async {
|
|
var patternMatch = _patternMatcher.firstMatch(code);
|
|
Expect.isNotNull(patternMatch, "Could not find the error pattern.");
|
|
var pattern = new RegExp(patternMatch.group(1));
|
|
var kindMatch = _kindMatcher.firstMatch(code);
|
|
Expect.isNotNull(kindMatch, "Could not find the expected minified kind.");
|
|
var kind = kindMatch.group(1);
|
|
|
|
// TODO(sigmund): add support for "other" when we encode symbol information
|
|
// directly for each field and local variable.
|
|
const validKinds = const ['global', 'instance'];
|
|
Expect.isTrue(validKinds.contains(kind),
|
|
"Invalid kind: $kind, please use one of $validKinds");
|
|
|
|
var nameMatch = _nameMatcher.firstMatch(code);
|
|
Expect.isNotNull(nameMatch, "Could not find the expected deobfuscated name.");
|
|
var expectedName = nameMatch.group(1);
|
|
var test = new MinifiedNameTest(pattern, kind, expectedName, code);
|
|
print('expectations: ${pattern.pattern} $kind $expectedName');
|
|
await checkExpectation(test, false);
|
|
await checkExpectation(test, true);
|
|
}
|
|
|
|
checkExpectation(MinifiedNameTest test, bool minified) async {
|
|
print('-- ${minified ? 'minified' : 'not-minified'}:');
|
|
var options = [
|
|
Flags.testMode,
|
|
'--libraries-spec=$sdkLibrariesSpecificationUri',
|
|
if (minified) Flags.minify,
|
|
];
|
|
D8Result result = await runWithD8(
|
|
memorySourceFiles: {'main.dart': test.code}, options: options);
|
|
String stdout = result.runResult.stdout;
|
|
String error = _extractError(stdout);
|
|
print(' error: $error');
|
|
Expect.isNotNull(error, 'Couldn\'t find the error message in $stdout');
|
|
|
|
var match = test.pattern.firstMatch(error);
|
|
Expect.isNotNull(
|
|
match,
|
|
'Error didn\'t match the test pattern'
|
|
'\nerror: $error\npattern:${test.pattern}');
|
|
var name = match.group(1);
|
|
print(' obfuscated-name: $name');
|
|
Expect.isNotNull(name, 'Error didn\'t contain a name\nerror: $error');
|
|
|
|
if (name.startsWith('minified:')) {
|
|
name = name.substring(9);
|
|
}
|
|
|
|
var sourceMap = '${result.outputPath}.map';
|
|
var json = jsonDecode(await new File(sourceMap).readAsString());
|
|
|
|
var mapping = Dart2jsMapping.json(json);
|
|
Expect.isTrue(mapping.globalNames.isNotEmpty,
|
|
"Source-map doesn't contain minified-names");
|
|
|
|
var actualName;
|
|
if (test.isGlobal) {
|
|
actualName = mapping.globalNames[name];
|
|
Expect.isNotNull(actualName, "'$name' not in global name map");
|
|
} else if (test.isInstance) {
|
|
// In non-minified mode some errors show the original name
|
|
// rather than the selector name (e.g. m1 instead of m1$0 in a
|
|
// NoSuchMethodError), and because of that the name might not be on the
|
|
// table.
|
|
//
|
|
// TODO(sigmund): consider making all errors show the internal name, or
|
|
// include a marker to make it easier to distinguish.
|
|
actualName = mapping.instanceNames[name] ?? name;
|
|
} else {
|
|
Expect.fail('unexpected');
|
|
}
|
|
print(' actual-name: $actualName');
|
|
Expect.equals(test.expectedName, actualName);
|
|
print(' PASS!!');
|
|
}
|
|
|
|
/// Returns the portion of the output that corresponds to the error message.
|
|
///
|
|
/// Note: some errors can span multiple lines.
|
|
String _extractError(String stdout) {
|
|
var firstStackFrame = stdout.indexOf('\n at');
|
|
if (firstStackFrame == -1) return null;
|
|
var errorMarker = stdout.indexOf('^') + 1;
|
|
return stdout.substring(errorMarker, firstStackFrame).trim();
|
|
}
|