| // Copyright (c) 2022, 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 'dart:io' as io; |
| |
| import 'package:analyzer/source/line_info.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| class NodeTextExpectationsCollector { |
| static const updatingIsEnabled = false; |
| |
| static const assertMethods = { |
| 'ResolutionTest.assertResolvedNodeText', |
| }; |
| |
| static final Map<String, _File> _files = {}; |
| |
| static void add(String actual) { |
| if (!updatingIsEnabled) { |
| return; |
| } |
| |
| var traceLines = '${StackTrace.current}'.split('\n'); |
| for (var traceIndex = 0; traceIndex < traceLines.length; traceIndex++) { |
| var traceLine = traceLines[traceIndex]; |
| for (var assertMethod in assertMethods) { |
| if (traceLine.contains(' $assertMethod ')) { |
| var invocationLine = traceLines[traceIndex + 1]; |
| var locationMatch = RegExp( |
| r'file://(.+_test.dart):(\d+):', |
| ).firstMatch(invocationLine); |
| if (locationMatch == null) { |
| fail('Cannot parse: $invocationLine'); |
| } |
| |
| var path = locationMatch.group(1)!; |
| var line = int.parse(locationMatch.group(2)!); |
| var file = _getFile(path); |
| |
| var invocationOffset = file.lineInfo.getOffsetOfLine(line - 1); |
| |
| const String rawStringPrefix = "r'''"; |
| var expectationOffset = file.content.indexOf( |
| rawStringPrefix, |
| invocationOffset, |
| ); |
| expectationOffset += rawStringPrefix.length; |
| var expectationEnd = file.content.indexOf("'''", expectationOffset); |
| |
| file.replacements.add( |
| _Replacement( |
| expectationOffset, |
| expectationEnd, |
| '\n$actual', |
| ), |
| ); |
| } |
| } |
| } |
| } |
| |
| static void _apply() { |
| for (var file in _files.values) { |
| file.applyReplacements(); |
| } |
| _files.clear(); |
| } |
| |
| static _File _getFile(String path) { |
| return _files[path] ??= _File(path); |
| } |
| } |
| |
| @reflectiveTest |
| class UpdateNodeTextExpectations { |
| test_applyReplacements() { |
| NodeTextExpectationsCollector._apply(); |
| } |
| } |
| |
| class _File { |
| final String path; |
| final String content; |
| final LineInfo lineInfo; |
| final List<_Replacement> replacements = []; |
| |
| factory _File(String path) { |
| var content = io.File(path).readAsStringSync(); |
| return _File._( |
| path: path, |
| content: content, |
| lineInfo: LineInfo.fromContent(content), |
| ); |
| } |
| |
| _File._({ |
| required this.path, |
| required this.content, |
| required this.lineInfo, |
| }); |
| |
| void applyReplacements() { |
| replacements.sort((a, b) => b.offset - a.offset); |
| var newCode = content; |
| for (var replacement in replacements) { |
| newCode = newCode.substring(0, replacement.offset) + |
| replacement.text + |
| newCode.substring(replacement.end); |
| } |
| io.File(path).writeAsStringSync(newCode); |
| } |
| } |
| |
| class _Replacement { |
| final int offset; |
| final int end; |
| final String text; |
| |
| _Replacement(this.offset, this.end, this.text); |
| } |