Kate Lovett a04fb324be
Bump Dart to 3.8 and reformat (#171703)
Bumps the Dart version to 3.8 across the repo (excluding
engine/src/flutter/third_party) and applies formatting updates from Dart
3.8.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
2025-07-07 17:58:32 +00:00

343 lines
11 KiB
Dart

// 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.
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
class TestCanvas implements Canvas {
final List<Invocation> invocations = <Invocation>[];
@override
void noSuchMethod(Invocation invocation) {
invocations.add(invocation);
}
}
void main() {
// the textDirection values below are intentionally sometimes different and
// sometimes the same as the layoutDirection, to make sure that they don't
// affect the layout.
test('A Banner with a location of topStart paints in the top left (LTR)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.rtl,
location: BannerLocation.topStart,
layoutDirection: TextDirection.ltr,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], lessThan(100.0));
expect(translateCommand.positionalArguments[1], lessThan(100.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0));
});
test('A Banner with a location of topStart paints in the top right (RTL)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.ltr,
location: BannerLocation.topStart,
layoutDirection: TextDirection.rtl,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
expect(translateCommand.positionalArguments[1], lessThan(100.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0));
});
test('A Banner with a location of topEnd paints in the top right (LTR)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.ltr,
location: BannerLocation.topEnd,
layoutDirection: TextDirection.ltr,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
expect(translateCommand.positionalArguments[1], lessThan(100.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0));
});
test('A Banner with a location of topEnd paints in the top left (RTL)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.rtl,
location: BannerLocation.topEnd,
layoutDirection: TextDirection.rtl,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], lessThan(100.0));
expect(translateCommand.positionalArguments[1], lessThan(100.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0));
});
test('A Banner with a location of bottomStart paints in the bottom left (LTR)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.ltr,
location: BannerLocation.bottomStart,
layoutDirection: TextDirection.ltr,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], lessThan(100.0));
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0));
});
test('A Banner with a location of bottomStart paints in the bottom right (RTL)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.rtl,
location: BannerLocation.bottomStart,
layoutDirection: TextDirection.rtl,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0));
});
test('A Banner with a location of bottomEnd paints in the bottom right (LTR)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.rtl,
location: BannerLocation.bottomEnd,
layoutDirection: TextDirection.ltr,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(-math.pi / 4.0));
});
test('A Banner with a location of bottomEnd paints in the bottom left (RTL)', () {
final BannerPainter bannerPainter = BannerPainter(
message: 'foo',
textDirection: TextDirection.ltr,
location: BannerLocation.bottomEnd,
layoutDirection: TextDirection.rtl,
);
final TestCanvas canvas = TestCanvas();
bannerPainter.paint(canvas, const Size(1000.0, 1000.0));
final Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #translate;
});
expect(translateCommand, isNotNull);
expect(translateCommand.positionalArguments[0], lessThan(100.0));
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
final Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
return invocation.memberName == #rotate;
});
expect(rotateCommand, isNotNull);
expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0));
});
testWidgets('Banner widget', (WidgetTester tester) async {
debugDisableShadows = false;
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: Banner(message: 'Hello', location: BannerLocation.topEnd),
),
);
expect(
find.byType(CustomPaint),
paints
..save()
..translate(x: 800.0, y: 0.0)
..rotate(angle: math.pi / 4.0)
..rect(
rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0),
color: const Color(0x7f000000),
hasMaskFilter: true,
)
..rect(
rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0),
color: const Color(0xa0b71c1c),
hasMaskFilter: false,
)
..paragraph(offset: const Offset(-40.0, 29.0))
..restore(),
);
debugDisableShadows = true;
});
testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async {
debugDisableShadows = false;
await tester.pumpWidget(const MaterialApp(home: Placeholder()));
expect(
find.byType(CheckedModeBanner),
paints
..save()
..translate(x: 800.0, y: 0.0)
..rotate(angle: math.pi / 4.0)
..rect(
rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0),
color: const Color(0x7f000000),
hasMaskFilter: true,
)
..rect(
rect: const Rect.fromLTRB(-40.0, 28.0, 40.0, 40.0),
color: const Color(0xa0b71c1c),
hasMaskFilter: false,
)
..paragraph(offset: const Offset(-40.0, 29.0))
..restore(),
);
debugDisableShadows = true;
});
test('BannerPainter dispatches memory events', () async {
await expectLater(
await memoryEvents(
() => BannerPainter(
message: 'foo',
textDirection: TextDirection.rtl,
location: BannerLocation.topStart,
layoutDirection: TextDirection.ltr,
).dispose(),
BannerPainter,
),
areCreateAndDispose,
);
});
testWidgets('Can configure shadow for Banner widget', (WidgetTester tester) async {
debugDisableShadows = false;
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: Banner(
message: 'Shadow banner',
location: BannerLocation.topEnd,
shadow: BoxShadow(color: Color(0xFF008000), blurRadius: 8.0),
),
),
);
final Finder customPaint = find.byType(CustomPaint);
expect(customPaint, findsOneWidget);
final CustomPaint paintWidget = tester.widget(customPaint);
final BannerPainter painter = paintWidget.foregroundPainter! as BannerPainter;
expect(painter.shadow.color, const Color(0xFF008000));
expect(painter.shadow.blurRadius, 8.0);
debugDisableShadows = true;
});
}