Text Painting Fuzzer (#12813)
Various improvements (in particular a new painting fuzzer) to the text manual test. Some additional documentation. A fix to Stack to remove an LTR bias: make unpositioned children apply "alignment". Some more debugging information on RichText and Text. A fix to the flutter tool to not crash when an RPC call throws an exception.
This commit is contained in:
parent
f4b0ccd9fd
commit
8fd20b5deb
File diff suppressed because it is too large
Load Diff
@ -187,6 +187,20 @@ class DecorationImagePainter {
|
||||
ImageStream _imageStream;
|
||||
ImageInfo _image;
|
||||
|
||||
/// Draw the image onto the given canvas.
|
||||
///
|
||||
/// The image is drawn at the position and size given by the `rect` argument.
|
||||
///
|
||||
/// The image is clipped to the given `clipPath`, if any.
|
||||
///
|
||||
/// The `configuration` object is used to resolve the image (e.g. to pick
|
||||
/// resolution-specific assets), and to implement the
|
||||
/// [DecorationImage.matchTextDirection] feature.
|
||||
///
|
||||
/// If the image needs to be painted again, e.g. because it is animated or
|
||||
/// because it had not yet been loaded the first time this method was called,
|
||||
/// then the `onChanged` callback passed to [DecorationImage.createPainter]
|
||||
/// will be called.
|
||||
void paint(Canvas canvas, Rect rect, Path clipPath, ImageConfiguration configuration) {
|
||||
if (_details == null)
|
||||
return;
|
||||
|
@ -43,6 +43,10 @@ class RenderListBody extends RenderBox
|
||||
child.parentData = new ListBodyParentData();
|
||||
}
|
||||
|
||||
/// The direction in which the children are laid out.
|
||||
///
|
||||
/// For example, if the [axisDirection] is [AxisDirection.down], each child
|
||||
/// will be laid out below the next, vertically.
|
||||
AxisDirection get axisDirection => _axisDirection;
|
||||
AxisDirection _axisDirection;
|
||||
set axisDirection(AxisDirection value) {
|
||||
@ -53,6 +57,8 @@ class RenderListBody extends RenderBox
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// The axis (horizontal or vertical) corresponding to the current
|
||||
/// [axisDirection].
|
||||
Axis get mainAxis => axisDirectionToAxis(axisDirection);
|
||||
|
||||
@override
|
||||
|
@ -2114,6 +2114,17 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
|
||||
owner.requestVisualUpdate();
|
||||
}
|
||||
|
||||
/// Report the semantics of this node, for example for accessibility purposes.
|
||||
///
|
||||
/// This method should be overridden by subclasses that have interesting
|
||||
/// semantic information.
|
||||
///
|
||||
/// The given [SemanticsConfiguration] object is mutable and should be
|
||||
/// annotated in a manner that describes the current state. No reference
|
||||
/// should be kept to that object; mutating it outside of the context of the
|
||||
/// [describeSemanticsConfiguration] call (for example as a result of
|
||||
/// asynchronous computation) will at best have no useful effect and at worse
|
||||
/// will cause crashes as the data will be in an inconsistent state.
|
||||
@protected
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
// Nothing to do by default.
|
||||
|
@ -403,6 +403,20 @@ class RenderParagraph extends RenderBox {
|
||||
return _textPainter.getWordBoundary(position);
|
||||
}
|
||||
|
||||
/// Returns the size of the text as laid out.
|
||||
///
|
||||
/// This can differ from [size] if the text overflowed or if the [constraints]
|
||||
/// provided by the parent [RenderObject] forced the layout to be bigger than
|
||||
/// necessary for the given [text].
|
||||
///
|
||||
/// This returns the [TextPainter.size] of the underlying [TextPainter].
|
||||
///
|
||||
/// Valid only after [layout].
|
||||
Size get textSize {
|
||||
assert(!debugNeedsLayout);
|
||||
return _textPainter.size;
|
||||
}
|
||||
|
||||
@override
|
||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||
super.describeSemanticsConfiguration(config);
|
||||
|
@ -596,6 +596,15 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
|
||||
|
||||
static final SemanticsConfiguration _kEmptyConfig = new SemanticsConfiguration();
|
||||
|
||||
/// Reconfigures the properties of this object to describe the configuration
|
||||
/// provided in the `config` argument and the children listen in the
|
||||
/// `childrenInInversePaintOrder` argument.
|
||||
///
|
||||
/// The arguments may be null; this represents an empty configuration (all
|
||||
/// values at their defaults, no children).
|
||||
///
|
||||
/// No reference is kept to the [SemanticsConfiguration] object, but the child
|
||||
/// list is used as-is and should therefore not be changed after this call.
|
||||
void updateWith({
|
||||
@required SemanticsConfiguration config,
|
||||
@required List<SemanticsNode> childrenInInversePaintOrder,
|
||||
|
@ -332,14 +332,20 @@ class RenderStack extends RenderBox
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
/// How to align the non-positioned children in the stack.
|
||||
/// How to align the non-positioned or partially-positioned children in the
|
||||
/// stack.
|
||||
///
|
||||
/// The non-positioned children are placed relative to each other such that
|
||||
/// the points determined by [alignment] are co-located. For example, if the
|
||||
/// [alignment] is [Alignment.topLeft], then the top left corner of
|
||||
/// each non-positioned child will be located at the same global coordinate.
|
||||
///
|
||||
/// If this is set to a [AlignmentDirectional] object, then [textDirection]
|
||||
/// Partially-positioned children, those that do not specify an alignment in a
|
||||
/// particular axis (e.g. that have neither `top` nor `bottom` set), use the
|
||||
/// alignment to determine how they should be positioned in that
|
||||
/// under-specified axis.
|
||||
///
|
||||
/// If this is set to an [AlignmentDirectional] object, then [textDirection]
|
||||
/// must not be null.
|
||||
AlignmentGeometry get alignment => _alignment;
|
||||
AlignmentGeometry _alignment;
|
||||
@ -504,20 +510,26 @@ class RenderStack extends RenderBox
|
||||
|
||||
child.layout(childConstraints, parentUsesSize: true);
|
||||
|
||||
double x = 0.0;
|
||||
if (childParentData.left != null)
|
||||
double x;
|
||||
if (childParentData.left != null) {
|
||||
x = childParentData.left;
|
||||
else if (childParentData.right != null)
|
||||
} else if (childParentData.right != null) {
|
||||
x = size.width - childParentData.right - child.size.width;
|
||||
} else {
|
||||
x = _resolvedAlignment.alongOffset(size - child.size).dx;
|
||||
}
|
||||
|
||||
if (x < 0.0 || x + child.size.width > size.width)
|
||||
_hasVisualOverflow = true;
|
||||
|
||||
double y = 0.0;
|
||||
if (childParentData.top != null)
|
||||
double y;
|
||||
if (childParentData.top != null) {
|
||||
y = childParentData.top;
|
||||
else if (childParentData.bottom != null)
|
||||
} else if (childParentData.bottom != null) {
|
||||
y = size.height - childParentData.bottom - child.size.height;
|
||||
} else {
|
||||
y = _resolvedAlignment.alongOffset(size - child.size).dy;
|
||||
}
|
||||
|
||||
if (y < 0.0 || y + child.size.height > size.height)
|
||||
_hasVisualOverflow = true;
|
||||
|
@ -2239,9 +2239,10 @@ class ListBody extends MultiChildRenderObjectWidget {
|
||||
/// Positioned children are those wrapped in a [Positioned] widget that has at
|
||||
/// least one non-null property. The stack sizes itself to contain all the
|
||||
/// non-positioned children, which are positioned according to [alignment]
|
||||
/// (which defaults to the top-left corner). The positioned children are then
|
||||
/// placed relative to the stack according to their top, right, bottom, and left
|
||||
/// properties.
|
||||
/// (which defaults to the top-left corner in left-to-right environments and the
|
||||
/// top-right corner in right-to-left environments). The positioned children are
|
||||
/// then placed relative to the stack according to their top, right, bottom, and
|
||||
/// left properties.
|
||||
///
|
||||
/// The stack paints its children in order with the first child being at the
|
||||
/// bottom. If you want to change the order in which the children paint, you
|
||||
@ -2282,12 +2283,18 @@ class Stack extends MultiChildRenderObjectWidget {
|
||||
List<Widget> children: const <Widget>[],
|
||||
}) : super(key: key, children: children);
|
||||
|
||||
/// How to align the non-positioned children in the stack.
|
||||
/// How to align the non-positioned and partially-positioned children in the
|
||||
/// stack.
|
||||
///
|
||||
/// The non-positioned children are placed relative to each other such that
|
||||
/// the points determined by [alignment] are co-located. For example, if the
|
||||
/// [alignment] is [Alignment.topLeft], then the top left corner of
|
||||
/// each non-positioned child will be located at the same global coordinate.
|
||||
///
|
||||
/// Partially-positioned children, those that do not specify an alignment in a
|
||||
/// particular axis (e.g. that have neither `top` nor `bottom` set), use the
|
||||
/// alignment to determine how they should be positioned in that
|
||||
/// under-specified axis.
|
||||
final AlignmentGeometry alignment;
|
||||
|
||||
/// The text direction with which to resolve [alignment].
|
||||
@ -2398,6 +2405,12 @@ class IndexedStack extends Stack {
|
||||
/// [height] properties can be used to give the dimensions, with one
|
||||
/// corresponding position property (e.g. [top] and [height]).
|
||||
///
|
||||
/// If all three values on a particular axis are null, then the
|
||||
/// [Stack.alignment] property is used to position the child.
|
||||
///
|
||||
/// If all six values are null, the child is a non-positioned child. The [Stack]
|
||||
/// uses only the non-positioned children to size itself.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [PositionedDirectional], which adapts to the ambient [Directionality].
|
||||
@ -2413,6 +2426,8 @@ class Positioned extends ParentDataWidget<Stack> {
|
||||
///
|
||||
/// * [Positioned.directional], which specifies the widget's horizontal
|
||||
/// position using `start` and `end` rather than `left` and `right`.
|
||||
/// * [PositionedDirectional], which is similar to [Positioned.directional]
|
||||
/// but adapts to the ambient [Directionality].
|
||||
const Positioned({
|
||||
Key key,
|
||||
this.left,
|
||||
@ -2530,36 +2545,54 @@ class Positioned extends ParentDataWidget<Stack> {
|
||||
///
|
||||
/// Only two out of the three horizontal values ([left], [right], [width]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// horizontally.
|
||||
final double left;
|
||||
|
||||
/// The distance that the child's top edge is inset from the top of the stack.
|
||||
///
|
||||
/// Only two out of the three vertical values ([top], [bottom], [height]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// vertically.
|
||||
final double top;
|
||||
|
||||
/// The distance that the child's right edge is inset from the right of the stack.
|
||||
///
|
||||
/// Only two out of the three horizontal values ([left], [right], [width]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// horizontally.
|
||||
final double right;
|
||||
|
||||
/// The distance that the child's bottom edge is inset from the bottom of the stack.
|
||||
///
|
||||
/// Only two out of the three vertical values ([top], [bottom], [height]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// vertically.
|
||||
final double bottom;
|
||||
|
||||
/// The child's width.
|
||||
///
|
||||
/// Only two out of the three horizontal values ([left], [right], [width]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// horizontally.
|
||||
final double width;
|
||||
|
||||
/// The child's height.
|
||||
///
|
||||
/// Only two out of the three vertical values ([top], [bottom], [height]) can be
|
||||
/// set. The third must be null.
|
||||
///
|
||||
/// If all three are null, the [Stack.alignment] is used to position the child
|
||||
/// vertically.
|
||||
final double height;
|
||||
|
||||
@override
|
||||
@ -3897,6 +3930,18 @@ class RichText extends LeafRenderObjectWidget {
|
||||
..textScaleFactor = textScaleFactor
|
||||
..maxLines = maxLines;
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder description) {
|
||||
super.debugFillProperties(description);
|
||||
description.add(new EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start));
|
||||
description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||
description.add(new FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
|
||||
description.add(new EnumProperty<TextOverflow>('overflow', overflow, defaultValue: TextOverflow.clip));
|
||||
description.add(new DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: 1.0));
|
||||
description.add(new IntProperty('maxLines', maxLines, ifNull: 'unlimited'));
|
||||
description.add(new StringProperty('text', text.toPlainText()));
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget that displays a [dart:ui.Image] directly.
|
||||
|
@ -4519,6 +4519,11 @@ class LeafRenderObjectElement extends RenderObjectElement {
|
||||
void removeChildRenderObject(RenderObject child) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
@override
|
||||
List<DiagnosticsNode> debugDescribeChildren() {
|
||||
return widget.debugDescribeChildren();
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Element] that uses a [SingleChildRenderObjectWidget] as its configuration.
|
||||
|
@ -29,7 +29,14 @@ class IconData {
|
||||
/// The font family from which the glyph for the [codePoint] will be selected.
|
||||
final String fontFamily;
|
||||
|
||||
// The name of the package from which the font family is included.
|
||||
/// The name of the package from which the font family is included.
|
||||
///
|
||||
/// The name is used by the [Icon] widget when configuring the [TextStyle] so
|
||||
/// that the given [fontFamily] is obtained from the appropriate asset.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [TextStyle], which describes how to use fonts from other packages.
|
||||
final String fontPackage;
|
||||
|
||||
@override
|
||||
|
@ -292,5 +292,11 @@ class Text extends StatelessWidget {
|
||||
super.debugFillProperties(description);
|
||||
description.add(new StringProperty('data', data, showName: false));
|
||||
style?.debugFillProperties(description);
|
||||
description.add(new EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null));
|
||||
description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
|
||||
description.add(new FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
|
||||
description.add(new EnumProperty<TextOverflow>('overflow', overflow, defaultValue: null));
|
||||
description.add(new DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null));
|
||||
description.add(new IntProperty('maxLines', maxLines, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ void main() {
|
||||
expect(painter.text.text.length, 28);
|
||||
painter.layout();
|
||||
|
||||
// The skips here are because the old rendering code considers the bidi formatting characters
|
||||
// to be part of the word sometimes and not others, which is fine, but we'd mildly prefer if
|
||||
// we were consistently considering them part of words always.
|
||||
final TextRange hebrew1 = painter.getWordBoundary(const TextPosition(offset: 4, affinity: TextAffinity.downstream));
|
||||
expect(hebrew1, const TextRange(start: 0, end: 8), skip: skipExpectsWithKnownBugs);
|
||||
final TextRange english2 = painter.getWordBoundary(const TextPosition(offset: 14, affinity: TextAffinity.downstream));
|
||||
|
@ -629,4 +629,122 @@ void main() {
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: new Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 100.0, height: 100.0),
|
||||
const Positioned(left: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(right: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(start: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(end: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(tester.getRect(find.byType(SizedBox).at(0)), new Rect.fromLTWH(350.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(1)), new Rect.fromLTWH(0.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(2)), new Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(3)), new Rect.fromLTWH(350.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(4)), new Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(5)), new Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(6)), new Rect.fromLTWH(0.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(7)), new Rect.fromLTWH(350.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(8)), new Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 100.0, height: 100.0),
|
||||
const Positioned(left: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(right: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(start: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(end: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(tester.getRect(find.byType(SizedBox).at(0)), new Rect.fromLTWH(350.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(1)), new Rect.fromLTWH(0.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(2)), new Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(3)), new Rect.fromLTWH(350.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(4)), new Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(5)), new Rect.fromLTWH(0.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(6)), new Rect.fromLTWH(700.0, 250.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(7)), new Rect.fromLTWH(350.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(8)), new Rect.fromLTWH(350.0, 500.0, 100.0, 100.0));
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new Stack(
|
||||
alignment: Alignment.bottomRight,
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 100.0, height: 100.0),
|
||||
const Positioned(left: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(right: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(start: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(end: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(tester.getRect(find.byType(SizedBox).at(0)), new Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(1)), new Rect.fromLTWH(0.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(2)), new Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(3)), new Rect.fromLTWH(700.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(4)), new Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(5)), new Rect.fromLTWH(0.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(6)), new Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(7)), new Rect.fromLTWH(700.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(8)), new Rect.fromLTWH(700.0, 500.0, 100.0, 100.0));
|
||||
|
||||
await tester.pumpWidget(
|
||||
new Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: new Stack(
|
||||
alignment: Alignment.topLeft,
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 100.0, height: 100.0),
|
||||
const Positioned(left: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(right: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const Positioned(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(start: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(end: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(top: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
const PositionedDirectional(bottom: 0.0, child: const SizedBox(width: 100.0, height: 100.0)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(tester.getRect(find.byType(SizedBox).at(0)), new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(1)), new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(2)), new Rect.fromLTWH(700.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(3)), new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(4)), new Rect.fromLTWH(0.0, 500.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(5)), new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(6)), new Rect.fromLTWH(700.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(7)), new Rect.fromLTWH(0.0, 0.0, 100.0, 100.0));
|
||||
expect(tester.getRect(find.byType(SizedBox).at(8)), new Rect.fromLTWH(0.0, 500.0, 100.0, 100.0));
|
||||
});
|
||||
}
|
||||
|
@ -765,23 +765,23 @@ void main() {
|
||||
equalsIgnoringHashCodes(
|
||||
'Table-[GlobalKey#00000](renderObject: RenderTable#00000)\n'
|
||||
'├Text("A")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "A", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("B")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "B", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("C")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "C", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("D")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "D", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("EEE")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "EEE", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("F")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "F", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("G")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "G", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'├Text("H")\n'
|
||||
'│└RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'│└RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "H", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
'└Text("III")\n'
|
||||
' └RichText(renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n',
|
||||
' └RichText(softWrap: wrapping at box width, maxLines: unlimited, text: "III", renderObject: RenderParagraph#00000 relayoutBoundary=up1)\n'
|
||||
),
|
||||
);
|
||||
});
|
||||
|
@ -52,7 +52,7 @@ void main() {
|
||||
final String message = failure.message;
|
||||
|
||||
expect(message, contains('Expected: no matching nodes in the widget tree\n'));
|
||||
expect(message, contains('Actual: ?:<exactly one widget with text "foo": Text("foo")>\n'));
|
||||
expect(message, contains('Actual: ?:<exactly one widget with text "foo": Text("foo", textDirection: ltr)>\n'));
|
||||
expect(message, contains('Which: means one was found but none were expected\n'));
|
||||
});
|
||||
|
||||
@ -70,7 +70,7 @@ void main() {
|
||||
final String message = failure.message;
|
||||
|
||||
expect(message, contains('Expected: no matching nodes in the widget tree\n'));
|
||||
expect(message, contains('Actual: ?:<exactly one widget with text "foo" (ignoring offstage widgets): Text("foo")>\n'));
|
||||
expect(message, contains('Actual: ?:<exactly one widget with text "foo" (ignoring offstage widgets): Text("foo", textDirection: ltr)>\n'));
|
||||
expect(message, contains('Which: means one was found but none were expected\n'));
|
||||
});
|
||||
|
||||
|
@ -738,6 +738,10 @@ class VM extends ServiceObjectOwner {
|
||||
} on WebSocketChannelException catch (error) {
|
||||
throwToolExit('Error connecting to observatory: $error');
|
||||
return null;
|
||||
} on rpc.RpcException catch (error) {
|
||||
printError('Error ${error.code} received from application: ${error.message}');
|
||||
printTrace('${error.data}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user