Unverified Commit 8a5ace25 authored by Jia Hao's avatar Jia Hao Committed by GitHub

Improve performance of Widget Tests (#70730)

parent 492ec23b
......@@ -1341,6 +1341,10 @@ class _IntrinsicDimensionsCacheEntry {
/// [computeMinIntrinsicWidth], [computeMaxIntrinsicWidth],
/// [computeMinIntrinsicHeight], [computeMaxIntrinsicHeight].
///
/// Be sure to set [debugCheckIntrinsicSizes] to true in your unit tests if you
/// do override any of these methods, which will add additional checks to
/// help validate your implementation.
///
/// In addition, if the box has any children, it must implement
/// [computeDistanceToActualBaseline]. [RenderProxyBox] provides a simple
/// implementation that forwards to the child; [RenderShiftedBox] provides an
......@@ -1445,6 +1449,10 @@ abstract class RenderBox extends RenderObject {
///
/// This function should never return a negative or infinite value.
///
/// Be sure to set [debugCheckIntrinsicSizes] to true in your unit tests if
/// you do override this method, which will add additional checks to help
/// validate your implementation.
///
/// ## Examples
///
/// ### Text
......@@ -1597,6 +1605,10 @@ abstract class RenderBox extends RenderObject {
///
/// This function should never return a negative or infinite value.
///
/// Be sure to set [debugCheckIntrinsicSizes] to true in your unit tests if
/// you do override this method, which will add additional checks to help
/// validate your implementation.
///
/// See also:
///
/// * [computeMinIntrinsicWidth], which has usage examples.
......@@ -1675,6 +1687,10 @@ abstract class RenderBox extends RenderObject {
///
/// This function should never return a negative or infinite value.
///
/// Be sure to set [debugCheckIntrinsicSizes] to true in your unit tests if
/// you do override this method, which will add additional checks to help
/// validate your implementation.
///
/// See also:
///
/// * [computeMinIntrinsicWidth], which has usage examples.
......@@ -1760,6 +1776,10 @@ abstract class RenderBox extends RenderObject {
///
/// This function should never return a negative or infinite value.
///
/// Be sure to set [debugCheckIntrinsicSizes] to true in your unit tests if
/// you do override this method, which will add additional checks to help
/// validate your implementation.
///
/// See also:
///
/// * [computeMinIntrinsicWidth], which has usage examples.
......
......@@ -132,8 +132,9 @@ bool debugPrintLayouts = false;
/// Check the intrinsic sizes of each [RenderBox] during layout.
///
/// By default this is turned off since these checks are expensive, but it is
/// enabled by the test framework.
/// By default this is turned off since these checks are expensive. If you are
/// implementing your own children of [RenderBox] with custom intrinsics, turn
/// this on in your unit tests for additional validations.
bool debugCheckIntrinsicSizes = false;
/// Adds [dart:developer.Timeline] events for every [RenderObject] layout.
......
......@@ -2,5 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export '_goldens_io.dart'
if (dart.library.html) '_goldens_web.dart' show testExecutable;
import 'dart:async';
import 'package:flutter/rendering.dart';
import '_goldens_io.dart'
if (dart.library.html) '_goldens_web.dart' as flutter_goldens;
Future<void> testExecutable(FutureOr<void> testMain()) {
// Enable checks because there are many implementations of [RenderBox] in this
// package can benefit from the additional validations.
debugCheckIntrinsicSizes = true;
return flutter_goldens.testExecutable(testMain);
}
......@@ -60,6 +60,21 @@ class RenderIntrinsicSize extends RenderProxyBox {
}
}
class RenderInvalidIntrinsics extends RenderBox {
@override
bool get sizedByParent => true;
@override
double computeMinIntrinsicWidth(double height) => -1;
@override
double computeMaxIntrinsicWidth(double height) => -1;
@override
double computeMinIntrinsicHeight(double width) => -1;
@override
double computeMaxIntrinsicHeight(double width) => -1;
@override
Size computeDryLayout(BoxConstraints constraints) => const Size(0, 0);
}
void main() {
test('Whether using intrinsics means you get hooked into layout', () {
RenderBox root;
......@@ -84,36 +99,49 @@ void main() {
expect(root.size, equals(inner.size));
});
test('When RenderObject.debugCheckingIntrinsics is true, parent returns correct intrinsics', () {
RenderObject.debugCheckingIntrinsics = true;
test('Parent returns correct intrinsics', () {
RenderParentSize parent;
RenderFixedSize inner;
try {
RenderParentSize parent;
RenderFixedSize inner;
layout(
RenderIntrinsicSize(
child: parent = RenderParentSize(
child: inner = RenderFixedSize()
)
),
constraints: const BoxConstraints(
minWidth: 0.0,
minHeight: 0.0,
maxWidth: 1000.0,
maxHeight: 1000.0,
),
);
_expectIntrinsicDimensions(parent, 100);
layout(
RenderIntrinsicSize(
child: parent = RenderParentSize(
child: inner = RenderFixedSize()
)
),
inner.grow();
pumpFrame();
_expectIntrinsicDimensions(parent, 200);
});
test('Intrinsic checks are turned on', () async {
final List<FlutterErrorDetails> errorDetails = <FlutterErrorDetails>[];
layout(RenderInvalidIntrinsics(),
constraints: const BoxConstraints(
minWidth: 0.0,
minHeight: 0.0,
maxWidth: 1000.0,
maxHeight: 1000.0,
),
);
_expectIntrinsicDimensions(parent, 100);
inner.grow();
pumpFrame();
_expectIntrinsicDimensions(parent, 200);
} finally {
RenderObject.debugCheckingIntrinsics = false;
}
), onErrors: () {
errorDetails.addAll(renderer.takeAllFlutterErrorDetails());
});
expect(errorDetails, isNotEmpty);
expect(
errorDetails.map((FlutterErrorDetails details) => details.toString()),
everyElement(contains('violate the intrinsic protocol')),
);
});
}
......
......@@ -181,7 +181,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
TestWidgetsFlutterBinding() : _window = TestWindow(window: ui.window) {
debugPrint = debugPrintOverride;
debugDisableShadows = disableShadows;
debugCheckIntrinsicSizes = checkIntrinsicSizes;
}
@override
......@@ -287,14 +286,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
/// equivalent as [Future.delayed].
Future<void> delayed(Duration duration);
/// The value to set [debugCheckIntrinsicSizes] to while tests are running.
///
/// This can be used to enable additional checks. For example,
/// [AutomatedTestWidgetsFlutterBinding] sets this to true, so that all tests
/// always run with aggressive intrinsic sizing tests enabled.
@protected
bool get checkIntrinsicSizes => false;
/// Creates and initializes the binding. This function is
/// idempotent; calling it a second time will just return the
/// previously-created instance.
......@@ -782,6 +773,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
Future<void> _runTestBody(Future<void> testBody(), VoidCallback invariantTester) async {
assert(inTest);
// So that we can assert that it remains the same after the test finishes.
_beforeTestCheckIntrinsicSizes = debugCheckIntrinsicSizes;
runApp(Container(key: UniqueKey(), child: _preTestMessage)); // Reset the tree to a known state.
await pump();
......@@ -814,6 +807,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
asyncBarrier(); // When using AutomatedTestWidgetsFlutterBinding, this flushes the microtasks.
}
late bool _beforeTestCheckIntrinsicSizes;
void _verifyInvariants() {
assert(debugAssertNoTransientCallbacks(
'An animation is still running even after the widget tree was disposed.'
......@@ -831,7 +826,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
));
assert(debugAssertAllRenderVarsUnset(
'The value of a rendering debug variable was changed by the test.',
debugCheckIntrinsicSizesOverride: checkIntrinsicSizes,
debugCheckIntrinsicSizesOverride: _beforeTestCheckIntrinsicSizes,
));
assert(debugAssertAllWidgetVarsUnset(
'The value of a widget debug variable was changed by the test.',
......@@ -944,9 +939,6 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
@override
bool get disableShadows => true;
@override
bool get checkIntrinsicSizes => true;
/// The value of [defaultTestTimeout] can be set to `None` to enable debugging flutter tests where
/// we would not want to timeout the test. This is expected to be used by test tooling which
/// can detect debug mode.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment