blob: a3d328fe72cd77717d7527ab4105c161c65da85a [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file is run as part of a reduced test set in CI on Mac and Windows
// machines.
@Tags(<String>['reduced-test-set'])
library;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
void main() {
testWidgets('DecoratedSliver creates, paints, and disposes BoxPainter', (WidgetTester tester) async {
final TestDecoration decoration = TestDecoration();
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: CustomScrollView(
slivers: <Widget>[
DecoratedSliver(
decoration: decoration,
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 100, height: 100),
),
)
],
)
)
));
expect(decoration.painters, hasLength(1));
expect(decoration.painters.last.lastConfiguration!.size, const Size(800, 100));
expect(decoration.painters.last.lastOffset, Offset.zero);
expect(decoration.painters.last.disposed, false);
await tester.pumpWidget(const SizedBox());
expect(decoration.painters, hasLength(1));
expect(decoration.painters.last.disposed, true);
});
testWidgets('DecoratedSliver can update box painter', (WidgetTester tester) async {
final TestDecoration decorationA = TestDecoration();
final TestDecoration decorationB = TestDecoration();
Decoration activateDecoration = decorationA;
late StateSetter localSetState;
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
localSetState = setState;
return CustomScrollView(
slivers: <Widget>[
DecoratedSliver(
decoration: activateDecoration,
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 100, height: 100),
),
)
],
);
},
)
)
));
expect(decorationA.painters, hasLength(1));
expect(decorationA.painters.last.paintCount, 1);
expect(decorationB.painters, hasLength(0));
localSetState(() {
activateDecoration = decorationB;
});
await tester.pump();
expect(decorationA.painters, hasLength(1));
expect(decorationB.painters, hasLength(1));
expect(decorationB.painters.last.paintCount, 1);
});
testWidgets('DecoratedSliver can update DecorationPosition', (WidgetTester tester) async {
final TestDecoration decoration = TestDecoration();
DecorationPosition activePosition = DecorationPosition.foreground;
late StateSetter localSetState;
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
localSetState = setState;
return CustomScrollView(
slivers: <Widget>[
DecoratedSliver(
decoration: decoration,
position: activePosition,
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 100, height: 100),
),
)
],
);
},
)
)
));
expect(decoration.painters, hasLength(1));
expect(decoration.painters.last.paintCount, 1);
localSetState(() {
activePosition = DecorationPosition.background;
});
await tester.pump();
expect(decoration.painters, hasLength(1));
expect(decoration.painters.last.paintCount, 2);
});
testWidgets('DecoratedSliver golden test', (WidgetTester tester) async {
const BoxDecoration decoration = BoxDecoration(
color: Colors.blue,
);
final Key backgroundKey = UniqueKey();
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: RepaintBoundary(
key: backgroundKey,
child: CustomScrollView(
slivers: <Widget>[
DecoratedSliver(
decoration: decoration,
sliver: SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverList(
delegate: SliverChildListDelegate.fixed(<Widget>[
Container(
height: 100,
color: Colors.red,
),
Container(
height: 100,
color: Colors.yellow,
),
Container(
height: 100,
color: Colors.red,
),
]),
),
),
),
],
),
),
)
));
await expectLater(find.byKey(backgroundKey), matchesGoldenFile('decorated_sliver.moon.background.png'));
final Key foregroundKey = UniqueKey();
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: RepaintBoundary(
key: foregroundKey,
child: CustomScrollView(
slivers: <Widget>[
DecoratedSliver(
decoration: decoration,
position: DecorationPosition.foreground,
sliver: SliverPadding(
padding: const EdgeInsets.all(16),
sliver: SliverList(
delegate: SliverChildListDelegate.fixed(<Widget>[
Container(
height: 100,
color: Colors.red,
),
Container(
height: 100,
color: Colors.yellow,
),
Container(
height: 100,
color: Colors.red,
),
]),
),
),
),
],
),
),
)
));
await expectLater(find.byKey(foregroundKey), matchesGoldenFile('decorated_sliver.moon.foreground.png'));
});
testWidgets('DecoratedSliver paints its border correctly vertically', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300,
width: 100,
child: CustomScrollView(
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 100, height: 500),
),
),
],
),
),
),
));
controller.jumpTo(200);
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, -199.5) & const Size(99, 499),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver paints its border correctly vertically reverse', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 300,
width: 100,
child: CustomScrollView(
controller: controller,
reverse: true,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 100, height: 500),
),
),
],
),
),
),
));
controller.jumpTo(200);
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, -199.5) & const Size(99, 499),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver paints its border correctly horizontally', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 100,
width: 300,
child: CustomScrollView(
scrollDirection: Axis.horizontal,
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 500, height: 100),
),
),
],
),
),
),
));
controller.jumpTo(200);
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(-199.5, 0.5) & const Size(499, 99),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver paints its border correctly horizontally reverse', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 100,
width: 300,
child: CustomScrollView(
scrollDirection: Axis.horizontal,
reverse: true,
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverToBoxAdapter(
child: SizedBox(width: 500, height: 100),
),
),
],
),
),
),
));
controller.jumpTo(200);
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(-199.5, 0.5) & const Size(499, 99),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver works with SliverMainAxisGroup', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 100,
width: 300,
child: CustomScrollView(
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverMainAxisGroup(
slivers: <Widget>[
SliverToBoxAdapter(child: SizedBox(height: 100)),
SliverToBoxAdapter(child: SizedBox(height: 100)),
],
),
),
],
),
),
),
));
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, 0.5) & const Size(299, 199),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver works with SliverCrossAxisGroup', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 100,
width: 300,
child: CustomScrollView(
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: const SliverCrossAxisGroup(
slivers: <Widget>[
SliverToBoxAdapter(child: SizedBox(height: 100)),
SliverToBoxAdapter(child: SizedBox(height: 100)),
],
),
),
],
),
),
),
));
await tester.pumpAndSettle();
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, 0.5) & const Size(299, 99),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
testWidgets('DecoratedSliver draws only up to the bottom cache when sliver has infinite scroll extent', (WidgetTester tester) async {
const Key key = Key('DecoratedSliver with border');
const Color black = Color(0xFF000000);
final ScrollController controller = ScrollController();
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Align(
alignment: Alignment.topLeft,
child: SizedBox(
height: 100,
width: 300,
child: CustomScrollView(
controller: controller,
slivers: <Widget>[
DecoratedSliver(
key: key,
decoration: BoxDecoration(border: Border.all()),
sliver: SliverList.builder(
itemBuilder: (BuildContext context, int index) => const SizedBox(height: 100),
),
),
],
),
),
),
));
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, 0.5) & const Size(299, 349),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
controller.jumpTo(200);
await tester.pumpAndSettle();
// Note that the bottom edge is of the rect is the same as above.
expect(find.byKey(key), paints..rect(
rect: const Offset(0.5, -199.5) & const Size(299, 549),
color: black,
style: PaintingStyle.stroke,
strokeWidth: 1.0,
));
});
}
class TestDecoration extends Decoration {
final List<TestBoxPainter> painters = <TestBoxPainter>[];
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
final TestBoxPainter painter = TestBoxPainter();
painters.add(painter);
return painter;
}
}
class TestBoxPainter extends BoxPainter {
Offset? lastOffset;
ImageConfiguration? lastConfiguration;
bool disposed = false;
int paintCount = 0;
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
lastOffset = offset;
lastConfiguration = configuration;
paintCount += 1;
}
@override
void dispose() {
assert(!disposed);
disposed = true;
super.dispose();
}
}