From 9995e370bf4a809e8592f40a1fe8c0a2a3ffb374 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 18 Oct 2022 10:25:04 -0700 Subject: [PATCH] Fix StarBorder operator== (#113588) --- dev/manual_tests/lib/star_border.dart | 2 - .../painting/star_border/star_border.0.dart | 1 - .../flutter/lib/src/painting/star_border.dart | 9 +- .../test/painting/star_border_test.dart | 152 +++++++++++------- 4 files changed, 103 insertions(+), 61 deletions(-) diff --git a/dev/manual_tests/lib/star_border.dart b/dev/manual_tests/lib/star_border.dart index 7a4e893bad..dafc353fa9 100644 --- a/dev/manual_tests/lib/star_border.dart +++ b/dev/manual_tests/lib/star_border.dart @@ -72,7 +72,6 @@ class _MyHomePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container( - key: UniqueKey(), alignment: Alignment.center, width: 300, height: 200, @@ -94,7 +93,6 @@ class _MyHomePageState extends State { child: const Text('Polygon'), ), Container( - key: UniqueKey(), alignment: Alignment.center, width: 300, height: 200, diff --git a/examples/api/lib/painting/star_border/star_border.0.dart b/examples/api/lib/painting/star_border/star_border.0.dart index d2cb175f84..34d3669c4b 100644 --- a/examples/api/lib/painting/star_border/star_border.0.dart +++ b/examples/api/lib/painting/star_border/star_border.0.dart @@ -144,7 +144,6 @@ class ExampleBorder extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - key: UniqueKey(), alignment: Alignment.center, padding: const EdgeInsets.all(20), width: 150, diff --git a/packages/flutter/lib/src/painting/star_border.dart b/packages/flutter/lib/src/painting/star_border.dart index 609f402283..7a4081e6d3 100644 --- a/packages/flutter/lib/src/painting/star_border.dart +++ b/packages/flutter/lib/src/painting/star_border.dart @@ -422,7 +422,14 @@ class StarBorder extends OutlinedBorder { if (other.runtimeType != runtimeType) { return false; } - return other is StarBorder && other.side == side; + return other is StarBorder + && other.side == side + && other.points == points + && other._innerRadiusRatio == _innerRadiusRatio + && other.pointRounding == pointRounding + && other.valleyRounding == valleyRounding + && other._rotationRadians == _rotationRadians + && other.squash == squash; } @override diff --git a/packages/flutter/test/painting/star_border_test.dart b/packages/flutter/test/painting/star_border_test.dart index d00b0140b9..945f67b2b2 100644 --- a/packages/flutter/test/painting/star_border_test.dart +++ b/packages/flutter/test/painting/star_border_test.dart @@ -76,6 +76,41 @@ void main() { expect(const StarBorder(), equals(const StarBorder().copyWith())); expect(copy, equals(expected)); expect(copy.hashCode, equals(expected.hashCode)); + + // Test that all properties are checked in operator== + expect(const StarBorder(), isNot(equals(const StarBorderSubclass()))); + expect(copy, isNot(equals('Not a StarBorder'))); + + // Test that two StarBorders where the only difference is polygon vs star + // constructor compare as different (which they are, because + // _innerRadiusRatio is null on the polygon). + expect( + const StarBorder( + points: 3, + innerRadiusRatio: 1, + pointRounding: 0.2, + rotation: 180, + squash: 0.4, + ), + isNot(equals( + const StarBorder.polygon( + sides: 3, + pointRounding: 0.2, + rotation: 180, + squash: 0.4, + ), + )), + ); + + // Test that copies are unequal whenever any one of the properties changes. + expect(copy, equals(copy)); + expect(copy, isNot(equals(copy.copyWith(side: const BorderSide())))); + expect(copy, isNot(equals(copy.copyWith(points: 10)))); + expect(copy, isNot(equals(copy.copyWith(innerRadiusRatio: 0.5)))); + expect(copy, isNot(equals(copy.copyWith(pointRounding: 0.5)))); + expect(copy, isNot(equals(copy.copyWith(valleyRounding: 0.5)))); + expect(copy, isNot(equals(copy.copyWith(rotation: 10)))); + expect(copy, isNot(equals(copy.copyWith(squash: 0.0)))); }); testWidgets('StarBorder basic geometry', (WidgetTester tester) async { @@ -87,14 +122,14 @@ void main() { await testBorder(tester, 'points_6', const StarBorder(points: 6)); await testBorder(tester, 'points_2', const StarBorder(points: 2)); await testBorder(tester, 'inner_radius_0', const StarBorder(innerRadiusRatio: 0.0)); - await testBorder(tester, 'inner_radius_2', const StarBorder(innerRadiusRatio: 0.2)); - await testBorder(tester, 'inner_radius_7', const StarBorder(innerRadiusRatio: 0.7)); - await testBorder(tester, 'point_rounding_2', const StarBorder(pointRounding: 0.2)); - await testBorder(tester, 'point_rounding_7', const StarBorder(pointRounding: 0.7)); - await testBorder(tester, 'point_rounding_10', const StarBorder(pointRounding: 1.0)); - await testBorder(tester, 'valley_rounding_2', const StarBorder(valleyRounding: 0.2)); - await testBorder(tester, 'valley_rounding_7', const StarBorder(valleyRounding: 0.7)); - await testBorder(tester, 'valley_rounding_10', const StarBorder(valleyRounding: 1.0)); + await testBorder(tester, 'inner_radius_20', const StarBorder(innerRadiusRatio: 0.2)); + await testBorder(tester, 'inner_radius_70', const StarBorder(innerRadiusRatio: 0.7)); + await testBorder(tester, 'point_rounding_20', const StarBorder(pointRounding: 0.2)); + await testBorder(tester, 'point_rounding_70', const StarBorder(pointRounding: 0.7)); + await testBorder(tester, 'point_rounding_100', const StarBorder(pointRounding: 1.0)); + await testBorder(tester, 'valley_rounding_20', const StarBorder(valleyRounding: 0.2)); + await testBorder(tester, 'valley_rounding_70', const StarBorder(valleyRounding: 0.7)); + await testBorder(tester, 'valley_rounding_100', const StarBorder(valleyRounding: 1.0)); await testBorder(tester, 'squash_2', const StarBorder(squash: 0.2)); await testBorder(tester, 'squash_7', const StarBorder(squash: 0.7)); await testBorder(tester, 'squash_10', const StarBorder(squash: 1.0)); @@ -104,32 +139,27 @@ void main() { await testBorder(tester, 'side_none', const StarBorder(side: BorderSide(style: BorderStyle.none))); await testBorder(tester, 'side_1', const StarBorder(side: BorderSide(color: Color(0xffff0000)))); await testBorder(tester, 'side_10', const StarBorder(side: BorderSide(color: Color(0xffff0000), width: 10))); - await testBorder(tester, 'side_align_center', - const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); - await testBorder(tester, 'side_align_outside', - const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); + await testBorder(tester, 'side_align_center', const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); + await testBorder(tester, 'side_align_outside', const StarBorder(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); }); testWidgets('StarBorder.polygon parameters', (WidgetTester tester) async { await testBorder(tester, 'poly_sides_6', const StarBorder.polygon(sides: 6)); await testBorder(tester, 'poly_sides_2', const StarBorder.polygon(sides: 2)); - await testBorder(tester, 'poly_point_rounding_2', const StarBorder.polygon(pointRounding: 0.2)); - await testBorder(tester, 'poly_point_rounding_7', const StarBorder.polygon(pointRounding: 0.7)); - await testBorder(tester, 'poly_point_rounding_10', const StarBorder.polygon(pointRounding: 1.0)); - await testBorder(tester, 'poly_squash_2', const StarBorder.polygon(squash: 0.2)); - await testBorder(tester, 'poly_squash_7', const StarBorder.polygon(squash: 0.7)); - await testBorder(tester, 'poly_squash_10', const StarBorder.polygon(squash: 1.0)); + await testBorder(tester, 'poly_point_rounding_20', const StarBorder.polygon(pointRounding: 0.2)); + await testBorder(tester, 'poly_point_rounding_70', const StarBorder.polygon(pointRounding: 0.7)); + await testBorder(tester, 'poly_point_rounding_100', const StarBorder.polygon(pointRounding: 1.0)); + await testBorder(tester, 'poly_squash_20', const StarBorder.polygon(squash: 0.2)); + await testBorder(tester, 'poly_squash_70', const StarBorder.polygon(squash: 0.7)); + await testBorder(tester, 'poly_squash_100', const StarBorder.polygon(squash: 1.0)); await testBorder(tester, 'poly_rotate_27', const StarBorder.polygon(rotation: 27)); await testBorder(tester, 'poly_rotate_270', const StarBorder.polygon(rotation: 270)); await testBorder(tester, 'poly_rotate_360', const StarBorder.polygon(rotation: 360)); await testBorder(tester, 'poly_side_none', const StarBorder.polygon(side: BorderSide(style: BorderStyle.none))); await testBorder(tester, 'poly_side_1', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000)))); - await testBorder( - tester, 'poly_side_10', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), width: 10))); - await testBorder(tester, 'poly_side_align_center', - const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); - await testBorder(tester, 'poly_side_align_outside', - const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); + await testBorder(tester, 'poly_side_10', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), width: 10))); + await testBorder(tester, 'poly_side_align_center', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignCenter))); + await testBorder(tester, 'poly_side_align_outside', const StarBorder.polygon(side: BorderSide(color: Color(0xffff0000), strokeAlign: BorderSide.strokeAlignOutside))); }); testWidgets("StarBorder doesn't try to scale an infinite scale matrix", (WidgetTester tester) async { @@ -141,7 +171,7 @@ void main() { width: 100, height: 100, child: Stack( - children: [ + children: [ Positioned.fromRelativeRect( rect: const RelativeRect.fromLTRB(100, 100, 100, 100), child: Container( @@ -169,37 +199,41 @@ void main() { innerRadiusRatio: 0.5, rotation: 90, ); - await testBorder(tester, 'to_star_border_2', from, lerpTo: otherBorder, lerpAmount: 0.2); - await testBorder(tester, 'to_star_border_7', from, lerpTo: otherBorder, lerpAmount: 0.7); - await testBorder(tester, 'to_star_border_10', from, lerpTo: otherBorder, lerpAmount: 1.0); - await testBorder(tester, 'from_star_border_2', from, lerpFrom: otherBorder, lerpAmount: 0.2); - await testBorder(tester, 'from_star_border_7', from, lerpFrom: otherBorder, lerpAmount: 0.7); - await testBorder(tester, 'from_star_border_10', from, lerpFrom: otherBorder, lerpAmount: 1.0); + await testBorder(tester, 'to_star_border_20', from, lerpTo: otherBorder, lerpAmount: 0.2); + await testBorder(tester, 'to_star_border_70', from, lerpTo: otherBorder, lerpAmount: 0.7); + await testBorder(tester, 'to_star_border_100', from, lerpTo: otherBorder, lerpAmount: 1.0); + await testBorder(tester, 'from_star_border_20', from, lerpFrom: otherBorder, lerpAmount: 0.2); + await testBorder(tester, 'from_star_border_70', from, lerpFrom: otherBorder, lerpAmount: 0.7); + await testBorder(tester, 'from_star_border_100', from, lerpFrom: otherBorder, lerpAmount: 1.0); }); testWidgets('StarBorder lerped with CircleBorder', (WidgetTester tester) async { const StarBorder from = StarBorder(); const ShapeBorder otherBorder = CircleBorder(); const ShapeBorder eccentricCircle = CircleBorder(eccentricity: 0.6); - await testBorder(tester, 'to_circle_border_2', from, lerpTo: otherBorder, lerpAmount: 0.2); - await testBorder(tester, 'to_circle_border_7', from, lerpTo: otherBorder, lerpAmount: 0.7); - await testBorder(tester, 'to_circle_border_10', from, lerpTo: otherBorder, lerpAmount: 1.0); - await testBorder(tester, 'from_circle_border_2', from, lerpFrom: otherBorder, lerpAmount: 0.2); - await testBorder(tester, 'from_circle_border_7', from, lerpFrom: otherBorder, lerpAmount: 0.7); - await testBorder(tester, 'from_circle_border_10', from, lerpFrom: otherBorder, lerpAmount: 1.0); - await testBorder(tester, 'to_eccentric_circle_border', from, lerpTo: eccentricCircle, lerpAmount: 0.4); - await testBorder(tester, 'from_eccentric_circle_border', from, lerpFrom: eccentricCircle, lerpAmount: 0.4); + await testBorder(tester, 'to_circle_border_20', from, lerpTo: otherBorder, lerpAmount: 0.2); + await testBorder(tester, 'to_circle_border_70', from, lerpTo: otherBorder, lerpAmount: 0.7); + await testBorder(tester, 'to_circle_border_100', from, lerpTo: otherBorder, lerpAmount: 1.0); + await testBorder(tester, 'from_circle_border_20', from, lerpFrom: otherBorder, lerpAmount: 0.2); + await testBorder(tester, 'from_circle_border_70', from, lerpFrom: otherBorder, lerpAmount: 0.7); + await testBorder(tester, 'from_circle_border_100', from, lerpFrom: otherBorder, lerpAmount: 1.0); + await testBorder(tester, 'to_eccentric_circle_border_20', from, lerpTo: eccentricCircle, lerpAmount: 0.2); + await testBorder(tester, 'to_eccentric_circle_border_70', from, lerpTo: eccentricCircle, lerpAmount: 0.7); + await testBorder(tester, 'to_eccentric_circle_border_100', from, lerpTo: eccentricCircle, lerpAmount: 1.0); + await testBorder(tester, 'from_eccentric_circle_border_20', from, lerpFrom: eccentricCircle, lerpAmount: 0.2); + await testBorder(tester, 'from_eccentric_circle_border_70', from, lerpFrom: eccentricCircle, lerpAmount: 0.7); + await testBorder(tester, 'from_eccentric_circle_border_100', from, lerpFrom: eccentricCircle, lerpAmount: 1.0); }); testWidgets('StarBorder lerped with RoundedRectangleBorder', (WidgetTester tester) async { const StarBorder from = StarBorder(); const RoundedRectangleBorder rectangleBorder = RoundedRectangleBorder(); - await testBorder(tester, 'to_rect_border_2', from, lerpTo: rectangleBorder, lerpAmount: 0.2); - await testBorder(tester, 'to_rect_border_7', from, lerpTo: rectangleBorder, lerpAmount: 0.7); - await testBorder(tester, 'to_rect_border_10', from, lerpTo: rectangleBorder, lerpAmount: 1.0); - await testBorder(tester, 'from_rect_border_2', from, lerpFrom: rectangleBorder, lerpAmount: 0.2); - await testBorder(tester, 'from_rect_border_7', from, lerpFrom: rectangleBorder, lerpAmount: 0.7); - await testBorder(tester, 'from_rect_border_10', from, lerpFrom: rectangleBorder, lerpAmount: 1.0); + await testBorder(tester, 'to_rect_border_20', from, lerpTo: rectangleBorder, lerpAmount: 0.2); + await testBorder(tester, 'to_rect_border_70', from, lerpTo: rectangleBorder, lerpAmount: 0.7); + await testBorder(tester, 'to_rect_border_100', from, lerpTo: rectangleBorder, lerpAmount: 1.0); + await testBorder(tester, 'from_rect_border_20', from, lerpFrom: rectangleBorder, lerpAmount: 0.2); + await testBorder(tester, 'from_rect_border_70', from, lerpFrom: rectangleBorder, lerpAmount: 0.7); + await testBorder(tester, 'from_rect_border_100', from, lerpFrom: rectangleBorder, lerpAmount: 1.0); const RoundedRectangleBorder roundedRectBorder = RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -207,23 +241,27 @@ void main() { bottomRight: Radius.circular(10.0), ), ); - await testBorder(tester, 'to_rrect_border_2', from, lerpTo: roundedRectBorder, lerpAmount: 0.2); - await testBorder(tester, 'to_rrect_border_7', from, lerpTo: roundedRectBorder, lerpAmount: 0.7); - await testBorder(tester, 'to_rrect_border_10', from, lerpTo: roundedRectBorder, lerpAmount: 1.0); - await testBorder(tester, 'from_rrect_border_2', from, lerpFrom: roundedRectBorder, lerpAmount: 0.2); - await testBorder(tester, 'from_rrect_border_7', from, lerpFrom: roundedRectBorder, lerpAmount: 0.7); - await testBorder(tester, 'from_rrect_border_10', from, lerpFrom: roundedRectBorder, lerpAmount: 1.0); + await testBorder(tester, 'to_rrect_border_20', from, lerpTo: roundedRectBorder, lerpAmount: 0.2); + await testBorder(tester, 'to_rrect_border_70', from, lerpTo: roundedRectBorder, lerpAmount: 0.7); + await testBorder(tester, 'to_rrect_border_100', from, lerpTo: roundedRectBorder, lerpAmount: 1.0); + await testBorder(tester, 'from_rrect_border_20', from, lerpFrom: roundedRectBorder, lerpAmount: 0.2); + await testBorder(tester, 'from_rrect_border_70', from, lerpFrom: roundedRectBorder, lerpAmount: 0.7); + await testBorder(tester, 'from_rrect_border_100', from, lerpFrom: roundedRectBorder, lerpAmount: 1.0); }); testWidgets('StarBorder lerped with StadiumBorder', (WidgetTester tester) async { const StarBorder from = StarBorder(); const StadiumBorder stadiumBorder = StadiumBorder(); - await testBorder(tester, 'to_stadium_border_2', from, lerpTo: stadiumBorder, lerpAmount: 0.2); - await testBorder(tester, 'to_stadium_border_7', from, lerpTo: stadiumBorder, lerpAmount: 0.7); - await testBorder(tester, 'to_stadium_border_10', from, lerpTo: stadiumBorder, lerpAmount: 1.0); - await testBorder(tester, 'from_stadium_border_2', from, lerpFrom: stadiumBorder, lerpAmount: 0.2); - await testBorder(tester, 'from_stadium_border_7', from, lerpFrom: stadiumBorder, lerpAmount: 0.7); - await testBorder(tester, 'from_stadium_border_10', from, lerpFrom: stadiumBorder, lerpAmount: 1.0); + await testBorder(tester, 'to_stadium_border_20', from, lerpTo: stadiumBorder, lerpAmount: 0.2); + await testBorder(tester, 'to_stadium_border_70', from, lerpTo: stadiumBorder, lerpAmount: 0.7); + await testBorder(tester, 'to_stadium_border_100', from, lerpTo: stadiumBorder, lerpAmount: 1.0); + await testBorder(tester, 'from_stadium_border_20', from, lerpFrom: stadiumBorder, lerpAmount: 0.2); + await testBorder(tester, 'from_stadium_border_70', from, lerpFrom: stadiumBorder, lerpAmount: 0.7); + await testBorder(tester, 'from_stadium_border_100', from, lerpFrom: stadiumBorder, lerpAmount: 1.0); }); } + +class StarBorderSubclass extends StarBorder { + const StarBorderSubclass(); +}