mirror of
https://github.com/flutter/flutter.git
synced 2026-02-11 13:22:46 +08:00
119 lines
4.9 KiB
Dart
119 lines
4.9 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/foundation.dart';
|
|
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'rendering_tester.dart';
|
|
|
|
void main() {
|
|
TestRenderingFlutterBinding.ensureInitialized();
|
|
|
|
// This test has to be kept separate from object_test.dart because the way
|
|
// the rendering_test.dart dependency of this test uses the bindings in not
|
|
// compatible with existing tests in object_test.dart.
|
|
test('reentrant paint error', () {
|
|
late FlutterErrorDetails errorDetails;
|
|
final RenderBox root = TestReentrantPaintingErrorRenderBox();
|
|
layout(root, onErrors: () {
|
|
errorDetails = TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!;
|
|
});
|
|
pumpFrame(phase: EnginePhase.paint);
|
|
|
|
expect(errorDetails, isNotNull);
|
|
expect(errorDetails.stack, isNotNull);
|
|
// Check the ErrorDetails without the stack trace
|
|
final List<String> lines = errorDetails.toString().split('\n');
|
|
// The lines in the middle of the error message contain the stack trace
|
|
// which will change depending on where the test is run.
|
|
expect(lines.length, greaterThan(12));
|
|
expect(
|
|
lines.take(12).join('\n'),
|
|
equalsIgnoringHashCodes(
|
|
'══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞══════════════════════\n'
|
|
'The following assertion was thrown during paint():\n'
|
|
'Tried to paint a RenderObject reentrantly.\n'
|
|
'The following RenderObject was already being painted when it was painted again:\n'
|
|
' TestReentrantPaintingErrorRenderBox#00000:\n'
|
|
' parentData: <none>\n'
|
|
' constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
|
' size: Size(100.0, 100.0)\n'
|
|
'Since this typically indicates an infinite recursion, it is\n'
|
|
'disallowed.\n'
|
|
'\n'
|
|
'When the exception was thrown, this was the stack:',
|
|
),
|
|
);
|
|
|
|
expect(
|
|
lines.getRange(lines.length - 8, lines.length).join('\n'),
|
|
equalsIgnoringHashCodes(
|
|
'The following RenderObject was being processed when the exception was fired:\n'
|
|
' TestReentrantPaintingErrorRenderBox#00000:\n'
|
|
' parentData: <none>\n'
|
|
' constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
|
' size: Size(100.0, 100.0)\n'
|
|
'This RenderObject has no descendants.\n'
|
|
'═════════════════════════════════════════════════════════════════\n',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('needsCompositingBitsUpdate paint error', () {
|
|
late FlutterError flutterError;
|
|
final RenderBox root = RenderRepaintBoundary(child: RenderSizedBox(const Size(100, 100)));
|
|
try {
|
|
layout(root);
|
|
PaintingContext.repaintCompositedChild(root, debugAlsoPaintedParent: true);
|
|
} on FlutterError catch (exception) {
|
|
flutterError = exception;
|
|
}
|
|
|
|
expect(flutterError, isNotNull);
|
|
// The lines in the middle of the error message contain the stack trace
|
|
// which will change depending on where the test is run.
|
|
expect(
|
|
flutterError.toStringDeep(),
|
|
equalsIgnoringHashCodes(
|
|
'FlutterError\n'
|
|
' Tried to paint a RenderObject before its compositing bits were\n'
|
|
' updated.\n'
|
|
' The following RenderObject was marked as having dirty compositing bits at the time that it was painted:\n'
|
|
' RenderRepaintBoundary#00000 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE:\n'
|
|
' needs compositing\n'
|
|
' parentData: <none>\n'
|
|
' constraints: BoxConstraints(w=800.0, h=600.0)\n'
|
|
' layer: OffsetLayer#00000 DETACHED\n'
|
|
' size: Size(800.0, 600.0)\n'
|
|
' metrics: 0.0% useful (1 bad vs 0 good)\n'
|
|
' diagnosis: insufficient data to draw conclusion (less than five\n'
|
|
' repaints)\n'
|
|
' A RenderObject that still has dirty compositing bits cannot be\n'
|
|
' painted because this indicates that the tree has not yet been\n'
|
|
' properly configured for creating the layer tree.\n'
|
|
' This usually indicates an error in the Flutter framework itself.\n',
|
|
),
|
|
);
|
|
expect(
|
|
flutterError.diagnostics.singleWhere((DiagnosticsNode node) => node.level == DiagnosticLevel.hint).toString(),
|
|
'This usually indicates an error in the Flutter framework itself.',
|
|
);
|
|
});
|
|
}
|
|
|
|
class TestReentrantPaintingErrorRenderBox extends RenderBox {
|
|
@override
|
|
void paint(PaintingContext context, Offset offset) {
|
|
// Cause a reentrant painting bug that would show up as a stack overflow if
|
|
// it was not for debugging checks in RenderObject.
|
|
context.paintChild(this, offset);
|
|
}
|
|
|
|
@override
|
|
void performLayout() {
|
|
size = const Size(100, 100);
|
|
}
|
|
}
|