Update equalsIgnoringHashCodes to take a list of Strings (#108507)
This commit is contained in:
@@ -64,13 +64,18 @@ void main() {
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))');
|
||||
expect(description[1], 'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))');
|
||||
expect(description[2], 'checkColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[3], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))');
|
||||
expect(description[4], 'splashRadius: 1.0');
|
||||
expect(description[5], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
|
||||
expect(description[6], equalsIgnoringHashCodes('visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)'));
|
||||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
||||
'checkColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff2))',
|
||||
'splashRadius: 1.0',
|
||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Checkbox is themeable', (WidgetTester tester) async {
|
||||
|
||||
@@ -2276,30 +2276,35 @@ void main() {
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'leading: Text');
|
||||
expect(description[1], 'title: Text');
|
||||
expect(description[2], 'subtitle: Text');
|
||||
expect(description[3], 'trailing: Text');
|
||||
expect(description[4], 'isThreeLine: THREE_LINE');
|
||||
expect(description[5], 'dense: true');
|
||||
expect(description[6], equalsIgnoringHashCodes('visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)'));
|
||||
expect(description[7], 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)');
|
||||
expect(description[8], 'style: ListTileStyle.list');
|
||||
expect(description[9], 'selectedColor: Color(0xff0000ff)');
|
||||
expect(description[10], 'iconColor: Color(0xff00ff00)');
|
||||
expect(description[11], 'textColor: Color(0xffff0000)');
|
||||
expect(description[12], 'contentPadding: EdgeInsets.zero');
|
||||
expect(description[13], 'enabled: false');
|
||||
expect(description[14], 'selected: true');
|
||||
expect(description[15], 'focusColor: Color(0xff00ffff)');
|
||||
expect(description[16], 'hoverColor: Color(0xff0000ff)');
|
||||
expect(description[17], 'autofocus: true');
|
||||
expect(description[18], 'tileColor: Color(0xffffff00)');
|
||||
expect(description[19], 'selectedTileColor: Color(0xff123456)');
|
||||
expect(description[20], 'enableFeedback: false');
|
||||
expect(description[21], 'horizontalTitleGap: 4.0');
|
||||
expect(description[22], 'minVerticalPadding: 2.0');
|
||||
expect(description[23], 'minLeadingWidth: 6.0');
|
||||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'leading: Text',
|
||||
'title: Text',
|
||||
'subtitle: Text',
|
||||
'trailing: Text',
|
||||
'isThreeLine: THREE_LINE',
|
||||
'dense: true',
|
||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||
'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.zero)',
|
||||
'style: ListTileStyle.list',
|
||||
'selectedColor: Color(0xff0000ff)',
|
||||
'iconColor: Color(0xff00ff00)',
|
||||
'textColor: Color(0xffff0000)',
|
||||
'contentPadding: EdgeInsets.zero',
|
||||
'enabled: false',
|
||||
'selected: true',
|
||||
'focusColor: Color(0xff00ffff)',
|
||||
'hoverColor: Color(0xff0000ff)',
|
||||
'autofocus: true',
|
||||
'tileColor: Color(0xffffff00)',
|
||||
'selectedTileColor: Color(0xff123456)',
|
||||
'enableFeedback: false',
|
||||
'horizontalTitleGap: 4.0',
|
||||
'minVerticalPadding: 2.0',
|
||||
'minLeadingWidth: 6.0',
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
group('Material 2', () {
|
||||
|
||||
@@ -107,23 +107,25 @@ void main() {
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'dense: true');
|
||||
expect(description[1], 'shape: StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))');
|
||||
expect(description[2], 'style: drawer');
|
||||
expect(description[3], 'selectedColor: Color(0x00000001)');
|
||||
expect(description[4], 'iconColor: Color(0x00000002)');
|
||||
expect(description[5], 'textColor: Color(0x00000003)');
|
||||
expect(description[6], 'contentPadding: EdgeInsets.all(100.0)');
|
||||
expect(description[7], 'tileColor: Color(0x00000004)');
|
||||
expect(description[8], 'selectedTileColor: Color(0x00000005)');
|
||||
expect(description[9], 'horizontalTitleGap: 200.0');
|
||||
expect(description[10], 'minVerticalPadding: 300.0');
|
||||
expect(description[11], 'minLeadingWidth: 400.0');
|
||||
expect(description[12], 'enableFeedback: true');
|
||||
expect(description[13], 'mouseCursor: MaterialStateMouseCursor(clickable)');
|
||||
expect(
|
||||
description[14],
|
||||
equalsIgnoringHashCodes('visualDensity: VisualDensity#00000(h: -1.0, v: -1.0)(horizontal: -1.0, vertical: -1.0)'),
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'dense: true',
|
||||
'shape: StadiumBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none))',
|
||||
'style: drawer',
|
||||
'selectedColor: Color(0x00000001)',
|
||||
'iconColor: Color(0x00000002)',
|
||||
'textColor: Color(0x00000003)',
|
||||
'contentPadding: EdgeInsets.all(100.0)',
|
||||
'tileColor: Color(0x00000004)',
|
||||
'selectedTileColor: Color(0x00000005)',
|
||||
'horizontalTitleGap: 200.0',
|
||||
'minVerticalPadding: 300.0',
|
||||
'minLeadingWidth: 400.0',
|
||||
'enableFeedback: true',
|
||||
'mouseCursor: MaterialStateMouseCursor(clickable)',
|
||||
'visualDensity: VisualDensity#00000(h: -1.0, v: -1.0)(horizontal: -1.0, vertical: -1.0)',
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -61,12 +61,17 @@ void main() {
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description[0], 'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))');
|
||||
expect(description[1], 'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))');
|
||||
expect(description[2], 'overlayColor: MaterialStatePropertyAll(Color(0xfffffff1))');
|
||||
expect(description[3], 'splashRadius: 1.0');
|
||||
expect(description[4], 'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap');
|
||||
expect(description[5], equalsIgnoringHashCodes('visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)'));
|
||||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'mouseCursor: MaterialStatePropertyAll(SystemMouseCursor(click))',
|
||||
'fillColor: MaterialStatePropertyAll(Color(0xfffffff0))',
|
||||
'overlayColor: MaterialStatePropertyAll(Color(0xfffffff1))',
|
||||
'splashRadius: 1.0',
|
||||
'materialTapTargetSize: MaterialTapTargetSize.shrinkWrap',
|
||||
'visualDensity: VisualDensity#00000(h: 0.0, v: 0.0)',
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Radio is themeable', (WidgetTester tester) async {
|
||||
|
||||
@@ -1009,8 +1009,13 @@ void main() {
|
||||
.toList();
|
||||
|
||||
expect(description.length, equals(2));
|
||||
expect(description[0], equalsIgnoringHashCodes('dispatcher: ActionDispatcher#00000'));
|
||||
expect(description[1], equals('actions: {}'));
|
||||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'dispatcher: ActionDispatcher#00000',
|
||||
'actions: {}',
|
||||
]),
|
||||
);
|
||||
});
|
||||
testWidgets('Actions implements debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
@@ -1032,8 +1037,13 @@ void main() {
|
||||
.toList();
|
||||
|
||||
expect(description.length, equals(2));
|
||||
expect(description[0], equalsIgnoringHashCodes('dispatcher: ActionDispatcher#00000'));
|
||||
expect(description[1], equalsIgnoringHashCodes('actions: {TestIntent: TestAction#00000}'));
|
||||
expect(
|
||||
description,
|
||||
equalsIgnoringHashCodes(<String>[
|
||||
'dispatcher: ActionDispatcher#00000',
|
||||
'actions: {TestIntent: TestAction#00000}',
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -292,11 +292,14 @@ Matcher offsetMoreOrLessEquals(Offset value, { double epsilon = precisionErrorTo
|
||||
return _IsWithinDistance<Offset>(_offsetDistance, value, epsilon);
|
||||
}
|
||||
|
||||
/// Asserts that two [String]s are equal after normalizing likely hash codes.
|
||||
/// Asserts that two [String]s or `Iterable<String>`s are equal after
|
||||
/// normalizing likely hash codes.
|
||||
///
|
||||
/// A `#` followed by 5 hexadecimal digits is assumed to be a short hash code
|
||||
/// and is normalized to `#00000`.
|
||||
///
|
||||
/// Only [String] or `Iterable<String>` are allowed types for `value`.
|
||||
///
|
||||
/// See Also:
|
||||
///
|
||||
/// * [describeIdentity], a method that generates short descriptions of objects
|
||||
@@ -305,7 +308,8 @@ Matcher offsetMoreOrLessEquals(Offset value, { double epsilon = precisionErrorTo
|
||||
/// [String] based on [Object.hashCode].
|
||||
/// * [DiagnosticableTree.toStringDeep], a method that returns a [String]
|
||||
/// typically containing multiple hash codes.
|
||||
Matcher equalsIgnoringHashCodes(String value) {
|
||||
Matcher equalsIgnoringHashCodes(Object value) {
|
||||
assert(value is String || value is Iterable<String>, "Only String or Iterable<String> are allowed types for equalsIgnoringHashCodes, it doesn't accept ${value.runtimeType}");
|
||||
return _EqualsIgnoringHashCodes(value);
|
||||
}
|
||||
|
||||
@@ -1056,21 +1060,33 @@ class _HasOneLineDescription extends Matcher {
|
||||
}
|
||||
|
||||
class _EqualsIgnoringHashCodes extends Matcher {
|
||||
_EqualsIgnoringHashCodes(String v) : _value = _normalize(v);
|
||||
_EqualsIgnoringHashCodes(Object v) : _value = _normalize(v);
|
||||
|
||||
final String _value;
|
||||
final Object _value;
|
||||
|
||||
static final Object _mismatchedValueKey = Object();
|
||||
|
||||
static String _normalize(String s) {
|
||||
return s.replaceAll(RegExp(r'#[0-9a-fA-F]{5}'), '#00000');
|
||||
static String _normalizeString(String value) {
|
||||
return value.replaceAll(RegExp(r'#[\da-fA-F]{5}'), '#00000');
|
||||
}
|
||||
|
||||
static Object _normalize(Object value, {bool expected = true}) {
|
||||
if (value is String) {
|
||||
return _normalizeString(value);
|
||||
}
|
||||
if (value is Iterable<String>) {
|
||||
return value.map<String>((dynamic item) => _normalizeString(item.toString()));
|
||||
}
|
||||
throw ArgumentError('The specified ${expected ? 'expected' : 'comparison'} value for '
|
||||
'equalsIgnoringHashCodes must be a String or an Iterable<String>, '
|
||||
'not a ${value.runtimeType}');
|
||||
}
|
||||
|
||||
@override
|
||||
bool matches(dynamic object, Map<dynamic, dynamic> matchState) {
|
||||
final String description = _normalize(object as String);
|
||||
if (_value != description) {
|
||||
matchState[_mismatchedValueKey] = description;
|
||||
final Object normalized = _normalize(object as Object, expected: false);
|
||||
if (!equals(_value).matches(normalized, matchState)) {
|
||||
matchState[_mismatchedValueKey] = normalized;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1078,7 +1094,10 @@ class _EqualsIgnoringHashCodes extends Matcher {
|
||||
|
||||
@override
|
||||
Description describe(Description description) {
|
||||
return description.add('multi line description equals $_value');
|
||||
if (_value is String) {
|
||||
return description.add('normalized value matches $_value');
|
||||
}
|
||||
return description.add('normalized value matches\n').addDescriptionOf(_value);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1089,14 +1108,14 @@ class _EqualsIgnoringHashCodes extends Matcher {
|
||||
bool verbose,
|
||||
) {
|
||||
if (matchState.containsKey(_mismatchedValueKey)) {
|
||||
final String actualValue = matchState[_mismatchedValueKey] as String;
|
||||
final Object actualValue = matchState[_mismatchedValueKey] as Object;
|
||||
// Leading whitespace is added so that lines in the multiline
|
||||
// description returned by addDescriptionOf are all indented equally
|
||||
// which makes the output easier to read for this case.
|
||||
return mismatchDescription
|
||||
.add('expected normalized value\n ')
|
||||
.add('was expected to be normalized value\n')
|
||||
.addDescriptionOf(_value)
|
||||
.add('\nbut got\n ')
|
||||
.add('\nbut got\n')
|
||||
.addDescriptionOf(actualValue);
|
||||
}
|
||||
return mismatchDescription;
|
||||
@@ -1164,11 +1183,11 @@ class _HasGoodToStringDeep extends Matcher {
|
||||
for (int i = 0; i < lines.length; ++i) {
|
||||
final String line = lines[i];
|
||||
if (line.isEmpty) {
|
||||
issues.add('Line ${i+1} is empty.');
|
||||
issues.add('Line ${i + 1} is empty.');
|
||||
}
|
||||
|
||||
if (line.trimRight() != line) {
|
||||
issues.add('Line ${i+1} has trailing whitespace.');
|
||||
issues.add('Line ${i + 1} has trailing whitespace.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,11 +1198,11 @@ class _HasGoodToStringDeep extends Matcher {
|
||||
// If a toStringDeep method doesn't properly handle nested values that
|
||||
// contain line breaks it can fail to add the required prefixes to all
|
||||
// lined when toStringDeep is called specifying prefixes.
|
||||
const String prefixLineOne = 'PREFIX_LINE_ONE____';
|
||||
const String prefixLineOne = 'PREFIX_LINE_ONE____';
|
||||
const String prefixOtherLines = 'PREFIX_OTHER_LINES_';
|
||||
final List<String> prefixIssues = <String>[];
|
||||
String descriptionWithPrefixes =
|
||||
object.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines) as String; // ignore: avoid_dynamic_calls
|
||||
// ignore: avoid_dynamic_calls
|
||||
String descriptionWithPrefixes = object.toStringDeep(prefixLineOne: prefixLineOne, prefixOtherLines: prefixOtherLines) as String;
|
||||
if (descriptionWithPrefixes.endsWith('\n')) {
|
||||
// Trim off trailing \n as the remaining calculations assume
|
||||
// the description does not end with a trailing \n.
|
||||
@@ -1197,7 +1216,7 @@ class _HasGoodToStringDeep extends Matcher {
|
||||
|
||||
for (int i = 1; i < linesWithPrefixes.length; ++i) {
|
||||
if (!linesWithPrefixes[i].startsWith(prefixOtherLines)) {
|
||||
prefixIssues.add('Line ${i+1} does not contain the expected prefix.');
|
||||
prefixIssues.add('Line ${i + 1} does not contain the expected prefix.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1979,9 +1998,9 @@ int _countDifferentPixels(Uint8List imageA, Uint8List imageB) {
|
||||
int delta = 0;
|
||||
for (int i = 0; i < imageA.length; i+=4) {
|
||||
if (imageA[i] != imageB[i] ||
|
||||
imageA[i+1] != imageB[i+1] ||
|
||||
imageA[i+2] != imageB[i+2] ||
|
||||
imageA[i+3] != imageB[i+3]) {
|
||||
imageA[i + 1] != imageB[i + 1] ||
|
||||
imageA[i + 2] != imageB[i + 2] ||
|
||||
imageA[i + 3] != imageB[i + 3]) {
|
||||
delta++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeHashCodesEquals', () {
|
||||
test('equalsIgnoringHashCodes', () {
|
||||
expect('Foo#34219', equalsIgnoringHashCodes('Foo#00000'));
|
||||
expect('Foo#34219', equalsIgnoringHashCodes('Foo#12345'));
|
||||
expect('Foo#34219', equalsIgnoringHashCodes('Foo#abcdf'));
|
||||
@@ -173,6 +173,24 @@ void main() {
|
||||
expect('Foo#', isNot(equalsIgnoringHashCodes('Foo#00000')));
|
||||
expect('Foo#3421', isNot(equalsIgnoringHashCodes('Foo#00000')));
|
||||
expect('Foo#342193', isNot(equalsIgnoringHashCodes('Foo#00000')));
|
||||
expect(<String>['Foo#a3b4d'], equalsIgnoringHashCodes(<String>['Foo#12345']));
|
||||
expect(
|
||||
<String>['Foo#a3b4d', 'Foo#12345'],
|
||||
equalsIgnoringHashCodes(<String>['Foo#00000', 'Foo#00000']),
|
||||
);
|
||||
expect(
|
||||
<String>['Foo#a3b4d', 'Bar#12345'],
|
||||
equalsIgnoringHashCodes(<String>['Foo#00000', 'Bar#00000']),
|
||||
);
|
||||
expect(
|
||||
<String>['Foo#a3b4d', 'Bar#12345'],
|
||||
isNot(equalsIgnoringHashCodes(<String>['Bar#00000', 'Foo#00000'])),
|
||||
);
|
||||
expect(<String>['Foo#a3b4d'], isNot(equalsIgnoringHashCodes(<String>['Foo'])));
|
||||
expect(
|
||||
<String>['Foo#a3b4d'],
|
||||
isNot(equalsIgnoringHashCodes(<String>['Foo#00000', 'Bar#00000'])),
|
||||
);
|
||||
});
|
||||
|
||||
test('moreOrLessEquals', () {
|
||||
|
||||
Reference in New Issue
Block a user