fix: resolve TestSemantics comparison and assert issues#185921
fix: resolve TestSemantics comparison and assert issues#185921harshyadavDeveloper wants to merge 3 commits into
Conversation
|
It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging. If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group. |
There was a problem hiding this comment.
Code Review
This pull request corrects tautological comparisons in semantics_tester.dart and modifies an assert statement in the _IncludesNodeWith matcher. Feedback identifies a typo and redundant check in the controlsNodes logic, and highlights a regression in the assert condition that incorrectly requires both property and range values, alongside a violation of the dart format style requirement.
| } | ||
|
|
||
| if (controlsNodes != controlsNodes && !setEquals(controlsNodes, node.controlsNodes)) { | ||
| if (controlsNodes != node.controlsNode && !setEquals(controlsNodes, node.controlsNodes)) { |
There was a problem hiding this comment.
There is a typo in the property name: it should be node.controlsNodes (plural), not node.controlsNode. Additionally, the identity check controlsNodes != node.controlsNodes is redundant because setEquals already performs an identity check internally and handles null values correctly.
| if (controlsNodes != node.controlsNode && !setEquals(controlsNodes, node.controlsNodes)) { | |
| if (!setEquals(controlsNodes, node.controlsNodes)) { |
| (label != null || | ||
| value != null || | ||
| actions != null || | ||
| flags != null || | ||
| flagsCollection != null || | ||
| tags != null || | ||
| increasedValue != null || | ||
| decreasedValue != null || | ||
| scrollPosition != null || | ||
| scrollExtentMax != null || | ||
| scrollExtentMin != null || | ||
| maxValueLength != null || | ||
| currentValueLength != null || | ||
| inputType != null) && | ||
| (minValue != null || maxValue != null), | ||
| ); |
There was a problem hiding this comment.
The logic in the assert statement has been changed from "at least one property" to "at least one property from the first group AND one of the min/max values". This is a regression that will break tests matching only on labels or values. It should use || to ensure at least one of any property is provided. Also, the formatting should follow dart format as per the repository style guide.
| (label != null || | |
| value != null || | |
| actions != null || | |
| flags != null || | |
| flagsCollection != null || | |
| tags != null || | |
| increasedValue != null || | |
| decreasedValue != null || | |
| scrollPosition != null || | |
| scrollExtentMax != null || | |
| scrollExtentMin != null || | |
| maxValueLength != null || | |
| currentValueLength != null || | |
| inputType != null) && | |
| (minValue != null || maxValue != null), | |
| ); | |
| label != null || | |
| value != null || | |
| actions != null || | |
| flags != null || | |
| flagsCollection != null || | |
| tags != null || | |
| increasedValue != null || | |
| decreasedValue != null || | |
| scrollPosition != null || | |
| scrollExtentMax != null || | |
| scrollExtentMin != null || | |
| maxValueLength != null || | |
| currentValueLength != null || | |
| inputType != null || | |
| minValue != null || | |
| maxValue != null, | |
| ); |
References
- All Dart code is formatted using
dart format. This is enforced by CI. (link)
There was a problem hiding this comment.
The gemini bots suggestion sounds valid
|
Added tests to cover the TestSemantics fixes. Verified that the updated tests pass locally. |
| ); | ||
| semantics.dispose(); | ||
| }); | ||
|
|
There was a problem hiding this comment.
Hi @harshyadavDeveloper , your tests require fixes. the tests you wrote honestly does not test the comparison errors we are addressing.
| locale: const Locale('fr'), | ||
| ); | ||
|
|
||
| expect(first, isNot(equals(second))); |
There was a problem hiding this comment.
Your tests compares two TestSemantics objects using equals(), but the bugs are in _stringAttributesEqual() & _matches() of the TestSemantics class.
Let me tell me tell you what you are doing:
- Creating two
TestSemanticsobjects - Comparing them using
equals() - Checks they're NOT equal
This test only compare two TestSemantics objects. Don't test the actual bugges. equals(second) calls the == operator. But TestSemantics does NOT override ==, So it uses the default Dart ==, Test PASSES
| controlsNodes: <String>{'3', '4'}, | ||
| ); | ||
|
|
||
| expect(first, isNot(equals(second))); |
| testWidgets('TestSemantics detects different locales correctly', (WidgetTester tester) async { | ||
| final first = TestSemantics( | ||
| id: 1, | ||
| label: 'Hello', | ||
| locale: const Locale('en'), | ||
| ); | ||
|
|
||
| final second = TestSemantics( | ||
| id: 1, | ||
| label: 'Hello', | ||
| locale: const Locale('fr'), | ||
| ); | ||
|
|
||
| expect(first, isNot(equals(second))); | ||
| }); | ||
|
|
||
| testWidgets('TestSemantics detects different controlNodes correctly', (WidgetTester tester) async { | ||
| final first = TestSemantics( | ||
| id: 1, | ||
| controlsNodes: <String>{'1', '2'}, | ||
| ); | ||
|
|
||
| final second = TestSemantics( | ||
| id: 1, | ||
| controlsNodes: <String>{'3', '4'}, | ||
| ); | ||
|
|
||
| expect(first, isNot(equals(second))); | ||
| }); |
There was a problem hiding this comment.
For verification of the concept. I ran your test code in my IDE with bugs in semantics_tester.dart. All test PASSED!! However, I'm providing you correct test code. I ensured all these tests fails with buggy behaviour and passes all when the issues are fixed.
| testWidgets('TestSemantics detects different locales correctly', (WidgetTester tester) async { | |
| final first = TestSemantics( | |
| id: 1, | |
| label: 'Hello', | |
| locale: const Locale('en'), | |
| ); | |
| final second = TestSemantics( | |
| id: 1, | |
| label: 'Hello', | |
| locale: const Locale('fr'), | |
| ); | |
| expect(first, isNot(equals(second))); | |
| }); | |
| testWidgets('TestSemantics detects different controlNodes correctly', (WidgetTester tester) async { | |
| final first = TestSemantics( | |
| id: 1, | |
| controlsNodes: <String>{'1', '2'}, | |
| ); | |
| final second = TestSemantics( | |
| id: 1, | |
| controlsNodes: <String>{'3', '4'}, | |
| ); | |
| expect(first, isNot(equals(second))); | |
| }); | |
| testWidgets('hasSemantics should detect controlsNodes mismatch', (WidgetTester tester) async { | |
| final semantics = SemanticsTester(tester); | |
| await tester.pumpWidget( | |
| Semantics(label: 'Test', textDirection: TextDirection.ltr, child: Container()), | |
| ); | |
| // Test expects controlsNodes but widget doesn't have any | |
| final testSemantics = TestSemantics.root( | |
| children: <TestSemantics>[ | |
| TestSemantics.rootChild( | |
| id: 1, | |
| label: 'Test', | |
| rect: TestSemantics.fullScreen, | |
| controlsNodes: <String>{'node1'}, | |
| ), | |
| ], | |
| ); | |
| expect(semantics, isNot(hasSemantics(testSemantics, ignoreId: true))); | |
| semantics.dispose(); | |
| }); | |
| test('includesNodeWith accepts minValue only', () { | |
| expect(() => includesNodeWith(minValue: '0'), returnsNormally); | |
| }); | |
| test('includesNodeWith accepts maxValue only', () { | |
| expect(() => includesNodeWith(maxValue: '100'), returnsNormally); | |
| }); | |
| test('includesNodeWith rejects no properties', () { | |
| expect(() => includesNodeWith(), throwsAssertionError); | |
| }); | |
| testWidgets('nodesWith detects locale attribute mismatch', (WidgetTester tester) async { | |
| final semantics = SemanticsTester(tester); | |
| await tester.pumpWidget( | |
| const Text.rich( | |
| TextSpan(text: 'Hello', locale: Locale('en')), | |
| textDirection: TextDirection.ltr, | |
| ), | |
| ); | |
| final attributedLabel = AttributedString( | |
| 'Hello', | |
| attributes: [ | |
| LocaleStringAttribute(range: const TextRange(start: 0, end: 5), locale: const Locale('fr')), | |
| ], | |
| ); | |
| final Iterable<SemanticsNode> nodes = semantics.nodesWith(attributedLabel: attributedLabel); | |
| expect(nodes, isEmpty); | |
| semantics.dispose(); | |
| }); |
justinmc
left a comment
There was a problem hiding this comment.
Thanks for the PR! +1 to @Istiak-Ahmed78's points here.
|
closing this pr in favor of #185975 |
Description
Fixes multiple issues in
TestSemanticswhere incorrect comparisonsand an invalid assert condition resulted in unintended behavior.
Changes include:
LocaleStringAttribute.localeto avoidcomparing a value with itself
controlsNodeswith itself&&instead of passing multiple arguments
These fixes improve correctness and prevent logical errors in
semantics testing.
Issues fixed by this PR
Fixes #185900
Pre-launch Checklist
///).