import "package:flutter/widgets.dart"; import "package:flutter_test/flutter_test.dart"; import "package:garage_ui/garage_ui.dart"; import "support/test_scheme.dart"; // A group inside a group. The inner one used to install its own scope over the // outer one's, so the outer's say was simply lost: the bottom row's field kept // the top corners the vertical group had flattened, and painted a top edge the // row above had already drawn. // // Corners are 0-or-1 keep factors, so composing is a product - a corner stays // round only where BOTH groups leave it alone. void main() { ButtonGroupCorners cornersOf(WidgetTester tester, Type type) { final ctx = tester.element(find.byType(type)); return ButtonGroupScope.maybeOf(ctx)!.corners; } ButtonGroupScope scopeOf(WidgetTester tester, Key key) { return ButtonGroupScope.maybeOf(tester.element(find.byKey(key)))!; } testWidgets("a horizontal group nested in a vertical one composes", ( tester, ) async { const top = Key("top"); const bottomStart = Key("bottom-start"); const bottomEnd = Key("bottom-end"); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: GarageTheme( data: ThemeData(colorScheme: testScheme, density: const Density()), child: Center( child: SizedBox( width: 300, child: ButtonGroup.vertical( expands: true, children: [ const SizedBox(key: top, height: 20), // no expands on the inner group - it keeps the // IntrinsicHeight that bounds it inside the vertical one. ButtonGroup.horizontal( children: const [ Expanded(child: SizedBox(key: bottomStart, height: 20)), SizedBox(key: bottomEnd, height: 20, width: 20), ], ), ], ), ), ), ), ), ); // top row: vertical index 0 - both top corners live, bottom flattened // against the row below. final t = scopeOf(tester, top); expect( [t.corners.topStart, t.corners.topEnd], [1, 1], reason: "the top row keeps its top corners", ); expect( [t.corners.bottomStart, t.corners.bottomEnd], [0, 0], reason: "the top row's bottom is a seam", ); expect(t.hideTop, isFalse); expect(t.hideStart, isFalse); // bottom-left: bottom of the vertical group AND start of the horizontal // one, so the ONLY surviving corner is bottom-start. final bs = scopeOf(tester, bottomStart); expect( [ bs.corners.topStart, bs.corners.topEnd, bs.corners.bottomStart, bs.corners.bottomEnd, ], [0, 0, 1, 0], reason: "only the outer bottom-start corner survives both groups", ); expect( bs.hideTop, isTrue, reason: "the row above already painted this edge", ); expect(bs.hideStart, isFalse, reason: "its the first in its own row"); // bottom-right: bottom of the vertical AND end of the horizontal, so only // bottom-end survives - and it gives up BOTH its top and its start edge, // which is the pair a single axis+index could never express. final be = scopeOf(tester, bottomEnd); expect( [ be.corners.topStart, be.corners.topEnd, be.corners.bottomStart, be.corners.bottomEnd, ], [0, 0, 0, 1], ); expect(be.hideTop, isTrue, reason: "the row above painted the top edge"); expect( be.hideStart, isTrue, reason: "the field beside it painted the start edge", ); }); testWidgets("an unnested group is unchanged", (tester) async { const a = Key("a"); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: GarageTheme( data: ThemeData(colorScheme: testScheme, density: const Density()), child: Center( child: ButtonGroup.horizontal( children: const [ SizedBox(key: a, height: 20, width: 20), SizedBox(height: 20, width: 20), ], ), ), ), ), ); final s = scopeOf(tester, a); expect( [ s.corners.topStart, s.corners.topEnd, s.corners.bottomStart, s.corners.bottomEnd, ], [1, 0, 1, 0], ); expect(s.hideTop, isFalse); expect(s.hideStart, isFalse); }); }