-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
The UnderlineInputBorder has equality and hashCode gap
The borderRadius property is missing from equality and hashCode in UnderlineInputBorder. This causes update issues in ThemeData if a theme changes only the upper side border radius in an InputDecoratorTheme, the application theme does not update since the UnderlineInputBorder is seen as identical.
The UnderlineInputBorder has properties borderSide and borderRadius , but only borderSide is included in equality and hashCode.
| class UnderlineInputBorder extends InputBorder { |
class UnderlineInputBorder extends InputBorder {
/// Creates an underline border for an [InputDecorator].
///
/// The [borderSide] parameter defaults to [BorderSide.none] (it must not be
/// null). Applications typically do not specify a [borderSide] parameter
/// because the input decorator substitutes its own, using [copyWith], based
/// on the current theme and [InputDecorator.isFocused].
///
/// The [borderRadius] parameter defaults to a value where the top left
/// and right corners have a circular radius of 4.0. The [borderRadius]
/// parameter must not be null.
const UnderlineInputBorder({
BorderSide borderSide = const BorderSide(),
this.borderRadius = const BorderRadius.only(
topLeft: Radius.circular(4.0),
topRight: Radius.circular(4.0),
),
}) : assert(borderRadius != null),
super(borderSide: borderSide);However borderRadius is not included in hashCode or equality.
| @override |
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
return other is InputBorder
&& other.borderSide == borderSide;
}
@override
int get hashCode => borderSide.hashCode;
}Q: Is there some reason why the UnderlineInputBorder equality is designed this way?
This gap causes certain theme updates to fail.
Will try to submit a fix PR.
Expected results
Expect these unit tests to pass:
void main() {
group('UnderlineInputBorder test', () {
test('UnderlineInputBorder equality', () {
// UnderlineInputBorder's equality is defined only by the borderSide
const UnderlineInputBorder underlineInputBorder =
UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue));
expect(
underlineInputBorder,
const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue)));
expect(underlineInputBorder, isNot(const UnderlineInputBorder()));
// UnderlineInputBorder's equality is defined by the borderSide and borderRadius
const UnderlineInputBorder underlineInputBorderRadius =
UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
),
);
expect(
underlineInputBorderRadius,
const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
),
),
);
expect(
underlineInputBorderRadius,
isNot(
const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(6.0),
topRight: Radius.circular(6.0),
),
),
),
);
});
test('UnderlineInputBorder hashCodes', () {
// UnderlineInputBorder's hashCode is defined only by the borderSide
const UnderlineInputBorder underlineInputBorder =
UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue));
expect(
underlineInputBorder.hashCode,
const UnderlineInputBorder(borderSide: BorderSide(color: Colors.blue))
.hashCode);
expect(underlineInputBorder.hashCode,
isNot(const UnderlineInputBorder().hashCode));
// UnderlineInputBorder's hashCode is defined by the borderSide and borderRadius
const UnderlineInputBorder underlineInputBorderRadius =
UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
),
);
expect(
underlineInputBorderRadius.hashCode,
const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
),
).hashCode,
);
expect(
underlineInputBorderRadius.hashCode,
isNot(
const UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(6.0),
topRight: Radius.circular(6.0),
),
).hashCode,
),
);
});
});
}Actual results
The tests FAIL.
package:test_api expect
package:flutter_test/src/widget_tester.dart 460:16 expect
test/input_decorator_test.dart 34:7 main.<fn>.<fn>
Expected: not UnderlineInputBorder:<UnderlineInputBorder()>
Actual: UnderlineInputBorder:<UnderlineInputBorder()>
package:test_api expect
package:flutter_test/src/widget_tester.dart 460:16 expect
test/input_decorator_test.dart 77:7 main.<fn>.<fn>
Expected: not <307579946>
Actual: <307579946>
The existing tests for UnderlineInputBorder and OutlineInputBorder are not exhaustive enough to capture an issue like this. Only the UnderlineInputBorder has this gap, the OutlineInputBorder does not have the same issue, but if it would have had a similar gap, its current test would not have caught the issue.
Proposal
- Add
borderRadiusto equality andhashCodeofUnderlineInputBorder. - Improve tests of
UnderlineInputBorderandOutlineInputBorderto capture a gap like this.
Used Flutter Version
Tested on channel master, 3.7.0-15.0.pre.16
This issue exists on all channels.
flutter doctor -v
[!] Flutter (Channel master, 3.7.0-15.0.pre.16, on macOS 13.0.1 22A400 darwin-arm64, locale en-US)
• Flutter version 3.7.0-15.0.pre.16 on channel master at /Users/rydmike/fvm/versions/master
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 7ddf42eae5 (2 days ago), 2023-01-06 17:44:44 -0500
• Engine revision 33d7f8a1b3
• Dart version 3.0.0 (build 3.0.0-85.0.dev)
• DevTools version 2.20.0
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
• Android SDK at /Users/rydmike/Library/Android/sdk
• Platform android-33, build-tools 33.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 14C18
• CocoaPods version 1.11.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
[✓] IntelliJ IDEA Community Edition (version 2022.3.1)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin version 71.2.6
• Dart plugin version 223.8214.16
[✓] VS Code (version 1.73.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.54.0
[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-arm64 • macOS 13.0.1 22A400 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.124
[✓] HTTP Host Availability
• All required HTTP hosts are available