blob: 7974d76928d088baa85bd33ea329012376a2cae6 [file]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: implementation_imports
library matchers;
import 'dart:io' as io;
import 'package:devtools_app/src/inspector/diagnostics_node.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:matcher/matcher.dart';
import '../support/constants.dart';
RemoteDiagnosticsNode findNodeMatching(
RemoteDiagnosticsNode node, String text) {
if (node.name?.startsWith(text) == true ||
node.description?.startsWith(text) == true) {
return node;
}
if (node.childrenNow == null) {
return null;
}
for (var child in node.childrenNow) {
final match = findNodeMatching(child, text);
if (match != null) {
return match;
}
}
return null;
}
String treeToDebugString(RemoteDiagnosticsNode node) {
return node.toDiagnosticsNode().toStringDeep();
}
String treeToDebugStringTruncated(RemoteDiagnosticsNode node, int maxLines) {
List<String> lines = node.toDiagnosticsNode().toStringDeep().split('\n');
if (lines.length > maxLines) {
lines = lines.take(maxLines).toList()..add('...');
}
return lines.join('\n');
}
/// Asserts that a [path] matches a golden file after normalizing likely hash
/// codes.
///
/// Paths are assumed to reference files within the `test/goldens` directory.
///
/// To rebaseline all golden files run:
/// ```
/// tool/update_goldens.sh
/// ```
///
/// A `#` followed by 5 hexadecimal digits is assumed to be a short hash code
/// and is normalized to #00000.
///
/// See Also:
///
/// * [equalsIgnoringHashCodes], which does the same thing without the golden
/// file functionality.
Matcher equalsGoldenIgnoringHashCodes(String path) {
return _EqualsGoldenIgnoringHashCodes(path);
}
class _EqualsGoldenIgnoringHashCodes extends Matcher {
_EqualsGoldenIgnoringHashCodes(String pathWithinGoldenDirectory)
: assert(devtoolsTestingPackageRoot != null) {
path =
'$devtoolsTestingPackageRoot/goldens$_goldensSuffix/$pathWithinGoldenDirectory';
try {
_value = _normalize(io.File(path).readAsStringSync());
} catch (e) {
_value = 'Error reading $path: $e';
}
}
String path;
String _value;
static final Object _mismatchedValueKey = Object();
static final String _goldensSuffix =
io.Platform.environment['DEVTOOLS_GOLDENS_SUFFIX'] ?? '';
static bool get updateGoldens => autoUpdateGoldenFiles;
static String _normalize(String s) {
return s.replaceAll(RegExp(r'#[0-9a-f]{5}'), '#00000');
}
@override
bool matches(dynamic object, Map<dynamic, dynamic> matchState) {
final String description = _normalize(object);
if (_value != description) {
if (updateGoldens) {
io.File(path).writeAsStringSync(description);
print('Updated golden file $path\nto\n$description');
// Act like the match succeeded so all goldens are updated instead of
// just the first failure.
return true;
}
matchState[_mismatchedValueKey] = description;
return false;
}
return true;
}
@override
Description describe(Description description) {
return description.add('multi line description equals $_value');
}
@override
Description describeMismatch(dynamic item, Description mismatchDescription,
Map<dynamic, dynamic> matchState, bool verbose) {
if (matchState.containsKey(_mismatchedValueKey)) {
final String actualValue = matchState[_mismatchedValueKey];
// Leading whitespace is added so that lines in the multi-line
// description returned by addDescriptionOf are all indented equally
// which makes the output easier to read for this case.
return mismatchDescription
.add('expected golden file \'$path\' with normalized value\n ')
.addDescriptionOf(_value)
.add('\nbut got\n ')
.addDescriptionOf(actualValue)
.add('\nTo update golden files run:\n')
.add(' tool/update_goldens.sh"\n');
}
return null;
}
}