Skip to content

The borderRadius property is missing from equality and hashCode in UnderlineInputBorder, equality and hashCode tests of UnderlineInputBorder and OutlineInputBorder are not exhaustive #118282

@rydmike

Description

@rydmike

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
  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 borderRadius to equality and hashCode of UnderlineInputBorder.
  • Improve tests of UnderlineInputBorder and OutlineInputBorder to 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

Metadata

Metadata

Assignees

Labels

f: material designflutter/packages/flutter/material repository.found in release: 3.3Found to occur in 3.3found in release: 3.7Found to occur in 3.7frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions