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

Provided by KDAB

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