mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This auto-formats all *.dart files in the repository outside of the `engine` subdirectory and enforces that these files stay formatted with a presubmit check. **Reviewers:** Please carefully review all the commits except for the one titled "formatted". The "formatted" commit was auto-generated by running `dev/tools/format.sh -a -f`. The other commits were hand-crafted to prepare the repo for the formatting change. I recommend reviewing the commits one-by-one via the "Commits" tab and avoiding Github's "Files changed" tab as it will likely slow down your browser because of the size of this PR. --------- Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
235 lines
7.6 KiB
Dart
235 lines
7.6 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 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'rendering_tester.dart';
|
|
|
|
class RenderLayoutTestBox extends RenderProxyBox {
|
|
RenderLayoutTestBox(this.onLayout, {this.onPerformLayout});
|
|
|
|
final VoidCallback onLayout;
|
|
final VoidCallback? onPerformLayout;
|
|
|
|
@override
|
|
void layout(Constraints constraints, {bool parentUsesSize = false}) {
|
|
// Doing this in tests is ok, but if you're writing your own
|
|
// render object, you want to override performLayout(), not
|
|
// layout(). Overriding layout() would remove many critical
|
|
// performance optimizations of the rendering system, as well as
|
|
// many bypassing many checked-mode integrity checks.
|
|
super.layout(constraints, parentUsesSize: parentUsesSize);
|
|
onLayout();
|
|
}
|
|
|
|
@override
|
|
bool get sizedByParent => true;
|
|
|
|
@override
|
|
void performLayout() {
|
|
child?.layout(constraints, parentUsesSize: true);
|
|
onPerformLayout?.call();
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
TestRenderingFlutterBinding.ensureInitialized();
|
|
|
|
test('moving children', () {
|
|
RenderBox child1, child2;
|
|
bool movedChild1 = false;
|
|
bool movedChild2 = false;
|
|
final RenderFlex block = RenderFlex(textDirection: TextDirection.ltr);
|
|
block.add(
|
|
child1 = RenderLayoutTestBox(() {
|
|
movedChild1 = true;
|
|
}),
|
|
);
|
|
block.add(
|
|
child2 = RenderLayoutTestBox(() {
|
|
movedChild2 = true;
|
|
}),
|
|
);
|
|
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
layout(block);
|
|
expect(movedChild1, isTrue);
|
|
expect(movedChild2, isTrue);
|
|
|
|
movedChild1 = false;
|
|
movedChild2 = false;
|
|
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
pumpFrame();
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
|
|
block.move(child1, after: child2);
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
pumpFrame();
|
|
expect(movedChild1, isTrue);
|
|
expect(movedChild2, isTrue);
|
|
|
|
movedChild1 = false;
|
|
movedChild2 = false;
|
|
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
pumpFrame();
|
|
expect(movedChild1, isFalse);
|
|
expect(movedChild2, isFalse);
|
|
});
|
|
|
|
group('Throws when illegal mutations are attempted: ', () {
|
|
FlutterError catchLayoutError(RenderBox box) {
|
|
Object? error;
|
|
layout(
|
|
box,
|
|
onErrors: () {
|
|
error = TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!.exception;
|
|
},
|
|
);
|
|
expect(error, isFlutterError);
|
|
return error! as FlutterError;
|
|
}
|
|
|
|
test('on disposed render objects', () {
|
|
final RenderBox box = RenderLayoutTestBox(() {});
|
|
box.dispose();
|
|
|
|
Object? error;
|
|
try {
|
|
box.markNeedsLayout();
|
|
} catch (e) {
|
|
error = e;
|
|
}
|
|
|
|
expect(error, isFlutterError);
|
|
expect(
|
|
(error! as FlutterError).message,
|
|
equalsIgnoringWhitespace(
|
|
'A disposed RenderObject was mutated.\n'
|
|
'The disposed RenderObject was:\n'
|
|
'${box.toStringShort()}',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('marking itself dirty in performLayout', () {
|
|
late RenderBox child1;
|
|
final RenderFlex block = RenderFlex(textDirection: TextDirection.ltr);
|
|
block.add(
|
|
child1 = RenderLayoutTestBox(
|
|
() {},
|
|
onPerformLayout: () {
|
|
child1.markNeedsLayout();
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(
|
|
catchLayoutError(block).message,
|
|
equalsIgnoringWhitespace(
|
|
'A RenderLayoutTestBox was mutated in its own performLayout implementation.\n'
|
|
'A RenderObject must not re-dirty itself while still being laid out.\n'
|
|
'The RenderObject being mutated was:\n'
|
|
'${child1.toStringShort()}\n'
|
|
'Consider using the LayoutBuilder widget to dynamically change a subtree during layout.',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('marking a sibling dirty in performLayout', () {
|
|
late RenderBox child1, child2;
|
|
final RenderFlex block = RenderFlex(textDirection: TextDirection.ltr);
|
|
block.add(child1 = RenderLayoutTestBox(() {}));
|
|
block.add(
|
|
child2 = RenderLayoutTestBox(
|
|
() {},
|
|
onPerformLayout: () {
|
|
child1.markNeedsLayout();
|
|
},
|
|
),
|
|
);
|
|
|
|
expect(
|
|
catchLayoutError(block).message,
|
|
equalsIgnoringWhitespace(
|
|
'A RenderLayoutTestBox was mutated in RenderLayoutTestBox.performLayout.\n'
|
|
'A RenderObject must not mutate another RenderObject from a different render subtree in its performLayout method.\n'
|
|
'The RenderObject being mutated was:\n'
|
|
'${child1.toStringShort()}\n'
|
|
'The RenderObject that was mutating the said RenderLayoutTestBox was:\n'
|
|
'${child2.toStringShort()}\n'
|
|
'Their common ancestor was:\n'
|
|
'${block.toStringShort()}\n'
|
|
'Mutating the layout of another RenderObject may cause some RenderObjects in its subtree to be laid out more than once. Consider using the LayoutBuilder widget to dynamically mutate a subtree during layout.',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('marking a descendant dirty in performLayout', () {
|
|
late RenderBox child1;
|
|
final RenderFlex block = RenderFlex(textDirection: TextDirection.ltr);
|
|
block.add(child1 = RenderLayoutTestBox(() {}));
|
|
block.add(RenderLayoutTestBox(child1.markNeedsLayout));
|
|
|
|
expect(
|
|
catchLayoutError(block).message,
|
|
equalsIgnoringWhitespace(
|
|
'A RenderLayoutTestBox was mutated in RenderFlex.performLayout.\n'
|
|
'A RenderObject must not mutate its descendants in its performLayout method.\n'
|
|
'The RenderObject being mutated was:\n'
|
|
'${child1.toStringShort()}\n'
|
|
'The ancestor RenderObject that was mutating the said RenderLayoutTestBox was:\n'
|
|
'${block.toStringShort()}\n'
|
|
'Mutating the layout of another RenderObject may cause some RenderObjects in its subtree to be laid out more than once. Consider using the LayoutBuilder widget to dynamically mutate a subtree during layout.',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('marking an out-of-band mutation in performLayout', () {
|
|
late RenderProxyBox child1, child11, child2, child21;
|
|
final RenderFlex block = RenderFlex(textDirection: TextDirection.ltr);
|
|
block.add(child1 = RenderLayoutTestBox(() {}));
|
|
block.add(child2 = RenderLayoutTestBox(() {}));
|
|
child1.child = child11 = RenderLayoutTestBox(() {});
|
|
layout(block);
|
|
|
|
expect(block.debugNeedsLayout, false);
|
|
expect(child1.debugNeedsLayout, false);
|
|
expect(child11.debugNeedsLayout, false);
|
|
expect(child2.debugNeedsLayout, false);
|
|
|
|
// Add a new child to child2 which is a relayout boundary.
|
|
child2.child = child21 = RenderLayoutTestBox(() {}, onPerformLayout: child11.markNeedsLayout);
|
|
|
|
FlutterError? error;
|
|
pumpFrame(
|
|
onErrors: () {
|
|
error =
|
|
TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!.exception
|
|
as FlutterError;
|
|
},
|
|
);
|
|
|
|
expect(
|
|
error?.message,
|
|
equalsIgnoringWhitespace(
|
|
'A RenderLayoutTestBox was mutated in RenderLayoutTestBox.performLayout.\n'
|
|
'The RenderObject was mutated when none of its ancestors is actively performing layout.\n'
|
|
'The RenderObject being mutated was:\n'
|
|
'${child11.toStringShort()}\n'
|
|
'The RenderObject that was mutating the said RenderLayoutTestBox was:\n'
|
|
'${child21.toStringShort()}',
|
|
),
|
|
);
|
|
});
|
|
});
|
|
}
|