blob: af9fa9dca52f06f945509069b322171dcdcf1156 [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.
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
const double _crispText = 100.0; // this font size is selected to avoid needing any antialiasing.
const String _expText = 'Éxp'; // renders in the test font as:
// ########
// ########
// ########
// ########
//
// ÉÉÉÉxxxxpppp
void main() {
testWidgets('Default background', (WidgetTester tester) async {
await tester.pumpWidget(const Align(
alignment: Alignment.topLeft,
child: Text(_expText, textDirection: TextDirection.ltr, style: TextStyle(color: Color(0xFF345678), fontSize: _crispText))),
);
await _expectColors(
tester,
find.byType(Align),
<Color>{ const Color(0x00000000), const Color(0xFF345678) },
<Offset, Color>{
Offset.zero: const Color(0xFF345678), // the text
const Offset(10, 10): const Color(0xFF345678), // the text
const Offset(50, 95): const Color(0x00000000), // the background (under the É)
const Offset(250, 50): const Color(0x00000000), // the text (above the p)
const Offset(250, 95): const Color(0xFF345678), // the text (the p)
const Offset(400, 400): const Color(0x00000000), // the background
const Offset(799, 599): const Color(0x00000000), // the background
},
);
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
testWidgets('Default text color', (WidgetTester tester) async {
await tester.pumpWidget(const ColoredBox(
color: Color(0xFFABCDEF),
child: Align(
alignment: Alignment.topLeft,
child: Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText)),
),
),
);
await _expectColors(
tester,
find.byType(Align),
<Color>{ const Color(0xFFABCDEF), const Color(0xFFFFFFFF) },
<Offset, Color>{
Offset.zero: const Color(0xFFFFFFFF), // the text
const Offset(10, 10): const Color(0xFFFFFFFF), // the text
const Offset(50, 95): const Color(0xFFABCDEF), // the background (under the É)
const Offset(250, 50): const Color(0xFFABCDEF), // the text (above the p)
const Offset(250, 95): const Color(0xFFFFFFFF), // the text (the p)
const Offset(400, 400): const Color(0xFFABCDEF), // the background
const Offset(799, 599): const Color(0xFFABCDEF), // the background
},
);
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
testWidgets('Default text selection color', (WidgetTester tester) async {
final GlobalKey key = GlobalKey();
await tester.pumpWidget(
ColoredBox(
color: const Color(0xFFFFFFFF),
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(),
child: Overlay(
initialEntries: <OverlayEntry>[
OverlayEntry(
builder: (BuildContext context) => SelectableRegion(
focusNode: FocusNode(),
selectionControls: emptyTextSelectionControls,
child: Align(
key: key,
alignment: Alignment.topLeft,
child: const Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText, color: Color(0xFF000000))),
),
),
),
],
),
),
),
),
);
await tester.pumpAndSettle();
await _expectColors(
tester,
find.byType(Align),
<Color>{ const Color(0xFFFFFFFF), const Color(0xFF000000) },
);
// fake a "select all" event to select the text
Actions.invoke(key.currentContext!, const SelectAllTextIntent(SelectionChangedCause.keyboard));
await tester.pump();
await _expectColors(
tester,
find.byType(Align),
<Color>{ const Color(0xFFFFFFFF), const Color(0xFF000000), const Color(0xFFBFBFBF) }, // 0x80808080 blended with 0xFFFFFFFF
<Offset, Color>{
Offset.zero: const Color(0xFF000000), // the selected text
const Offset(10, 10): const Color(0xFF000000), // the selected text
const Offset(50, 95): const Color(0xFFBFBFBF), // the selected background (under the É)
const Offset(250, 50): const Color(0xFFBFBFBF), // the selected background (above the p)
const Offset(250, 95): const Color(0xFF000000), // the selected text (the p)
const Offset(400, 400): const Color(0xFFFFFFFF), // the background
const Offset(799, 599): const Color(0xFFFFFFFF), // the background
},
);
}, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently.
}
Color _getPixel(ByteData bytes, int x, int y, int width) {
final int offset = (x + y * width) * 4;
return Color.fromARGB(
bytes.getUint8(offset + 3),
bytes.getUint8(offset + 0),
bytes.getUint8(offset + 1),
bytes.getUint8(offset + 2),
);
}
Future<void> _expectColors(WidgetTester tester, Finder finder, Set<Color> allowedColors, [ Map<Offset, Color>? spotChecks ]) async {
final TestWidgetsFlutterBinding binding = tester.binding;
final ui.Image image = (await binding.runAsync<ui.Image>(() => captureImage(finder.evaluate().single)))!;
final ByteData bytes = (await binding.runAsync<ByteData?>(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!;
final Set<int> actualColorValues = <int>{};
for (int offset = 0; offset < bytes.lengthInBytes; offset += 4) {
actualColorValues.add((bytes.getUint8(offset + 3) << 24) +
(bytes.getUint8(offset + 0) << 16) +
(bytes.getUint8(offset + 1) << 8) +
(bytes.getUint8(offset + 2)));
}
final Set<Color> actualColors = actualColorValues.map((int value) => Color(value)).toSet();
expect(actualColors, allowedColors);
spotChecks?.forEach((Offset position, Color expected) {
assert(position.dx.round() >= 0);
assert(position.dx.round() < image.width);
assert(position.dy.round() >= 0);
assert(position.dy.round() < image.height);
final Offset precisePosition = position * tester.view.devicePixelRatio;
final Color actual = _getPixel(bytes, precisePosition.dx.round(), precisePosition.dy.round(), image.width);
expect(actual, expected, reason: 'Pixel at $position is $actual but expected $expected.');
});
}