| // Copyright (c) 2017, 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. |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/error/error.dart'; |
| import 'package:analyzer/src/dart/ast/utilities.dart'; |
| import 'package:test/test.dart'; |
| |
| import '../../../generated/parser_fasta_test.dart'; |
| |
| /** |
| * The base class for tests that test how well the parser recovers from various |
| * syntactic errors. |
| */ |
| abstract class AbstractRecoveryTest extends FastaParserTestCase { |
| void testRecovery( |
| String invalidCode, List<ErrorCode> errorCodes, String validCode) { |
| CompilationUnit invalidUnit = parseCompilationUnit(invalidCode, errorCodes); |
| CompilationUnit validUnit = parseCompilationUnit(validCode); |
| ResultComparator.compare(invalidUnit, validUnit); |
| } |
| } |
| |
| /** |
| * An object used to compare to AST structures and cause the test to fail if |
| * they differ in any important ways. |
| */ |
| class ResultComparator extends AstComparator { |
| bool failDifferentLength(List first, List second) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.write('Expected a list of length '); |
| buffer.write(second.length); |
| buffer.write('; found a list of length '); |
| buffer.writeln(first.length); |
| if (first is NodeList) { |
| _safelyWriteNodePath(buffer, first.owner); |
| } |
| fail(buffer.toString()); |
| return false; |
| } |
| |
| @override |
| bool failIfNotNull(Object first, Object second) { |
| if (second != null) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.write('Expected null; found a '); |
| buffer.writeln(second.runtimeType); |
| if (second is AstNode) { |
| _safelyWriteNodePath(buffer, second); |
| } |
| fail(buffer.toString()); |
| } |
| return true; |
| } |
| |
| @override |
| bool failIsNull(Object first, Object second) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.write('Expected a '); |
| buffer.write(first.runtimeType); |
| buffer.writeln('; found null'); |
| if (first is AstNode) { |
| _safelyWriteNodePath(buffer, first); |
| } |
| fail(buffer.toString()); |
| return false; |
| } |
| |
| @override |
| bool failRuntimeType(Object first, Object second) { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.write('Expected a '); |
| buffer.writeln(second.runtimeType); |
| buffer.write('; found '); |
| buffer.writeln(first.runtimeType); |
| if (first is AstNode) { |
| _safelyWriteNodePath(buffer, first); |
| } |
| fail(buffer.toString()); |
| return false; |
| } |
| |
| /** |
| * Overridden to allow the valid code to contain an explicit identifier where |
| * a synthetic identifier is expected to be inserted by recovery. |
| */ |
| @override |
| bool isEqualNodes(AstNode first, AstNode second) { |
| if (first is SimpleIdentifier && second is SimpleIdentifier) { |
| if (first.isSynthetic && second.name == '_s_') { |
| return true; |
| } |
| } |
| return super.isEqualNodes(first, second); |
| } |
| |
| /** |
| * Overridden to ignore the offsets of tokens because these can legitimately |
| * be different. |
| */ |
| @override |
| bool isEqualTokensNotNull(Token first, Token second) => |
| first.length == second.length && first.lexeme == second.lexeme; |
| |
| void _safelyWriteNodePath(StringBuffer buffer, AstNode node) { |
| buffer.write(' path: '); |
| if (node == null) { |
| buffer.write(' null'); |
| } else { |
| _writeNodePath(buffer, node); |
| } |
| } |
| |
| void _writeNodePath(StringBuffer buffer, AstNode node) { |
| AstNode parent = node.parent; |
| if (parent != null) { |
| _writeNodePath(buffer, parent); |
| buffer.write(', '); |
| } |
| buffer.write(node.runtimeType); |
| } |
| |
| /** |
| * Compare the [first] and [second] nodes, failing the test if they are |
| * different. |
| */ |
| static void compare(AstNode first, AstNode second) { |
| ResultComparator comparator = new ResultComparator(); |
| comparator.isEqualNodes(first, second); |
| } |
| } |