1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/foundation.dart';
6import 'package:flutter/rendering.dart';
7import 'package:flutter_test/flutter_test.dart';
8
9import 'rendering_tester.dart';
10
11void main() {
12 TestRenderingFlutterBinding.ensureInitialized();
13
14 // This test has to be kept separate from object_test.dart because the way
15 // the rendering_test.dart dependency of this test uses the bindings in not
16 // compatible with existing tests in object_test.dart.
17 test('reentrant paint error', () {
18 late FlutterErrorDetails errorDetails;
19 final RenderBox root = TestReentrantPaintingErrorRenderBox();
20 layout(
21 root,
22 onErrors: () {
23 errorDetails = TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!;
24 },
25 );
26 pumpFrame(phase: EnginePhase.paint);
27
28 expect(errorDetails, isNotNull);
29 expect(errorDetails.stack, isNotNull);
30 // Check the ErrorDetails without the stack trace
31 final List<String> lines = errorDetails.toString().split('\n');
32 // The lines in the middle of the error message contain the stack trace
33 // which will change depending on where the test is run.
34 expect(lines.length, greaterThan(12));
35 expect(
36 lines.take(12).join('\n'),
37 equalsIgnoringHashCodes(
38 '══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞══════════════════════\n'
39 'The following assertion was thrown during paint():\n'
40 'Tried to paint a RenderObject reentrantly.\n'
41 'The following RenderObject was already being painted when it was painted again:\n'
42 ' TestReentrantPaintingErrorRenderBox#00000:\n'
43 ' parentData: <none>\n'
44 ' constraints: BoxConstraints(w=800.0, h=600.0)\n'
45 ' size: Size(100.0, 100.0)\n'
46 'Since this typically indicates an infinite recursion, it is\n'
47 'disallowed.\n'
48 '\n'
49 'When the exception was thrown, this was the stack:',
50 ),
51 );
52
53 expect(
54 lines.getRange(lines.length - 8, lines.length).join('\n'),
55 equalsIgnoringHashCodes(
56 'The following RenderObject was being processed when the exception was fired:\n'
57 ' TestReentrantPaintingErrorRenderBox#00000:\n'
58 ' parentData: <none>\n'
59 ' constraints: BoxConstraints(w=800.0, h=600.0)\n'
60 ' size: Size(100.0, 100.0)\n'
61 'This RenderObject has no descendants.\n'
62 '═════════════════════════════════════════════════════════════════\n',
63 ),
64 );
65 });
66
67 test('needsCompositingBitsUpdate paint error', () {
68 late FlutterError flutterError;
69 final RenderBox root = RenderRepaintBoundary(child: RenderSizedBox(const Size(100, 100)));
70 try {
71 layout(root);
72 PaintingContext.repaintCompositedChild(root, debugAlsoPaintedParent: true);
73 } on FlutterError catch (exception) {
74 flutterError = exception;
75 }
76
77 expect(flutterError, isNotNull);
78 // The lines in the middle of the error message contain the stack trace
79 // which will change depending on where the test is run.
80 expect(
81 flutterError.toStringDeep(),
82 equalsIgnoringHashCodes(
83 'FlutterError\n'
84 ' Tried to paint a RenderObject before its compositing bits were\n'
85 ' updated.\n'
86 ' The following RenderObject was marked as having dirty compositing bits at the time that it was painted:\n'
87 ' RenderRepaintBoundary#00000 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:\n'
88 ' needs compositing\n'
89 ' parentData: <none>\n'
90 ' constraints: BoxConstraints(w=800.0, h=600.0)\n'
91 ' layer: OffsetLayer#00000 DETACHED\n'
92 ' size: Size(800.0, 600.0)\n'
93 ' metrics: 0.0% useful (1 bad vs 0 good)\n'
94 ' diagnosis: insufficient data to draw conclusion (less than five\n'
95 ' repaints)\n'
96 ' A RenderObject that still has dirty compositing bits cannot be\n'
97 ' painted because this indicates that the tree has not yet been\n'
98 ' properly configured for creating the layer tree.\n'
99 ' This usually indicates an error in the Flutter framework itself.\n',
100 ),
101 );
102 expect(
103 flutterError.diagnostics
104 .singleWhere((DiagnosticsNode node) => node.level == DiagnosticLevel.hint)
105 .toString(),
106 'This usually indicates an error in the Flutter framework itself.',
107 );
108 });
109}
110
111class TestReentrantPaintingErrorRenderBox extends RenderBox {
112 @override
113 void paint(PaintingContext context, Offset offset) {
114 // Cause a reentrant painting bug that would show up as a stack overflow if
115 // it was not for debugging checks in RenderObject.
116 context.paintChild(this, offset);
117 }
118
119 @override
120 void performLayout() {
121 size = const Size(100, 100);
122 }
123}
124

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com