blob: c27c57d94487e377d3a53cae05084295041e368e [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' show ByteData;
import 'dart:ui' as ui hide window;
/// [SingletonFlutterWindow] that wraps another [SingletonFlutterWindow] and
/// allows faking of some properties for testing purposes.
///
/// Tests for certain widgets, e.g., [MaterialApp], might require faking certain
/// properties of a [SingletonFlutterWindow]. [TestWindow] facilitates the
/// faking of these properties by overriding the properties of a real
/// [SingletonFlutterWindow] with desired fake values. The binding used within
/// tests, [TestWidgetsFlutterBinding], contains a [TestWindow] that is used by
/// all tests.
///
/// ## Sample Code
///
/// A test can utilize a [TestWindow] in the following way:
///
/// ```dart
/// testWidgets('your test name here', (WidgetTester tester) async {
/// // Retrieve the TestWidgetsFlutterBinding.
/// final TestWidgetsFlutterBinding testBinding = tester.binding;
///
/// // Fake the desired properties of the TestWindow. All code running
/// // within this test will perceive the following fake text scale
/// // factor as the real text scale factor of the window.
/// testBinding.window.textScaleFactorFakeValue = 2.5;
///
/// // Test code that depends on text scale factor here.
/// });
/// ```
///
/// The [TestWidgetsFlutterBinding] is recreated for each test and
/// therefore any fake values defined in one test will not persist
/// to the next.
///
/// If a test needs to override a real [SingletonFlutterWindow] property and
/// then later return to using the real [SingletonFlutterWindow] property,
/// [TestWindow] provides methods to clear each individual test value, e.g.,
/// [clearLocaleTestValue()].
///
/// To clear all fake test values in a [TestWindow], consider using
/// [clearAllTestValues()].
class TestWindow implements ui.SingletonFlutterWindow {
/// Constructs a [TestWindow] that defers all behavior to the given
/// [dart:ui.SingletonFlutterWindow] unless explicitly overridden for test purposes.
TestWindow({
required ui.SingletonFlutterWindow window,
}) : _window = window;
/// The [dart:ui.SingletonFlutterWindow] that is wrapped by this [TestWindow].
final ui.SingletonFlutterWindow _window;
@override
double get devicePixelRatio => _devicePixelRatio ?? _window.devicePixelRatio;
double? _devicePixelRatio;
/// Hides the real device pixel ratio and reports the given [devicePixelRatio]
/// instead.
set devicePixelRatioTestValue(double devicePixelRatio) {
_devicePixelRatio = devicePixelRatio;
onMetricsChanged?.call();
}
/// Deletes any existing test device pixel ratio and returns to using the real
/// device pixel ratio.
void clearDevicePixelRatioTestValue() {
_devicePixelRatio = null;
onMetricsChanged?.call();
}
@override
ui.Size get physicalSize => _physicalSizeTestValue ?? _window.physicalSize;
ui.Size? _physicalSizeTestValue;
/// Hides the real physical size and reports the given [physicalSizeTestValue]
/// instead.
set physicalSizeTestValue (ui.Size physicalSizeTestValue) {
_physicalSizeTestValue = physicalSizeTestValue;
onMetricsChanged?.call();
}
/// Deletes any existing test physical size and returns to using the real
/// physical size.
void clearPhysicalSizeTestValue() {
_physicalSizeTestValue = null;
onMetricsChanged?.call();
}
@override
ui.WindowPadding get viewInsets => _viewInsetsTestValue ?? _window.viewInsets;
ui.WindowPadding? _viewInsetsTestValue;
/// Hides the real view insets and reports the given [viewInsetsTestValue]
/// instead.
set viewInsetsTestValue(ui.WindowPadding viewInsetsTestValue) {
_viewInsetsTestValue = viewInsetsTestValue;
onMetricsChanged?.call();
}
/// Deletes any existing test view insets and returns to using the real view
/// insets.
void clearViewInsetsTestValue() {
_viewInsetsTestValue = null;
onMetricsChanged?.call();
}
@override
ui.WindowPadding get viewPadding => _viewPaddingTestValue ?? _window.padding;
ui.WindowPadding? _viewPaddingTestValue;
/// Hides the real view padding and reports the given [paddingTestValue]
/// instead.
set viewPaddingTestValue(ui.WindowPadding viewPaddingTestValue) {
_viewPaddingTestValue = viewPaddingTestValue;
onMetricsChanged?.call();
}
/// Deletes any existing test view padding and returns to using the real
/// viewPadding.
void clearViewPaddingTestValue() {
_viewPaddingTestValue = null;
onMetricsChanged?.call();
}
@override
ui.WindowPadding get padding => _paddingTestValue ?? _window.padding;
ui.WindowPadding? _paddingTestValue;
/// Hides the real padding and reports the given [paddingTestValue] instead.
set paddingTestValue(ui.WindowPadding paddingTestValue) {
_paddingTestValue = paddingTestValue;
onMetricsChanged?.call();
}
/// Deletes any existing test padding and returns to using the real padding.
void clearPaddingTestValue() {
_paddingTestValue = null;
onMetricsChanged?.call();
}
@override
ui.WindowPadding get systemGestureInsets => _systemGestureInsetsTestValue ?? _window.systemGestureInsets;
ui.WindowPadding? _systemGestureInsetsTestValue;
/// Hides the real system gesture insets and reports the given [systemGestureInsetsTestValue] instead.
set systemGestureInsetsTestValue(ui.WindowPadding systemGestureInsetsTestValue) {
_systemGestureInsetsTestValue = systemGestureInsetsTestValue;
onMetricsChanged?.call();
}
/// Deletes any existing test system gesture insets and returns to using the real system gesture insets.
void clearSystemGestureInsetsTestValue() {
_systemGestureInsetsTestValue = null;
onMetricsChanged?.call();
}
@override
ui.VoidCallback? get onMetricsChanged => platformDispatcher.onMetricsChanged;
@override
set onMetricsChanged(ui.VoidCallback? callback) {
platformDispatcher.onMetricsChanged = callback;
}
@override
ui.Locale get locale => _localeTestValue ?? platformDispatcher.locale;
ui.Locale? _localeTestValue;
/// Hides the real locale and reports the given [localeTestValue] instead.
set localeTestValue(ui.Locale localeTestValue) {
_localeTestValue = localeTestValue;
onLocaleChanged?.call();
}
/// Deletes any existing test locale and returns to using the real locale.
void clearLocaleTestValue() {
_localeTestValue = null;
onLocaleChanged?.call();
}
@override
List<ui.Locale> get locales => _localesTestValue ?? platformDispatcher.locales;
List<ui.Locale>? _localesTestValue;
/// Hides the real locales and reports the given [localesTestValue] instead.
set localesTestValue(List<ui.Locale> localesTestValue) {
_localesTestValue = localesTestValue;
onLocaleChanged?.call();
}
/// Deletes any existing test locales and returns to using the real locales.
void clearLocalesTestValue() {
_localesTestValue = null;
onLocaleChanged?.call();
}
@override
ui.VoidCallback? get onLocaleChanged => platformDispatcher.onLocaleChanged;
@override
set onLocaleChanged(ui.VoidCallback? callback) {
platformDispatcher.onLocaleChanged = callback;
}
@override
String get initialLifecycleState => _initialLifecycleStateTestValue;
String _initialLifecycleStateTestValue = '';
/// Sets a faked initialLifecycleState for testing.
set initialLifecycleStateTestValue(String state) {
_initialLifecycleStateTestValue = state;
}
@override
double get textScaleFactor => _textScaleFactorTestValue ?? platformDispatcher.textScaleFactor;
double? _textScaleFactorTestValue;
/// Hides the real text scale factor and reports the given
/// [textScaleFactorTestValue] instead.
set textScaleFactorTestValue(double textScaleFactorTestValue) {
_textScaleFactorTestValue = textScaleFactorTestValue;
onTextScaleFactorChanged?.call();
}
/// Deletes any existing test text scale factor and returns to using the real
/// text scale factor.
void clearTextScaleFactorTestValue() {
_textScaleFactorTestValue = null;
onTextScaleFactorChanged?.call();
}
@override
ui.Brightness get platformBrightness => _platformBrightnessTestValue ?? platformDispatcher.platformBrightness;
ui.Brightness? _platformBrightnessTestValue;
@override
ui.VoidCallback? get onPlatformBrightnessChanged => platformDispatcher.onPlatformBrightnessChanged;
@override
set onPlatformBrightnessChanged(ui.VoidCallback? callback) {
platformDispatcher.onPlatformBrightnessChanged = callback;
}
/// Hides the real text scale factor and reports the given
/// [platformBrightnessTestValue] instead.
set platformBrightnessTestValue(ui.Brightness platformBrightnessTestValue) {
_platformBrightnessTestValue = platformBrightnessTestValue;
onPlatformBrightnessChanged?.call();
}
/// Deletes any existing test platform brightness and returns to using the
/// real platform brightness.
void clearPlatformBrightnessTestValue() {
_platformBrightnessTestValue = null;
onPlatformBrightnessChanged?.call();
}
@override
bool get alwaysUse24HourFormat => _alwaysUse24HourFormatTestValue ?? platformDispatcher.alwaysUse24HourFormat;
bool? _alwaysUse24HourFormatTestValue;
/// Hides the real clock format and reports the given
/// [alwaysUse24HourFormatTestValue] instead.
set alwaysUse24HourFormatTestValue(bool alwaysUse24HourFormatTestValue) {
_alwaysUse24HourFormatTestValue = alwaysUse24HourFormatTestValue;
}
/// Deletes any existing test clock format and returns to using the real clock
/// format.
void clearAlwaysUse24HourTestValue() {
_alwaysUse24HourFormatTestValue = null;
}
@override
ui.VoidCallback? get onTextScaleFactorChanged => platformDispatcher.onTextScaleFactorChanged;
@override
set onTextScaleFactorChanged(ui.VoidCallback? callback) {
platformDispatcher.onTextScaleFactorChanged = callback;
}
@override
ui.FrameCallback? get onBeginFrame => platformDispatcher.onBeginFrame;
@override
set onBeginFrame(ui.FrameCallback? callback) {
platformDispatcher.onBeginFrame = callback;
}
@override
ui.VoidCallback? get onDrawFrame => platformDispatcher.onDrawFrame;
@override
set onDrawFrame(ui.VoidCallback? callback) {
platformDispatcher.onDrawFrame = callback;
}
@override
ui.TimingsCallback? get onReportTimings => platformDispatcher.onReportTimings;
@override
set onReportTimings(ui.TimingsCallback? callback) {
platformDispatcher.onReportTimings = callback;
}
@override
ui.PointerDataPacketCallback? get onPointerDataPacket => platformDispatcher.onPointerDataPacket;
@override
set onPointerDataPacket(ui.PointerDataPacketCallback? callback) {
platformDispatcher.onPointerDataPacket = callback;
}
@override
String get defaultRouteName => _defaultRouteNameTestValue ?? platformDispatcher.defaultRouteName;
String? _defaultRouteNameTestValue;
/// Hides the real default route name and reports the given
/// [defaultRouteNameTestValue] instead.
set defaultRouteNameTestValue(String defaultRouteNameTestValue) {
_defaultRouteNameTestValue = defaultRouteNameTestValue;
}
/// Deletes any existing test default route name and returns to using the real
/// default route name.
void clearDefaultRouteNameTestValue() {
_defaultRouteNameTestValue = null;
}
@override
void scheduleFrame() {
platformDispatcher.scheduleFrame();
}
@override
void render(ui.Scene scene) {
_window.render(scene);
}
@override
bool get semanticsEnabled => _semanticsEnabledTestValue ?? platformDispatcher.semanticsEnabled;
bool? _semanticsEnabledTestValue;
/// Hides the real semantics enabled and reports the given
/// [semanticsEnabledTestValue] instead.
set semanticsEnabledTestValue(bool semanticsEnabledTestValue) {
_semanticsEnabledTestValue = semanticsEnabledTestValue;
onSemanticsEnabledChanged?.call();
}
/// Deletes any existing test semantics enabled and returns to using the real
/// semantics enabled.
void clearSemanticsEnabledTestValue() {
_semanticsEnabledTestValue = null;
onSemanticsEnabledChanged?.call();
}
@override
ui.VoidCallback? get onSemanticsEnabledChanged => platformDispatcher.onSemanticsEnabledChanged;
@override
set onSemanticsEnabledChanged(ui.VoidCallback? callback) {
platformDispatcher.onSemanticsEnabledChanged = callback;
}
@override
ui.SemanticsActionCallback? get onSemanticsAction => platformDispatcher.onSemanticsAction;
@override
set onSemanticsAction(ui.SemanticsActionCallback? callback) {
platformDispatcher.onSemanticsAction = callback;
}
@override
ui.AccessibilityFeatures get accessibilityFeatures => _accessibilityFeaturesTestValue ?? platformDispatcher.accessibilityFeatures;
ui.AccessibilityFeatures? _accessibilityFeaturesTestValue;
/// Hides the real accessibility features and reports the given
/// [accessibilityFeaturesTestValue] instead.
set accessibilityFeaturesTestValue(ui.AccessibilityFeatures accessibilityFeaturesTestValue) {
_accessibilityFeaturesTestValue = accessibilityFeaturesTestValue;
onAccessibilityFeaturesChanged?.call();
}
/// Deletes any existing test accessibility features and returns to using the
/// real accessibility features.
void clearAccessibilityFeaturesTestValue() {
_accessibilityFeaturesTestValue = null;
onAccessibilityFeaturesChanged?.call();
}
@override
ui.VoidCallback? get onAccessibilityFeaturesChanged => platformDispatcher.onAccessibilityFeaturesChanged;
@override
set onAccessibilityFeaturesChanged(ui.VoidCallback? callback) {
platformDispatcher.onAccessibilityFeaturesChanged = callback;
}
@override
void updateSemantics(ui.SemanticsUpdate update) {
platformDispatcher.updateSemantics(update);
}
@override
void setIsolateDebugName(String name) {
platformDispatcher.setIsolateDebugName(name);
}
@override
void sendPlatformMessage(
String name,
ByteData? data,
ui.PlatformMessageResponseCallback? callback,
) {
platformDispatcher.sendPlatformMessage(name, data, callback);
}
@Deprecated(
'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. '
'This feature was deprecated after v2.1.0-10.0.pre.'
)
@override
ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
@Deprecated(
'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. '
'This feature was deprecated after v2.1.0-10.0.pre.'
)
@override
set onPlatformMessage(ui.PlatformMessageCallback? callback) {
platformDispatcher.onPlatformMessage = callback;
}
@override
ui.PlatformDispatcher get platformDispatcher => _window.platformDispatcher;
/// Delete any test value properties that have been set on this [TestWindow]
/// and return to reporting the real [SingletonFlutterWindow] values for all
/// [SingletonFlutterWindow] properties.
///
/// If desired, clearing of properties can be done on an individual basis,
/// e.g., [clearLocaleTestValue()].
void clearAllTestValues() {
clearAccessibilityFeaturesTestValue();
clearAlwaysUse24HourTestValue();
clearDefaultRouteNameTestValue();
clearDevicePixelRatioTestValue();
clearPlatformBrightnessTestValue();
clearLocaleTestValue();
clearLocalesTestValue();
clearPaddingTestValue();
clearPhysicalSizeTestValue();
clearSemanticsEnabledTestValue();
clearTextScaleFactorTestValue();
clearViewInsetsTestValue();
}
/// This gives us some grace time when the dart:ui side adds something to
/// Window, and makes things easier when we do rolls to give us time to catch
/// up.
@override
dynamic noSuchMethod(Invocation invocation) {
return null;
}
}