a6cc772b67
Change-Id: I206a7a8132b5ea79dc019acf5c2e0cd800307bcf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212161 Reviewed-by: Jens Johansen <jensj@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
151 lines
4.6 KiB
Dart
151 lines
4.6 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.md file.
|
|
|
|
// @dart = 2.9
|
|
|
|
library fasta.test.assert_locations_test;
|
|
|
|
import 'package:async_helper/async_helper.dart' show asyncTest;
|
|
|
|
import 'package:expect/expect.dart' show Expect;
|
|
|
|
import 'package:kernel/ast.dart'
|
|
show Component, RecursiveVisitor, Procedure, AssertStatement;
|
|
|
|
import "package:front_end/src/api_prototype/compiler_options.dart"
|
|
show CompilerOptions, DiagnosticMessage;
|
|
|
|
import 'package:front_end/src/testing/compiler_common.dart' show compileScript;
|
|
|
|
/// Span of the condition expression in the assert statement.
|
|
class ConditionSpan {
|
|
final startOffset;
|
|
final endOffset;
|
|
ConditionSpan(this.startOffset, this.endOffset);
|
|
}
|
|
|
|
/// Generated test with multiple functions each containing a single
|
|
/// assertion statement inside. [spans] specifies the mapping
|
|
/// between function name and [ConditionSpan] for an [AssertionStatement]
|
|
/// inside that function.
|
|
class Test {
|
|
final String source;
|
|
final Map<String, ConditionSpan> spans;
|
|
|
|
Test(this.source, this.spans);
|
|
}
|
|
|
|
Test generateTest() {
|
|
final sb = new StringBuffer();
|
|
final spans = new Map<String, ConditionSpan>();
|
|
|
|
// Create a test case for assert statement with the given [condition] and
|
|
// [message]. Argument list would contain a trailing comma if [trailingComma]
|
|
// is [true].
|
|
// [additionalOffset] specifies an offset in characters from the opening
|
|
// parenthesis of the assert statement to the first character of the
|
|
// condition.
|
|
void makeAssertWithMessage(String condition,
|
|
{String message, bool trailingComma: false, int additionalOffset: 0}) {
|
|
final name = 'testCase${spans.length}';
|
|
sb.writeln('void $name(x) {');
|
|
sb.write('assert(');
|
|
final startOffset = sb.length + additionalOffset;
|
|
sb.write(condition);
|
|
final endOffset = sb.length;
|
|
if (message != null) {
|
|
sb.write(', "${message}"');
|
|
}
|
|
if (trailingComma) {
|
|
sb.write(',');
|
|
}
|
|
sb.writeln(');');
|
|
sb.writeln('}');
|
|
spans[name] = new ConditionSpan(startOffset, endOffset);
|
|
}
|
|
|
|
// Create test cases for various variants of the assert statement with
|
|
// the given condition.
|
|
void makeAssert(String condition, {int additionalOffset: 0}) {
|
|
makeAssertWithMessage(condition, additionalOffset: additionalOffset);
|
|
makeAssertWithMessage(condition,
|
|
trailingComma: true, additionalOffset: additionalOffset);
|
|
makeAssertWithMessage(condition,
|
|
message: 'message message', additionalOffset: additionalOffset);
|
|
makeAssertWithMessage(condition,
|
|
message: 'message message',
|
|
trailingComma: true,
|
|
additionalOffset: additionalOffset);
|
|
}
|
|
|
|
// Create all test cases.
|
|
makeAssert('''
|
|
|
|
(
|
|
x != null
|
|
)''', additionalOffset: 3);
|
|
makeAssert('''(x != null)''');
|
|
makeAssert('''x''');
|
|
makeAssert('''((x))''');
|
|
makeAssert('''!x''');
|
|
makeAssert('''((!x))''');
|
|
makeAssert('''x.method("a", "b")''');
|
|
|
|
// Add a dummy main to avoid compilation errors.
|
|
sb.writeln('''
|
|
void main() {}
|
|
''');
|
|
|
|
return new Test(sb.toString(), spans);
|
|
}
|
|
|
|
/// Visitor that verifies that all [AssertStatement]s in the Kernel AST
|
|
/// have expected spans for their conditions.
|
|
class VerifyingVisitor extends RecursiveVisitor {
|
|
final Test test;
|
|
|
|
/// Set of names of verified [Procedure]s.
|
|
final Set<String> verified = new Set<String>();
|
|
|
|
/// When [AssertStatement] is reached it is checked against this
|
|
/// span.
|
|
ConditionSpan expectedSpan;
|
|
|
|
VerifyingVisitor(this.test);
|
|
|
|
@override
|
|
void visitProcedure(Procedure node) {
|
|
expectedSpan = test.spans[node.name.text];
|
|
if (expectedSpan != null) {
|
|
super.visitProcedure(node);
|
|
verified.add(node.name.text);
|
|
expectedSpan = null;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void visitAssertStatement(AssertStatement node) {
|
|
Expect.equals(expectedSpan.startOffset, node.conditionStartOffset);
|
|
Expect.equals(expectedSpan.endOffset, node.conditionEndOffset);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
asyncTest(() async {
|
|
Test test = generateTest();
|
|
CompilerOptions options = new CompilerOptions()
|
|
..onDiagnostic = (DiagnosticMessage message) {
|
|
Expect.fail(
|
|
"Unexpected message: ${message.plainTextFormatted.join('\n')}");
|
|
};
|
|
Component p = (await compileScript(test.source,
|
|
options: options, fileName: 'synthetic-test.dart'))
|
|
?.component;
|
|
Expect.isNotNull(p);
|
|
VerifyingVisitor visitor = new VerifyingVisitor(test);
|
|
p.mainMethod.enclosingLibrary.accept(visitor);
|
|
Expect.setEquals(test.spans.keys, visitor.verified);
|
|
});
|
|
}
|