Unverified Commit 574fb1f0 authored by pdblasi-google's avatar pdblasi-google Committed by GitHub

110598: expect() in semantic test producing unhelpful output (#110613)

parent ab77e435
...@@ -2272,10 +2272,10 @@ class _MatchesSemanticsData extends Matcher { ...@@ -2272,10 +2272,10 @@ class _MatchesSemanticsData extends Matcher {
.toList(); .toList();
if (expectedActions.isNotEmpty) { if (expectedActions.isNotEmpty) {
description.add(' with actions: ').addDescriptionOf(expectedActions); description.add(' with actions: ${_createEnumsSummary(expectedActions)} ');
} }
if (notExpectedActions.isNotEmpty) { if (notExpectedActions.isNotEmpty) {
description.add(' without actions: ').addDescriptionOf(notExpectedActions); description.add(' without actions: ${_createEnumsSummary(notExpectedActions)} ');
} }
} }
if (flags.isNotEmpty) { if (flags.isNotEmpty) {
...@@ -2289,10 +2289,10 @@ class _MatchesSemanticsData extends Matcher { ...@@ -2289,10 +2289,10 @@ class _MatchesSemanticsData extends Matcher {
.toList(); .toList();
if (expectedFlags.isNotEmpty) { if (expectedFlags.isNotEmpty) {
description.add(' with flags: ').addDescriptionOf(expectedFlags); description.add(' with flags: ${_createEnumsSummary(expectedFlags)} ');
} }
if (notExpectedFlags.isNotEmpty) { if (notExpectedFlags.isNotEmpty) {
description.add(' without flags: ').addDescriptionOf(notExpectedFlags); description.add(' without flags: ${_createEnumsSummary(notExpectedFlags)} ');
} }
} }
if (textDirection != null) { if (textDirection != null) {
...@@ -2434,18 +2434,24 @@ class _MatchesSemanticsData extends Matcher { ...@@ -2434,18 +2434,24 @@ class _MatchesSemanticsData extends Matcher {
return failWithDescription(matchState, 'maxValueLength was: ${data.maxValueLength}'); return failWithDescription(matchState, 'maxValueLength was: ${data.maxValueLength}');
} }
if (actions.isNotEmpty) { if (actions.isNotEmpty) {
final List<SemanticsAction> unexpectedActions = <SemanticsAction>[];
final List<SemanticsAction> missingActions = <SemanticsAction>[];
for (final MapEntry<ui.SemanticsAction, bool> actionEntry in actions.entries) { for (final MapEntry<ui.SemanticsAction, bool> actionEntry in actions.entries) {
final ui.SemanticsAction action = actionEntry.key; final ui.SemanticsAction action = actionEntry.key;
final bool actionExpected = actionEntry.value; final bool actionExpected = actionEntry.value;
final bool actionPresent = (action.index & data.actions) == action.index; final bool actionPresent = (action.index & data.actions) == action.index;
if (actionPresent != actionExpected) { if (actionPresent != actionExpected) {
final List<String> actionSummary = <String>[ if(actionExpected) {
for (final int action in SemanticsAction.values.keys) missingActions.add(action);
if ((data.actions & action) != 0) describeEnum(action), } else {
]; unexpectedActions.add(action);
return failWithDescription(matchState, 'actions were: $actionSummary'); }
} }
} }
if (unexpectedActions.isNotEmpty || missingActions.isNotEmpty) {
return failWithDescription(matchState, 'missing actions: ${_createEnumsSummary(missingActions)} unexpected actions: ${_createEnumsSummary(unexpectedActions)}');
}
} }
if (customActions != null || hintOverrides != null) { if (customActions != null || hintOverrides != null) {
final List<CustomSemanticsAction> providedCustomActions = data.customSemanticsActionIds?.map<CustomSemanticsAction>((int id) { final List<CustomSemanticsAction> providedCustomActions = data.customSemanticsActionIds?.map<CustomSemanticsAction>((int id) {
...@@ -2473,18 +2479,24 @@ class _MatchesSemanticsData extends Matcher { ...@@ -2473,18 +2479,24 @@ class _MatchesSemanticsData extends Matcher {
} }
} }
if (flags.isNotEmpty) { if (flags.isNotEmpty) {
final List<SemanticsFlag> unexpectedFlags = <SemanticsFlag>[];
final List<SemanticsFlag> missingFlags = <SemanticsFlag>[];
for (final MapEntry<ui.SemanticsFlag, bool> flagEntry in flags.entries) { for (final MapEntry<ui.SemanticsFlag, bool> flagEntry in flags.entries) {
final ui.SemanticsFlag flag = flagEntry.key; final ui.SemanticsFlag flag = flagEntry.key;
final bool flagExpected = flagEntry.value; final bool flagExpected = flagEntry.value;
final bool flagPresent = flag.index & data.flags == flag.index; final bool flagPresent = flag.index & data.flags == flag.index;
if (flagPresent != flagExpected) { if (flagPresent != flagExpected) {
final List<String> flagSummary = <String>[ if(flagExpected) {
for (final int flag in SemanticsFlag.values.keys) missingFlags.add(flag);
if ((data.flags & flag) != 0) describeEnum(flag), } else {
]; unexpectedFlags.add(flag);
return failWithDescription(matchState, 'flags were: $flagSummary'); }
} }
} }
if (unexpectedFlags.isNotEmpty || missingFlags.isNotEmpty) {
return failWithDescription(matchState, 'missing flags: ${_createEnumsSummary(missingFlags)} unexpected flags: ${_createEnumsSummary(unexpectedFlags)}');
}
} }
bool allMatched = true; bool allMatched = true;
if (children != null) { if (children != null) {
...@@ -2512,6 +2524,11 @@ class _MatchesSemanticsData extends Matcher { ...@@ -2512,6 +2524,11 @@ class _MatchesSemanticsData extends Matcher {
) { ) {
return mismatchDescription.add(matchState['failure'] as String); return mismatchDescription.add(matchState['failure'] as String);
} }
static String _createEnumsSummary<T extends Object>(List<T> enums) {
assert(T == SemanticsAction || T == SemanticsFlag, 'This method is only intended for lists of SemanticsActions or SemanticsFlags.');
return '[${enums.map(describeEnum).join(', ')}]';
}
} }
class _MatchesAccessibilityGuideline extends AsyncMatcher { class _MatchesAccessibilityGuideline extends AsyncMatcher {
......
...@@ -733,6 +733,62 @@ void main() { ...@@ -733,6 +733,62 @@ void main() {
)); ));
handle.dispose(); handle.dispose();
}); });
testWidgets('failure does not throw unexpected errors', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
addTearDown(() => handle.dispose());
const Key key = Key('semantics');
await tester.pumpWidget(Semantics(
key: key,
namesRoute: true,
header: true,
button: true,
link: true,
onTap: () { },
onLongPress: () { },
label: 'foo',
hint: 'bar',
value: 'baz',
increasedValue: 'a',
decreasedValue: 'b',
textDirection: TextDirection.rtl,
onTapHint: 'scan',
onLongPressHint: 'fill',
customSemanticsActions: <CustomSemanticsAction, VoidCallback>{
const CustomSemanticsAction(label: 'foo'): () { },
const CustomSemanticsAction(label: 'bar'): () { },
},
));
// This should fail due to the mis-match between the `namesRoute` value.
void failedExpectation() => expect(tester.getSemantics(find.byKey(key)),
matchesSemantics(
// Adding the explicit `false` for test readability
// ignore: avoid_redundant_argument_values
namesRoute: false,
label: 'foo',
hint: 'bar',
value: 'baz',
increasedValue: 'a',
decreasedValue: 'b',
textDirection: TextDirection.rtl,
hasTapAction: true,
hasLongPressAction: true,
isButton: true,
isLink: true,
isHeader: true,
onTapHint: 'scan',
onLongPressHint: 'fill',
customActions: <CustomSemanticsAction>[
const CustomSemanticsAction(label: 'foo'),
const CustomSemanticsAction(label: 'bar'),
],
),
);
expect(failedExpectation, throwsA(isA<TestFailure>()));
});
}); });
group('containsSemantics', () { group('containsSemantics', () {
...@@ -1173,6 +1229,60 @@ void main() { ...@@ -1173,6 +1229,60 @@ void main() {
expect(node, containsSemantics(customActions: <CustomSemanticsAction>[action])); expect(node, containsSemantics(customActions: <CustomSemanticsAction>[action]));
}); });
testWidgets('failure does not throw unexpected errors', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
addTearDown(() => handle.dispose());
const Key key = Key('semantics');
await tester.pumpWidget(Semantics(
key: key,
namesRoute: true,
header: true,
button: true,
link: true,
onTap: () { },
onLongPress: () { },
label: 'foo',
hint: 'bar',
value: 'baz',
increasedValue: 'a',
decreasedValue: 'b',
textDirection: TextDirection.rtl,
onTapHint: 'scan',
onLongPressHint: 'fill',
customSemanticsActions: <CustomSemanticsAction, VoidCallback>{
const CustomSemanticsAction(label: 'foo'): () { },
const CustomSemanticsAction(label: 'bar'): () { },
},
));
// This should fail due to the mis-match between the `namesRoute` value.
void failedExpectation() => expect(tester.getSemantics(find.byKey(key)),
containsSemantics(
label: 'foo',
hint: 'bar',
value: 'baz',
increasedValue: 'a',
decreasedValue: 'b',
textDirection: TextDirection.rtl,
hasTapAction: true,
hasLongPressAction: true,
isButton: true,
isLink: true,
isHeader: true,
namesRoute: false,
onTapHint: 'scan',
onLongPressHint: 'fill',
customActions: <CustomSemanticsAction>[
const CustomSemanticsAction(label: 'foo'),
const CustomSemanticsAction(label: 'bar'),
],
),
);
expect(failedExpectation, throwsA(isA<TestFailure>()));
});
}); });
group('findsAtLeastNWidgets', () { group('findsAtLeastNWidgets', () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment