Commit cd3715a8 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Border RTL (#12407)

parent cc3f5767
......@@ -194,10 +194,13 @@ class BorderSide {
return a;
if (t == 1.0)
return b;
final double width = ui.lerpDouble(a.width, b.width, t);
if (width < 0.0)
return BorderSide.none;
if (a.style == b.style) {
return new BorderSide(
color: Color.lerp(a.color, b.color, t),
width: math.max(0.0, ui.lerpDouble(a.width, b.width, t)),
width: width,
style: a.style, // == b.style
);
}
......@@ -220,7 +223,7 @@ class BorderSide {
}
return new BorderSide(
color: Color.lerp(colorA, colorB, t),
width: math.max(0.0, ui.lerpDouble(a.width, b.width, t)),
width: width,
style: BorderStyle.solid,
);
}
......
......@@ -110,7 +110,14 @@ class BoxDecoration extends Decoration {
/// A border to draw above the background [color], [gradient], or [image].
///
/// Follows the [shape] and [borderRadius].
final Border border;
///
/// Use [Border] objects to describe borders that do not depend on the reading
/// direction.
///
/// Use [BoxBorder] objects to describe borders that should flip their left
/// and right edges based on whether the text is being read left-to-right or
/// right-to-left.
final BoxBorder border;
/// If non-null, the corners of this box are rounded by this [BorderRadius].
///
......@@ -137,7 +144,7 @@ class BoxDecoration extends Decoration {
final BoxShape shape;
@override
EdgeInsets get padding => border?.dimensions;
EdgeInsetsGeometry get padding => border?.dimensions;
/// Returns a new box decoration that is scaled by the given factor.
BoxDecoration scale(double factor) {
......@@ -145,7 +152,7 @@ class BoxDecoration extends Decoration {
return new BoxDecoration(
color: Color.lerp(null, color, factor),
image: image,
border: Border.lerp(null, border, factor),
border: BoxBorder.lerp(null, border, factor),
borderRadius: BorderRadius.lerp(null, borderRadius, factor),
boxShadow: BoxShadow.lerpList(null, boxShadow, factor),
gradient: gradient,
......@@ -192,7 +199,7 @@ class BoxDecoration extends Decoration {
return new BoxDecoration(
color: Color.lerp(a.color, b.color, t),
image: t < 0.5 ? a.image : b.image,
border: Border.lerp(a.border, b.border, t),
border: BoxBorder.lerp(a.border, b.border, t),
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t),
gradient: t < 0.5 ? a.gradient : b.gradient,
......@@ -238,7 +245,7 @@ class BoxDecoration extends Decoration {
properties.add(new DiagnosticsProperty<Color>('color', color, defaultValue: null));
properties.add(new DiagnosticsProperty<DecorationImage>('image', image, defaultValue: null));
properties.add(new DiagnosticsProperty<Border>('border', border, defaultValue: null));
properties.add(new DiagnosticsProperty<BoxBorder>('border', border, defaultValue: null));
properties.add(new DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius, defaultValue: null));
properties.add(new IterableProperty<BoxShadow>('boxShadow', boxShadow, defaultValue: null, style: DiagnosticsTreeStyle.whitespace));
properties.add(new DiagnosticsProperty<Gradient>('gradient', gradient, defaultValue: null));
......@@ -421,7 +428,8 @@ class _BoxDecorationPainter extends BoxPainter {
canvas,
rect,
shape: _decoration.shape,
borderRadius: _decoration.borderRadius
borderRadius: _decoration.borderRadius,
textDirection: configuration.textDirection,
);
}
}
......@@ -53,7 +53,12 @@ abstract class Decoration extends Diagnosticable {
/// does not take into account that the circle is drawn in the center of the
/// box regardless of the ratio of the box; it does not provide the extra
/// padding that is implied by changing the ratio.
EdgeInsets get padding => EdgeInsets.zero;
///
/// The value returned by this getter must be resolved (using
/// [EdgeInsetsGeometry.resolve] to obtain an absolute [EdgeInsets]. (For
/// example, [BorderDirectional] will return an [EdgeInsetsDirectional] for
/// its [padding].)
EdgeInsetsGeometry get padding => EdgeInsets.zero;
/// Whether this decoration is complex enough to benefit from caching its painting.
bool get isComplex => false;
......
This diff is collapsed.
......@@ -128,10 +128,11 @@ void main() {
final BorderSide side0 = const BorderSide(width: 0.0);
final BorderSide side1 = const BorderSide(width: 1.0);
final BorderSide side2 = const BorderSide(width: 2.0);
expect(BorderSide.lerp(side2, side1, 10.0), side0);
expect(BorderSide.lerp(side1, side2, -10.0), side0);
expect(BorderSide.lerp(side2, side1, 10.0), BorderSide.none);
expect(BorderSide.lerp(side1, side2, -10.0), BorderSide.none);
expect(BorderSide.lerp(side0, side1, 2.0), side2);
expect(BorderSide.lerp(side1, side0, 2.0), side0);
expect(BorderSide.lerp(side1, side0, 2.0), BorderSide.none);
expect(BorderSide.lerp(side2, side1, 2.0), side0);
});
test('BorderSide - toString', () {
expect(
......
......@@ -6,6 +6,14 @@ import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('Border constructor', () {
final Null $null = null;
expect(() => new Border(left: $null), throwsAssertionError);
expect(() => new Border(top: $null), throwsAssertionError);
expect(() => new Border(right: $null), throwsAssertionError);
expect(() => new Border(bottom: $null), throwsAssertionError);
});
test('Border.merge', () {
final BorderSide magenta3 = const BorderSide(color: const Color(0xFFFF00FF), width: 3.0);
final BorderSide magenta6 = const BorderSide(color: const Color(0xFFFF00FF), width: 6.0);
......@@ -94,4 +102,135 @@ void main() {
final Border bY2 = new Border(top: yellow2);
expect(bY2.scale(0.0), bY0);
});
test('Border.dimensions', () {
expect(
const Border(
left: const BorderSide(width: 2.0),
top: const BorderSide(width: 3.0),
bottom: const BorderSide(width: 5.0),
right: const BorderSide(width: 7.0),
).dimensions,
const EdgeInsets.fromLTRB(2.0, 3.0, 7.0, 5.0),
);
});
test('Border.isUniform', () {
expect(
const Border(
left: const BorderSide(width: 3.0),
top: const BorderSide(width: 3.0),
right: const BorderSide(width: 3.0),
bottom: const BorderSide(width: 3.1),
).isUniform,
false,
);
expect(
const Border(
left: const BorderSide(width: 3.0),
top: const BorderSide(width: 3.0),
right: const BorderSide(width: 3.0),
bottom: const BorderSide(width: 3.0),
).isUniform,
true,
);
expect(
const Border(
left: const BorderSide(color: const Color(0xFFFFFFFE)),
top: const BorderSide(color: const Color(0xFFFFFFFF)),
right: const BorderSide(color: const Color(0xFFFFFFFF)),
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
).isUniform,
false,
);
expect(
const Border(
left: const BorderSide(color: const Color(0xFFFFFFFF)),
top: const BorderSide(color: const Color(0xFFFFFFFF)),
right: const BorderSide(color: const Color(0xFFFFFFFF)),
bottom: const BorderSide(color: const Color(0xFFFFFFFF)),
).isUniform,
true,
);
expect(
const Border(
left: const BorderSide(style: BorderStyle.none),
top: const BorderSide(style: BorderStyle.none),
right: const BorderSide(style: BorderStyle.none),
bottom: const BorderSide(style: BorderStyle.solid, width: 0.0),
).isUniform,
false,
);
expect(
const Border(
left: const BorderSide(style: BorderStyle.none),
top: const BorderSide(style: BorderStyle.none),
right: const BorderSide(style: BorderStyle.none),
bottom: const BorderSide(style: BorderStyle.solid, width: 0.0),
).isUniform,
false,
);
expect(
const Border(
left: const BorderSide(style: BorderStyle.none),
top: const BorderSide(style: BorderStyle.none),
right: const BorderSide(style: BorderStyle.none),
bottom: BorderSide.none,
).isUniform,
false,
);
expect(
const Border(
left: const BorderSide(style: BorderStyle.none, width: 0.0),
top: const BorderSide(style: BorderStyle.none, width: 0.0),
right: const BorderSide(style: BorderStyle.none, width: 0.0),
bottom: BorderSide.none,
).isUniform,
true,
);
expect(
const Border().isUniform,
true,
);
});
test('Border.lerp', () {
final Border visualWithTop10 = const Border(top: const BorderSide(width: 10.0));
final Border atMinus100 = const Border(left: const BorderSide(width: 0.0), right: const BorderSide(width: 300.0));
final Border at0 = const Border(left: const BorderSide(width: 100.0), right: const BorderSide(width: 200.0));
final Border at25 = const Border(left: const BorderSide(width: 125.0), right: const BorderSide(width: 175.0));
final Border at75 = const Border(left: const BorderSide(width: 175.0), right: const BorderSide(width: 125.0));
final Border at100 = const Border(left: const BorderSide(width: 200.0), right: const BorderSide(width: 100.0));
final Border at200 = const Border(left: const BorderSide(width: 300.0), right: const BorderSide(width: 0.0));
expect(Border.lerp(null, null, -1.0), null);
expect(Border.lerp(visualWithTop10, null, -1.0), const Border(top: const BorderSide(width: 20.0)));
expect(Border.lerp(null, visualWithTop10, -1.0), const Border());
expect(Border.lerp(at0, at100, -1.0), atMinus100);
expect(Border.lerp(null, null, 0.0), null);
expect(Border.lerp(visualWithTop10, null, 0.0), const Border(top: const BorderSide(width: 10.0)));
expect(Border.lerp(null, visualWithTop10, 0.0), const Border());
expect(Border.lerp(at0, at100, 0.0), at0);
expect(Border.lerp(null, null, 0.25), null);
expect(Border.lerp(visualWithTop10, null, 0.25), const Border(top: const BorderSide(width: 7.5)));
expect(Border.lerp(null, visualWithTop10, 0.25), const Border(top: const BorderSide(width: 2.5)));
expect(Border.lerp(at0, at100, 0.25), at25);
expect(Border.lerp(null, null, 0.75), null);
expect(Border.lerp(visualWithTop10, null, 0.75), const Border(top: const BorderSide(width: 2.5)));
expect(Border.lerp(null, visualWithTop10, 0.75), const Border(top: const BorderSide(width: 7.5)));
expect(Border.lerp(at0, at100, 0.75), at75);
expect(Border.lerp(null, null, 1.0), null);
expect(Border.lerp(visualWithTop10, null, 1.0), const Border());
expect(Border.lerp(null, visualWithTop10, 1.0), const Border(top: const BorderSide(width: 10.0)));
expect(Border.lerp(at0, at100, 1.0), at100);
expect(Border.lerp(null, null, 2.0), null);
expect(Border.lerp(visualWithTop10, null, 2.0), const Border());
expect(Border.lerp(null, visualWithTop10, 2.0), const Border(top: const BorderSide(width: 20.0)));
expect(Border.lerp(at0, at100, 2.0), at200);
});
}
\ No newline at end of file
......@@ -70,4 +70,69 @@ void main() {
..rect(rect: rect.deflate(2.5), color: b1.top.color)
);
});
test('Compound borders', () {
final BorderSide side1 = const BorderSide(color: const Color(0xFF00FF00));
final BorderSide side2 = const BorderSide(color: const Color(0xFF0000FF));
final BorderDirectional b1 = new BorderDirectional(top: side1, start: side1, end: side1, bottom: side1);
final BorderDirectional b2 = new BorderDirectional(top: side2, start: side2, end: side2, bottom: side2);
expect(
(b1 + b2).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))',
);
expect(
(b1 + (b2 + b2)).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))',
);
expect(
((b1 + b2) + b2).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 2.0, BorderStyle.solid))',
);
expect((b1 + b2) + b2, b1 + (b2 + b2));
expect(
(b1 + b2).scale(3.0).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 3.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 3.0, BorderStyle.solid))',
);
expect(
(b1 + b2).scale(0.0).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), start: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), end: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff00ff00), 0.0, BorderStyle.none)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), start: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), end: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none), bottom: BorderSide(Color(0xff0000ff), 0.0, BorderStyle.none))',
);
expect(
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.0).toString(),
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid))',
);
expect(
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.25).toString(),
'BorderDirectional(top: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff003fbf), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00bf3f), 1.0, BorderStyle.solid))',
);
expect(
ShapeBorder.lerp(b2 + b1, b1 + b2, 0.5).toString(),
'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff007f7f), 1.0, BorderStyle.solid))',
);
expect(
ShapeBorder.lerp(b2 + b1, b1 + b2, 1.0).toString(),
'BorderDirectional(top: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff00ff00), 1.0, BorderStyle.solid)) + '
'BorderDirectional(top: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), start: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), end: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid), bottom: BorderSide(Color(0xff0000ff), 1.0, BorderStyle.solid))'
);
expect((b1 + b2).dimensions, const EdgeInsetsDirectional.fromSTEB(2.0, 2.0, 2.0, 2.0));
final Rect rect = new Rect.fromLTRB(11.0, 15.0, 299.0, 175.0);
expect((Canvas canvas) => (b1 + b2).paint(canvas, rect, textDirection: TextDirection.rtl), paints
..rect(rect: rect.deflate(0.5), color: b2.top.color)
..rect(rect: rect.deflate(1.5), color: b1.top.color)
);
expect((b1 + b2 + b1).dimensions, const EdgeInsetsDirectional.fromSTEB(3.0, 3.0, 3.0, 3.0));
expect((Canvas canvas) => (b1 + b2 + b1).paint(canvas, rect, textDirection: TextDirection.rtl), paints
..rect(rect: rect.deflate(0.5), color: b1.top.color)
..rect(rect: rect.deflate(1.5), color: b2.top.color)
..rect(rect: rect.deflate(2.5), color: b1.top.color)
);
});
}
......@@ -38,11 +38,16 @@ import 'recording_canvas.dart';
/// See [PaintPattern] for a discussion of the semantics of paint patterns.
///
/// To match something which paints nothing, see [paintsNothing].
///
/// To match something which asserts instead of painting, see [paintsAssertion].
PaintPattern get paints => new _TestRecordingCanvasPatternMatcher();
/// Matches objects or functions that paint an empty display list.
Matcher get paintsNothing => new _TestRecordingCanvasPaintsNothingMatcher();
/// Matches objects or functions that assert when they try to paint.
Matcher get paintsAssertion => new _TestRecordingCanvasPaintsAssertionMatcher();
/// Signature for [PaintPattern.something] predicate argument.
///
/// Used by the [paints] matcher.
......@@ -218,8 +223,10 @@ abstract class PaintPattern {
/// are compared to the actual [Canvas.drawPath] call's `paint` argument, and
/// any mismatches result in failure.
///
/// There is currently no way to check the actual path itself.
// See https://github.com/flutter/flutter/issues/93 which tracks that issue.
/// To introspect the Path object (as it stands after the painting has
/// completed), the `includes` and `excludes` arguments can be provided to
/// specify points that should be considered inside or outside the path
/// (respectively).
///
/// If no call to [Canvas.drawPath] was made, then this results in failure.
///
......@@ -231,7 +238,7 @@ abstract class PaintPattern {
/// painting has completed, not at the time of the call. If the same [Paint]
/// object is reused multiple times, then this may not match the actual
/// arguments as they were seen by the method.
void path({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style });
void path({ Iterable<Offset> includes, Iterable<Offset> excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style });
/// Indicates that a line is expected next.
///
......@@ -327,6 +334,29 @@ class _MismatchedCall {
final RecordedInvocation call;
}
bool _evaluatePainter(Object object, Canvas canvas, PaintingContext context) {
if (object is _ContextPainterFunction) {
final _ContextPainterFunction function = object;
function(context, Offset.zero);
} else if (object is _CanvasPainterFunction) {
final _CanvasPainterFunction function = object;
function(canvas);
} else {
if (object is Finder) {
TestAsyncUtils.guardSync();
final Finder finder = object;
object = finder.evaluate().single.renderObject;
}
if (object is RenderObject) {
final RenderObject renderObject = object;
renderObject.paint(context, Offset.zero);
} else {
return false;
}
}
return true;
}
abstract class _TestRecordingCanvasMatcher extends Matcher {
@override
bool matches(Object object, Map<dynamic, dynamic> matchState) {
......@@ -336,25 +366,9 @@ abstract class _TestRecordingCanvasMatcher extends Matcher {
String prefixMessage = 'unexpectedly failed.';
bool result = false;
try {
if (object is _ContextPainterFunction) {
final _ContextPainterFunction function = object;
function(context, Offset.zero);
} else if (object is _CanvasPainterFunction) {
final _CanvasPainterFunction function = object;
function(canvas);
} else {
if (object is Finder) {
TestAsyncUtils.guardSync();
final Finder finder = object;
object = finder.evaluate().single.renderObject;
}
if (object is RenderObject) {
final RenderObject renderObject = object;
renderObject.paint(context, Offset.zero);
} else {
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
return false;
}
if (!_evaluatePainter(object, canvas, context)) {
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
return false;
}
result = _evaluatePredicates(canvas.invocations, description);
if (!result)
......@@ -407,6 +421,55 @@ class _TestRecordingCanvasPaintsNothingMatcher extends _TestRecordingCanvasMatch
}
}
class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher {
@override
bool matches(Object object, Map<dynamic, dynamic> matchState) {
final TestRecordingCanvas canvas = new TestRecordingCanvas();
final TestRecordingPaintingContext context = new TestRecordingPaintingContext(canvas);
final StringBuffer description = new StringBuffer();
String prefixMessage = 'unexpectedly failed.';
bool result = false;
try {
if (!_evaluatePainter(object, canvas, context)) {
matchState[this] = 'was not one of the supported objects for the "paints" matcher.';
return false;
}
prefixMessage = 'did not assert.';
} on AssertionError {
result = true;
} catch (error, stack) {
prefixMessage = 'threw the following exception:';
description.writeln(error.toString());
description.write(stack.toString());
result = false;
}
if (!result) {
if (canvas.invocations.isNotEmpty) {
description.write('The complete display list was:');
for (RecordedInvocation call in canvas.invocations)
description.write('\n * $call');
}
matchState[this] = '$prefixMessage\n$description';
}
return result;
}
@override
Description describe(Description description) {
return description.add('An object or closure that asserts when it tries to paint.');
}
@override
Description describeMismatch(
dynamic item,
Description description,
Map<dynamic, dynamic> matchState,
bool verbose,
) {
return description.add(matchState[this]);
}
}
class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher implements PaintPattern {
final List<_PaintPredicate> _predicates = <_PaintPredicate>[];
......@@ -471,8 +534,8 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp
}
@override
void path({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) {
_predicates.add(new _PathPaintPredicate(color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style));
void path({ Iterable<Offset> includes, Iterable<Offset> excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) {
_predicates.add(new _PathPaintPredicate(includes: includes, excludes: excludes, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style));
}
@override
......@@ -805,9 +868,42 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate {
}
class _PathPaintPredicate extends _DrawCommandPaintPredicate {
_PathPaintPredicate({ Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
_PathPaintPredicate({ this.includes, this.excludes, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
#drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style
);
final Iterable<Offset> includes;
final Iterable<Offset> excludes;
@override
void verifyArguments(List<dynamic> arguments) {
super.verifyArguments(arguments);
final Path pathArgument = arguments[0];
if (includes != null) {
for (Offset offset in includes) {
if (!pathArgument.contains(offset))
throw 'It called $methodName with a path that unexpectedly did not contain $offset.';
}
}
if (excludes != null) {
for (Offset offset in excludes) {
if (pathArgument.contains(offset))
throw 'It called $methodName with a path that unexpectedly contained $offset.';
}
}
}
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (includes != null && excludes != null) {
description.add('that contains $includes and does not contain $excludes');
} else if (includes != null) {
description.add('that contains $includes');
} else if (excludes != null) {
description.add('that does not contain $excludes');
}
}
}
// TODO(ianh): add arguments to test the points, length, angle, that kind of thing
......
......@@ -77,9 +77,11 @@ void main() {
actualDecoration = actualBox.decoration;
expect(actualDecoration.color, const Color(0xFF7F7F7F));
expect(actualDecoration.border.left.width, 2.5);
expect(actualDecoration.border.left.style, BorderStyle.solid);
expect(actualDecoration.border.left.color, const Color(0xFF101010));
expect(actualDecoration.border, const isInstanceOf<Border>());
final Border border = actualDecoration.border;
expect(border.left.width, 2.5);
expect(border.left.style, BorderStyle.solid);
expect(border.left.color, const Color(0xFF101010));
expect(actualDecoration.borderRadius, new BorderRadius.circular(5.0));
expect(actualDecoration.shape, BoxShape.rectangle);
expect(actualDecoration.boxShadow[0].blurRadius, 5.0);
......@@ -131,9 +133,11 @@ void main() {
// Same as the test above but the values should be much closer to the
// tween's end values given the easeOut curve.
expect(actualDecoration.color, const Color(0xFF505050));
expect(actualDecoration.border.left.width, closeTo(1.9, 0.1));
expect(actualDecoration.border.left.style, BorderStyle.solid);
expect(actualDecoration.border.left.color, const Color(0xFF151515));
expect(actualDecoration.border, const isInstanceOf<Border>());
final Border border = actualDecoration.border;
expect(border.left.width, closeTo(1.9, 0.1));
expect(border.left.style, BorderStyle.solid);
expect(border.left.color, const Color(0xFF151515));
expect(actualDecoration.borderRadius.topLeft.x, closeTo(6.8, 0.1));
expect(actualDecoration.shape, BoxShape.rectangle);
expect(actualDecoration.boxShadow[0].blurRadius, closeTo(3.1, 0.1));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment