border_test.dart 15.2 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/widgets.dart';
6 7
import 'package:flutter_test/flutter_test.dart';

8 9 10 11 12 13 14 15 16
class TestCanvas implements Canvas {
  final List<Invocation> invocations = <Invocation>[];

  @override
  void noSuchMethod(Invocation invocation) {
    invocations.add(invocation);
  }
}

17
void main() {
18
  test('Border.fromBorderSide constructor', () {
19
    const BorderSide side = BorderSide();
20
    const Border border = Border.fromBorderSide(side);
21 22 23 24 25 26
    expect(border.left, same(side));
    expect(border.top, same(side));
    expect(border.right, same(side));
    expect(border.bottom, same(side));
  });

27 28
  test('Border.symmetric constructor', () {
    const BorderSide side1 = BorderSide(color: Color(0xFFFFFFFF));
29
    const BorderSide side2 = BorderSide();
30
    const Border border = Border.symmetric(vertical: side1, horizontal: side2);
31 32 33 34
    expect(border.left, same(side1));
    expect(border.top, same(side2));
    expect(border.right, same(side1));
    expect(border.bottom, same(side2));
35 36
  });

37
  test('Border.merge', () {
38 39 40 41
    const BorderSide magenta3 = BorderSide(color: Color(0xFFFF00FF), width: 3.0);
    const BorderSide magenta6 = BorderSide(color: Color(0xFFFF00FF), width: 6.0);
    const BorderSide yellow2 = BorderSide(color: Color(0xFFFFFF00), width: 2.0);
    const BorderSide yellowNone0 = BorderSide(color: Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
42 43
    expect(
      Border.merge(
44 45
        const Border(top: yellow2),
        const Border(right: magenta3),
46
      ),
47
      const Border(top: yellow2, right: magenta3),
48 49 50
    );
    expect(
      Border.merge(
51 52
        const Border(bottom: magenta3),
        const Border(bottom: magenta3),
53
      ),
54
      const Border(bottom: magenta6),
55 56 57
    );
    expect(
      Border.merge(
58 59
        const Border(left: magenta3, right: yellowNone0),
        const Border(right: yellow2),
60
      ),
61
      const Border(left: magenta3, right: yellow2),
62 63 64 65 66 67 68
    );
    expect(
      Border.merge(const Border(), const Border()),
      const Border(),
    );
    expect(
      () => Border.merge(
69 70
        const Border(left: magenta3),
        const Border(left: yellow2),
71 72 73 74 75 76
      ),
      throwsAssertionError,
    );
  });

  test('Border.add', () {
77 78 79 80
    const BorderSide magenta3 = BorderSide(color: Color(0xFFFF00FF), width: 3.0);
    const BorderSide magenta6 = BorderSide(color: Color(0xFFFF00FF), width: 6.0);
    const BorderSide yellow2 = BorderSide(color: Color(0xFFFFFF00), width: 2.0);
    const BorderSide yellowNone0 = BorderSide(color: Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
81
    expect(
82 83
      const Border(top: yellow2) + const Border(right: magenta3),
      const Border(top: yellow2, right: magenta3),
84 85
    );
    expect(
86 87
      const Border(bottom: magenta3) + const Border(bottom: magenta3),
      const Border(bottom: magenta6),
88 89
    );
    expect(
90 91
      const Border(left: magenta3, right: yellowNone0) + const Border(right: yellow2),
      const Border(left: magenta3, right: yellow2),
92 93
    );
    expect(
Ian Hickson's avatar
Ian Hickson committed
94
      const Border() + const Border(),
95 96 97
      const Border(),
    );
    expect(
98
      const Border(left: magenta3) + const Border(left: yellow2),
Dan Field's avatar
Dan Field committed
99
      isNot(isA<Border>()), // see shape_border_test.dart for better tests of this case
100
    );
101 102
    const Border b3 = Border(top: magenta3);
    const Border b6 = Border(top: magenta6);
Ian Hickson's avatar
Ian Hickson committed
103
    expect(b3 + b3, b6);
104 105
    const Border b0 = Border(top: yellowNone0);
    const Border bZ = Border();
Ian Hickson's avatar
Ian Hickson committed
106 107 108 109
    expect(b0 + b0, bZ);
    expect(bZ + bZ, bZ);
    expect(b0 + bZ, bZ);
    expect(bZ + b0, bZ);
110 111 112
  });

  test('Border.scale', () {
113 114 115 116 117 118
    const BorderSide magenta3 = BorderSide(color: Color(0xFFFF00FF), width: 3.0);
    const BorderSide magenta6 = BorderSide(color: Color(0xFFFF00FF), width: 6.0);
    const BorderSide yellow2 = BorderSide(color: Color(0xFFFFFF00), width: 2.0);
    const BorderSide yellowNone0 = BorderSide(color: Color(0xFFFFFF00), width: 0.0, style: BorderStyle.none);
    const Border b3 = Border(left: magenta3);
    const Border b6 = Border(left: magenta6);
119
    expect(b3.scale(2.0), b6);
120
    const Border bY0 = Border(top: yellowNone0);
121
    expect(bY0.scale(3.0), bY0);
122
    const Border bY2 = Border(top: yellow2);
123 124
    expect(bY2.scale(0.0), bY0);
  });
Ian Hickson's avatar
Ian Hickson committed
125 126 127 128

  test('Border.dimensions', () {
    expect(
      const Border(
129 130 131 132
        left: BorderSide(width: 2.0),
        top: BorderSide(width: 3.0),
        bottom: BorderSide(width: 5.0),
        right: BorderSide(width: 7.0),
Ian Hickson's avatar
Ian Hickson committed
133 134 135 136 137 138 139 140
      ).dimensions,
      const EdgeInsets.fromLTRB(2.0, 3.0, 7.0, 5.0),
    );
  });

  test('Border.isUniform', () {
    expect(
      const Border(
141 142 143 144
        left: BorderSide(width: 3.0),
        top: BorderSide(width: 3.0),
        right: BorderSide(width: 3.0),
        bottom: BorderSide(width: 3.1),
Ian Hickson's avatar
Ian Hickson committed
145 146 147 148 149
      ).isUniform,
      false,
    );
    expect(
      const Border(
150 151 152 153
        left: BorderSide(width: 3.0),
        top: BorderSide(width: 3.0),
        right: BorderSide(width: 3.0),
        bottom: BorderSide(width: 3.0),
Ian Hickson's avatar
Ian Hickson committed
154 155 156 157 158
      ).isUniform,
      true,
    );
    expect(
      const Border(
159 160 161 162
        left: BorderSide(color: Color(0xFFFFFFFE)),
        top: BorderSide(color: Color(0xFFFFFFFF)),
        right: BorderSide(color: Color(0xFFFFFFFF)),
        bottom: BorderSide(color: Color(0xFFFFFFFF)),
Ian Hickson's avatar
Ian Hickson committed
163 164 165 166 167
      ).isUniform,
      false,
    );
    expect(
      const Border(
168 169 170 171
        left: BorderSide(color: Color(0xFFFFFFFF)),
        top: BorderSide(color: Color(0xFFFFFFFF)),
        right: BorderSide(color: Color(0xFFFFFFFF)),
        bottom: BorderSide(color: Color(0xFFFFFFFF)),
Ian Hickson's avatar
Ian Hickson committed
172 173 174 175 176
      ).isUniform,
      true,
    );
    expect(
      const Border(
177 178 179
        left: BorderSide(style: BorderStyle.none),
        top: BorderSide(style: BorderStyle.none),
        right: BorderSide(style: BorderStyle.none),
180
        bottom: BorderSide(width: 0.0),
Ian Hickson's avatar
Ian Hickson committed
181 182 183 184 185
      ).isUniform,
      false,
    );
    expect(
      const Border(
186 187 188
        left: BorderSide(style: BorderStyle.none),
        top: BorderSide(style: BorderStyle.none),
        right: BorderSide(style: BorderStyle.none),
189
        bottom: BorderSide(width: 0.0),
Ian Hickson's avatar
Ian Hickson committed
190 191 192 193 194
      ).isUniform,
      false,
    );
    expect(
      const Border(
195 196 197
        left: BorderSide(style: BorderStyle.none),
        top: BorderSide(style: BorderStyle.none),
        right: BorderSide(style: BorderStyle.none),
Ian Hickson's avatar
Ian Hickson committed
198 199 200
      ).isUniform,
      false,
    );
201 202 203
    expect(
      const Border(
        left: BorderSide(),
204 205
        top: BorderSide(strokeAlign: BorderSide.strokeAlignCenter),
        right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside),
206 207 208
      ).isUniform,
      false,
    );
Ian Hickson's avatar
Ian Hickson committed
209
    expect(
210
      const Border().isUniform,
Ian Hickson's avatar
Ian Hickson committed
211 212 213 214 215 216 217 218 219
      true,
    );
    expect(
      const Border().isUniform,
      true,
    );
  });

  test('Border.lerp', () {
220 221 222 223 224 225 226
    const Border visualWithTop10 = Border(top: BorderSide(width: 10.0));
    const Border atMinus100 = Border(left: BorderSide(width: 0.0), right: BorderSide(width: 300.0));
    const Border at0 = Border(left: BorderSide(width: 100.0), right: BorderSide(width: 200.0));
    const Border at25 = Border(left: BorderSide(width: 125.0), right: BorderSide(width: 175.0));
    const Border at75 = Border(left: BorderSide(width: 175.0), right: BorderSide(width: 125.0));
    const Border at100 = Border(left: BorderSide(width: 200.0), right: BorderSide(width: 100.0));
    const Border at200 = Border(left: BorderSide(width: 300.0), right: BorderSide(width: 0.0));
Ian Hickson's avatar
Ian Hickson committed
227 228

    expect(Border.lerp(null, null, -1.0), null);
229
    expect(Border.lerp(visualWithTop10, null, -1.0), const Border(top: BorderSide(width: 20.0)));
Ian Hickson's avatar
Ian Hickson committed
230 231 232 233
    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);
234
    expect(Border.lerp(visualWithTop10, null, 0.0), const Border(top: BorderSide(width: 10.0)));
Ian Hickson's avatar
Ian Hickson committed
235 236 237 238
    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);
239 240
    expect(Border.lerp(visualWithTop10, null, 0.25), const Border(top: BorderSide(width: 7.5)));
    expect(Border.lerp(null, visualWithTop10, 0.25), const Border(top: BorderSide(width: 2.5)));
Ian Hickson's avatar
Ian Hickson committed
241 242 243
    expect(Border.lerp(at0, at100, 0.25), at25);

    expect(Border.lerp(null, null, 0.75), null);
244 245
    expect(Border.lerp(visualWithTop10, null, 0.75), const Border(top: BorderSide(width: 2.5)));
    expect(Border.lerp(null, visualWithTop10, 0.75), const Border(top: BorderSide(width: 7.5)));
Ian Hickson's avatar
Ian Hickson committed
246 247 248 249
    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());
250
    expect(Border.lerp(null, visualWithTop10, 1.0), const Border(top: BorderSide(width: 10.0)));
Ian Hickson's avatar
Ian Hickson committed
251 252 253 254
    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());
255
    expect(Border.lerp(null, visualWithTop10, 2.0), const Border(top: BorderSide(width: 20.0)));
Ian Hickson's avatar
Ian Hickson committed
256 257
    expect(Border.lerp(at0, at100, 2.0), at200);
  });
258 259 260 261 262 263

  test('Border - throws correct exception with strokeAlign', () {
    late FlutterError error;
    try {
      final TestCanvas canvas = TestCanvas();
      // Border.all supports all StrokeAlign values.
264
      // Border() supports [BorderSide.strokeAlignInside] only.
265
      const Border(
266 267
        left: BorderSide(strokeAlign: BorderSide.strokeAlignCenter, color: Color(0xff000001)),
        right: BorderSide(strokeAlign: BorderSide.strokeAlignOutside, color: Color(0xff000002)),
268 269 270 271 272 273 274 275
      ).paint(canvas, const Rect.fromLTWH(10.0, 20.0, 30.0, 40.0));
    } on FlutterError catch (e) {
      error = e;
    }
    expect(error, isNotNull);
    expect(error.diagnostics.length, 1);
    expect(
      error.diagnostics[0].toStringDeep(),
276
      'A Border can only draw strokeAlign different than\nBorderSide.strokeAlignInside on borders with uniform colors and\nstyles.\n',
277 278 279 280 281 282 283
    );
  });

  test('Border.dimension', () {
    final Border insideBorder = Border.all(width: 10);
    expect(insideBorder.dimensions, const EdgeInsets.all(10));

284
    final Border centerBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignCenter);
285 286
    expect(centerBorder.dimensions, const EdgeInsets.all(5));

287
    final Border outsideBorder = Border.all(width: 10, strokeAlign: BorderSide.strokeAlignOutside);
288 289 290 291 292 293
    expect(outsideBorder.dimensions, EdgeInsets.zero);

    const BorderSide insideSide = BorderSide(width: 10);
    const BorderDirectional insideBorderDirectional = BorderDirectional(top: insideSide, bottom: insideSide, start: insideSide, end: insideSide);
    expect(insideBorderDirectional.dimensions, const EdgeInsetsDirectional.all(10));

294
    const BorderSide centerSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter);
295 296 297
    const BorderDirectional centerBorderDirectional = BorderDirectional(top: centerSide, bottom: centerSide, start: centerSide, end: centerSide);
    expect(centerBorderDirectional.dimensions, const EdgeInsetsDirectional.all(5));

298
    const BorderSide outsideSide = BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignOutside);
299 300
    const BorderDirectional outsideBorderDirectional = BorderDirectional(top: outsideSide, bottom: outsideSide, start: outsideSide, end: outsideSide);
    expect(outsideBorderDirectional.dimensions, EdgeInsetsDirectional.zero);
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

    const Border nonUniformBorder = Border(
      left: BorderSide(width: 5),
      top: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter),
      right: BorderSide(width: 15, strokeAlign: BorderSide.strokeAlignOutside),
      bottom: BorderSide(width: 20),
    );
    expect(nonUniformBorder.dimensions, const EdgeInsets.fromLTRB(5, 5, 0, 20));

    const BorderDirectional nonUniformBorderDirectional = BorderDirectional(
      start: BorderSide(width: 5),
      top: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter),
      end: BorderSide(width: 15, strokeAlign: BorderSide.strokeAlignOutside),
      bottom: BorderSide(width: 20),
    );
    expect(nonUniformBorderDirectional.dimensions, const EdgeInsetsDirectional.fromSTEB(5, 5, 0, 20));
  });

  testWidgets('Non-Uniform Border variations', (WidgetTester tester) async {

    Widget buildWidget({ required BoxBorder border, BorderRadius? borderRadius, BoxShape boxShape = BoxShape.rectangle}) {
      return Directionality(
        textDirection: TextDirection.ltr,
        child: DecoratedBox(
          decoration: BoxDecoration(
            shape: boxShape,
            border: border,
            borderRadius: borderRadius,
          ),
        ),
      );
    }

    // This is used to test every allowed non-uniform border combination.
    const Border allowedBorderVariations = Border(
      left: BorderSide(width: 5),
      top: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter),
      right: BorderSide(width: 15, strokeAlign: BorderSide.strokeAlignOutside),
      bottom: BorderSide(width: 20),
    );

    // This falls into non-uniform border because of strokeAlign.
    await tester.pumpWidget(buildWidget(border: allowedBorderVariations));
    expect(tester.takeException(), isNull,
        reason: 'Border with non-uniform strokeAlign should not fail.');

    await tester.pumpWidget(buildWidget(
      border: allowedBorderVariations,
      borderRadius: BorderRadius.circular(25),
    ));
    expect(tester.takeException(), isNull);

    await tester.pumpWidget(buildWidget(border: allowedBorderVariations, boxShape: BoxShape.circle));
    expect(tester.takeException(), isNull);

    await tester.pumpWidget(
      buildWidget(
        border: const Border(
          left: BorderSide(width: 5, style: BorderStyle.none),
          top: BorderSide(width: 10),
          right: BorderSide(width: 15),
          bottom: BorderSide(width: 20),
        ),
        borderRadius: BorderRadius.circular(25),
      ),
    );
    expect(tester.takeException(), isAssertionError,
        reason: 'Border with non-uniform styles should fail with borderRadius.');

    await tester.pumpWidget(
      buildWidget(
        border: const Border(
          left: BorderSide(width: 5, color: Color(0xff123456)),
          top: BorderSide(width: 10),
          right: BorderSide(width: 15),
          bottom: BorderSide(width: 20),
        ),
        borderRadius: BorderRadius.circular(20),
      ),
    );
    expect(tester.takeException(), isAssertionError,
        reason: 'Border with non-uniform colors should fail with borderRadius.');

    // Tests for BorderDirectional.
    const BorderDirectional allowedBorderDirectionalVariations = BorderDirectional(
      start: BorderSide(width: 5),
      top: BorderSide(width: 10, strokeAlign: BorderSide.strokeAlignCenter),
      end: BorderSide(width: 15, strokeAlign: BorderSide.strokeAlignOutside),
      bottom: BorderSide(width: 20),
    );

    await tester.pumpWidget(buildWidget(border: allowedBorderDirectionalVariations));
    expect(tester.takeException(), isNull);

    await tester.pumpWidget(buildWidget(
      border: allowedBorderDirectionalVariations,
      borderRadius: BorderRadius.circular(25),
    ));
    expect(tester.takeException(), isNull,
        reason:'BorderDirectional should not fail with uniform styles and colors.');

    await tester.pumpWidget(buildWidget(border: allowedBorderDirectionalVariations, boxShape: BoxShape.circle));
    expect(tester.takeException(), isNull);
404
  });
405
}