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

5 6
// @dart = 2.8

7
import 'package:flutter/foundation.dart';
8
import 'package:flutter/rendering.dart';
9
import 'package:flutter_test/flutter_test.dart';
10 11 12 13 14

import 'rendering_tester.dart';

void main() {
  test('Overconstrained flex', () {
15 16
    final RenderDecoratedBox box = RenderDecoratedBox(decoration: const BoxDecoration());
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr, children: <RenderBox>[box]);
17
    layout(flex, constraints: const BoxConstraints(
18
      minWidth: 200.0, maxWidth: 200.0, minHeight: 200.0, maxHeight: 200.0),
19
    );
20

21 22
    expect(flex.size.width, equals(200.0), reason: 'flex width');
    expect(flex.size.height, equals(200.0), reason: 'flex height');
23
  });
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
  test('Inconsequential overflow is ignored', () {
    // These values are meant to simulate slight rounding errors in addition
    // or subtraction in the layout code for Flex.
    const double slightlyLarger = 438.8571428571429;
    const double slightlySmaller = 438.85714285714283;
    final List<dynamic> exceptions = <dynamic>[];
    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    FlutterError.onError = (FlutterErrorDetails details) {
      exceptions.add(details.exception);
    };
    const BoxConstraints square = BoxConstraints.tightFor(width: slightlyLarger, height: 100.0);
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(
      textDirection: TextDirection.ltr,
      mainAxisSize: MainAxisSize.min,
    );
    final RenderConstrainedOverflowBox parent = RenderConstrainedOverflowBox(
      minWidth: 0.0,
      maxWidth: slightlySmaller,
      minHeight: 0.0,
      maxHeight: 400.0,
      child: flex,
    );
    flex.add(box1);
    layout(parent);
    expect(flex.size, const Size(slightlySmaller, 100.0));
    pumpFrame(phase: EnginePhase.paint);

    expect(exceptions, isEmpty);
    FlutterError.onError = oldHandler;
  });

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  test('Clip behavior is respected', () {
    const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
    final TestClipPaintingContext context = TestClipPaintingContext();

    // By default, clipBehavior should be Clip.none
    final RenderFlex defaultFlex = RenderFlex(direction: Axis.vertical, children: <RenderBox>[box200x200]);
    layout(defaultFlex, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors);
    defaultFlex.paint(context, Offset.zero);
    expect(context.clipBehavior, equals(Clip.none));

    for (final Clip clip in Clip.values) {
      final RenderFlex flex = RenderFlex(direction: Axis.vertical, children: <RenderBox>[box200x200], clipBehavior: clip);
      layout(flex, constraints: viewport, phase: EnginePhase.composite, onErrors: expectOverflowedErrors);
      flex.paint(context, Offset.zero);
      expect(context.clipBehavior, equals(clip));
    }
  });

75
  test('Vertical Overflow', () {
76
    final RenderConstrainedBox flexible = RenderConstrainedBox(
77 78
      additionalConstraints: const BoxConstraints.expand()
    );
79
    final RenderFlex flex = RenderFlex(
80
      direction: Axis.vertical,
81
      verticalDirection: VerticalDirection.down,
82
      children: <RenderBox>[
83
        RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(height: 200.0)),
84
        flexible,
85
      ],
86
    );
87
    final FlexParentData flexParentData = flexible.parentData as FlexParentData;
88
    flexParentData.flex = 1;
89
    const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
90 91
    layout(flex, constraints: viewport);
    expect(flexible.size.height, equals(0.0));
92 93 94 95
    expect(flex.getMinIntrinsicHeight(100.0), equals(200.0));
    expect(flex.getMaxIntrinsicHeight(100.0), equals(200.0));
    expect(flex.getMinIntrinsicWidth(100.0), equals(0.0));
    expect(flex.getMaxIntrinsicWidth(100.0), equals(0.0));
96 97 98
  });

  test('Horizontal Overflow', () {
99
    final RenderConstrainedBox flexible = RenderConstrainedBox(
100 101
      additionalConstraints: const BoxConstraints.expand()
    );
102
    final RenderFlex flex = RenderFlex(
103
      direction: Axis.horizontal,
104
      textDirection: TextDirection.ltr,
105
      children: <RenderBox>[
106
        RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200.0)),
107
        flexible,
108
      ],
109
    );
110
    final FlexParentData flexParentData = flexible.parentData as FlexParentData;
111
    flexParentData.flex = 1;
112
    const BoxConstraints viewport = BoxConstraints(maxHeight: 100.0, maxWidth: 100.0);
113 114
    layout(flex, constraints: viewport);
    expect(flexible.size.width, equals(0.0));
115 116 117 118
    expect(flex.getMinIntrinsicHeight(100.0), equals(0.0));
    expect(flex.getMaxIntrinsicHeight(100.0), equals(0.0));
    expect(flex.getMinIntrinsicWidth(100.0), equals(200.0));
    expect(flex.getMaxIntrinsicWidth(100.0), equals(200.0));
119 120 121
  });

  test('Vertical Flipped Constraints', () {
122
    final RenderFlex flex = RenderFlex(
123
      direction: Axis.vertical,
124
      verticalDirection: VerticalDirection.down,
125
      children: <RenderBox>[
126
        RenderAspectRatio(aspectRatio: 1.0),
127
      ],
128
    );
129
    const BoxConstraints viewport = BoxConstraints(maxHeight: 200.0, maxWidth: 1000.0);
130
    layout(flex, constraints: viewport);
131
    expect(flex.getMaxIntrinsicWidth(200.0), equals(0.0));
132 133
  });

134
  // We can't write a horizontal version of the above test due to
135 136
  // RenderAspectRatio being height-in, width-out.

137
  test('Defaults', () {
138
    final RenderFlex flex = RenderFlex();
139
    expect(flex.crossAxisAlignment, equals(CrossAxisAlignment.center));
140
    expect(flex.direction, equals(Axis.horizontal));
141 142
    expect(flex, hasAGoodToStringDeep);
    expect(
143
      flex.toStringDeep(minLevel: DiagnosticLevel.info),
144 145
      equalsIgnoringHashCodes(
        'RenderFlex#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
Ian Hickson's avatar
Ian Hickson committed
146 147
        '   parentData: MISSING\n'
        '   constraints: MISSING\n'
148 149 150 151 152
        '   size: MISSING\n'
        '   direction: horizontal\n'
        '   mainAxisAlignment: start\n'
        '   mainAxisSize: max\n'
        '   crossAxisAlignment: center\n'
153
        '   verticalDirection: down\n'
154 155
      ),
    );
156 157 158
  });

  test('Parent data', () {
159 160 161
    final RenderDecoratedBox box1 = RenderDecoratedBox(decoration: const BoxDecoration());
    final RenderDecoratedBox box2 = RenderDecoratedBox(decoration: const BoxDecoration());
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr, children: <RenderBox>[box1, box2]);
162
    layout(flex, constraints: const BoxConstraints(
163
      minWidth: 0.0, maxWidth: 100.0, minHeight: 0.0, maxHeight: 100.0),
164 165 166 167 168 169
    );
    expect(box1.size.width, equals(0.0));
    expect(box1.size.height, equals(0.0));
    expect(box2.size.width, equals(0.0));
    expect(box2.size.height, equals(0.0));

170
    final FlexParentData box2ParentData = box2.parentData as FlexParentData;
171
    box2ParentData.flex = 1;
172 173 174 175 176 177 178 179 180
    flex.markNeedsLayout();
    pumpFrame();
    expect(box1.size.width, equals(0.0));
    expect(box1.size.height, equals(0.0));
    expect(box2.size.width, equals(100.0));
    expect(box2.size.height, equals(0.0));
  });

  test('Stretch', () {
181 182 183
    final RenderDecoratedBox box1 = RenderDecoratedBox(decoration: const BoxDecoration());
    final RenderDecoratedBox box2 = RenderDecoratedBox(decoration: const BoxDecoration());
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr);
184
    flex.setupParentData(box2);
185
    final FlexParentData box2ParentData = box2.parentData as FlexParentData;
186 187
    box2ParentData.flex = 2;
    flex.addAll(<RenderBox>[box1, box2]);
188
    layout(flex, constraints: const BoxConstraints(
189
      minWidth: 0.0, maxWidth: 100.0, minHeight: 0.0, maxHeight: 100.0),
190 191 192 193 194 195
    );
    expect(box1.size.width, equals(0.0));
    expect(box1.size.height, equals(0.0));
    expect(box2.size.width, equals(100.0));
    expect(box2.size.height, equals(0.0));

196
    flex.crossAxisAlignment = CrossAxisAlignment.stretch;
197 198 199 200 201 202
    pumpFrame();
    expect(box1.size.width, equals(0.0));
    expect(box1.size.height, equals(100.0));
    expect(box2.size.width, equals(100.0));
    expect(box2.size.height, equals(100.0));

203
    flex.direction = Axis.vertical;
204 205 206 207 208 209
    pumpFrame();
    expect(box1.size.width, equals(100.0));
    expect(box1.size.height, equals(0.0));
    expect(box2.size.width, equals(100.0));
    expect(box2.size.height, equals(100.0));
  });
210 211

  test('Space evenly', () {
212 213 214 215
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr, mainAxisAlignment: MainAxisAlignment.spaceEvenly);
216 217
    flex.addAll(<RenderBox>[box1, box2, box3]);
    layout(flex, constraints: const BoxConstraints(
218
      minWidth: 0.0, maxWidth: 500.0, minHeight: 0.0, maxHeight: 400.0),
219 220
    );
    Offset getOffset(RenderBox box) {
221
      final FlexParentData parentData = box.parentData as FlexParentData;
222 223 224 225 226 227 228 229 230
      return parentData.offset;
    }
    expect(getOffset(box1).dx, equals(50.0));
    expect(box1.size.width, equals(100.0));
    expect(getOffset(box2).dx, equals(200.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(350.0));
    expect(box3.size.width, equals(100.0));

231
    flex.direction = Axis.vertical;
232 233 234 235 236 237 238 239
    pumpFrame();
    expect(getOffset(box1).dy, equals(25.0));
    expect(box1.size.height, equals(100.0));
    expect(getOffset(box2).dy, equals(150.0));
    expect(box2.size.height, equals(100.0));
    expect(getOffset(box3).dy, equals(275.0));
    expect(box3.size.height, equals(100.0));
  });
Adam Barth's avatar
Adam Barth committed
240 241

  test('Fit.loose', () {
242 243 244 245
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr, mainAxisAlignment: MainAxisAlignment.spaceBetween);
Adam Barth's avatar
Adam Barth committed
246 247
    flex.addAll(<RenderBox>[box1, box2, box3]);
    layout(flex, constraints: const BoxConstraints(
248
      minWidth: 0.0, maxWidth: 500.0, minHeight: 0.0, maxHeight: 400.0),
Adam Barth's avatar
Adam Barth committed
249 250
    );
    Offset getOffset(RenderBox box) {
251
      final FlexParentData parentData = box.parentData as FlexParentData;
Adam Barth's avatar
Adam Barth committed
252 253 254 255 256 257 258 259 260 261
      return parentData.offset;
    }
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(100.0));
    expect(getOffset(box2).dx, equals(200.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(400.0));
    expect(box3.size.width, equals(100.0));

    void setFit(RenderBox box, FlexFit fit) {
262
      final FlexParentData parentData = box.parentData as FlexParentData;
Adam Barth's avatar
Adam Barth committed
263 264 265 266 267
      parentData.flex = 1;
      parentData.fit = fit;
    }

    setFit(box1, FlexFit.loose);
268
    flex.markNeedsLayout();
Adam Barth's avatar
Adam Barth committed
269 270 271 272 273 274 275 276 277

    pumpFrame();
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(100.0));
    expect(getOffset(box2).dx, equals(200.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(400.0));
    expect(box3.size.width, equals(100.0));

278
    box1.additionalConstraints = const BoxConstraints.tightFor(width: 1000.0, height: 100.0);
Adam Barth's avatar
Adam Barth committed
279 280 281 282 283 284 285 286 287

    pumpFrame();
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(300.0));
    expect(getOffset(box2).dx, equals(300.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(400.0));
    expect(box3.size.width, equals(100.0));
  });
288 289

  test('Flexible with MainAxisSize.min', () {
290 291 292 293
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 100.0, height: 100.0));
    final RenderFlex flex = RenderFlex(
294
      textDirection: TextDirection.ltr,
295
      mainAxisSize: MainAxisSize.min,
296
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
297 298 299
    );
    flex.addAll(<RenderBox>[box1, box2, box3]);
    layout(flex, constraints: const BoxConstraints(
300
      minWidth: 0.0, maxWidth: 500.0, minHeight: 0.0, maxHeight: 400.0),
301 302
    );
    Offset getOffset(RenderBox box) {
303
      final FlexParentData parentData = box.parentData as FlexParentData;
304 305 306 307 308 309 310 311 312 313 314
      return parentData.offset;
    }
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(100.0));
    expect(getOffset(box2).dx, equals(100.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(200.0));
    expect(box3.size.width, equals(100.0));
    expect(flex.size.width, equals(300.0));

    void setFit(RenderBox box, FlexFit fit) {
315
      final FlexParentData parentData = box.parentData as FlexParentData;
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
      parentData.flex = 1;
      parentData.fit = fit;
    }

    setFit(box1, FlexFit.tight);
    flex.markNeedsLayout();

    pumpFrame();
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(300.0));
    expect(getOffset(box2).dx, equals(300.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(400.0));
    expect(box3.size.width, equals(100.0));
    expect(flex.size.width, equals(500.0));

    setFit(box1, FlexFit.loose);
    flex.markNeedsLayout();

    pumpFrame();
    expect(getOffset(box1).dx, equals(0.0));
    expect(box1.size.width, equals(100.0));
    expect(getOffset(box2).dx, equals(100.0));
    expect(box2.size.width, equals(100.0));
    expect(getOffset(box3).dx, equals(200.0));
    expect(box3.size.width, equals(100.0));
    expect(flex.size.width, equals(300.0));
  });
344 345 346

  test('MainAxisSize.min inside unconstrained', () {
    FlutterError.onError = (FlutterErrorDetails details) => throw details.exception;
347
    const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
348 349 350 351
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(
352
      textDirection: TextDirection.ltr,
353 354
      mainAxisSize: MainAxisSize.min,
    );
355
    final RenderConstrainedOverflowBox parent = RenderConstrainedOverflowBox(
356
      minWidth: 0.0,
357
      maxWidth: double.infinity,
358 359 360 361 362 363 364
      minHeight: 0.0,
      maxHeight: 400.0,
      child: flex,
    );
    flex.addAll(<RenderBox>[box1, box2, box3]);
    layout(parent);
    expect(flex.size, const Size(300.0, 100.0));
365
    final FlexParentData box2ParentData = box2.parentData as FlexParentData;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    box2ParentData.flex = 1;
    box2ParentData.fit = FlexFit.loose;
    flex.markNeedsLayout();
    pumpFrame();
    expect(flex.size, const Size(300.0, 100.0));
    parent.maxWidth = 500.0; // NOW WITH CONSTRAINED BOUNDARIES
    pumpFrame();
    expect(flex.size, const Size(300.0, 100.0));
    flex.mainAxisSize = MainAxisSize.max;
    pumpFrame();
    expect(flex.size, const Size(500.0, 100.0));
    flex.mainAxisSize = MainAxisSize.min;
    box2ParentData.fit = FlexFit.tight;
    flex.markNeedsLayout();
    pumpFrame();
    expect(flex.size, const Size(500.0, 100.0));
    parent.maxWidth = 505.0;
    pumpFrame();
    expect(flex.size, const Size(505.0, 100.0));
  });

  test('MainAxisSize.min inside unconstrained', () {
388
    const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
389 390 391 392
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(
393
      textDirection: TextDirection.ltr,
394 395
      mainAxisSize: MainAxisSize.min,
    );
396
    final RenderConstrainedOverflowBox parent = RenderConstrainedOverflowBox(
397
      minWidth: 0.0,
398
      maxWidth: double.infinity,
399 400 401 402 403
      minHeight: 0.0,
      maxHeight: 400.0,
      child: flex,
    );
    flex.addAll(<RenderBox>[box1, box2, box3]);
404
    final FlexParentData box2ParentData = box2.parentData as FlexParentData;
405
    box2ParentData.flex = 1;
406 407 408 409
    final List<dynamic> exceptions = <dynamic>[];
    layout(parent, onErrors: () {
      exceptions.addAll(renderer.takeAllFlutterExceptions());
    });
410
    expect(exceptions, isNotEmpty);
Dan Field's avatar
Dan Field committed
411
    expect(exceptions.first, isFlutterError);
412 413 414
  });

  test('MainAxisSize.min inside unconstrained', () {
415
    const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
416 417 418 419
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(
420
      textDirection: TextDirection.ltr,
421 422
      mainAxisSize: MainAxisSize.max,
    );
423
    final RenderConstrainedOverflowBox parent = RenderConstrainedOverflowBox(
424
      minWidth: 0.0,
425
      maxWidth: double.infinity,
426 427 428 429 430
      minHeight: 0.0,
      maxHeight: 400.0,
      child: flex,
    );
    flex.addAll(<RenderBox>[box1, box2, box3]);
431
    final FlexParentData box2ParentData = box2.parentData as FlexParentData;
432 433
    box2ParentData.flex = 1;
    box2ParentData.fit = FlexFit.loose;
434 435 436 437
    final List<dynamic> exceptions = <dynamic>[];
    layout(parent, onErrors: () {
      exceptions.addAll(renderer.takeAllFlutterExceptions());
    });
438
    expect(exceptions, isNotEmpty);
Dan Field's avatar
Dan Field committed
439
    expect(exceptions.first, isFlutterError);
440
  });
441

442
  test('MainAxisSize.min inside tightly constrained', () {
443
    const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
444 445 446 447
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(
448 449 450 451 452 453 454 455 456 457 458 459 460 461
      textDirection: TextDirection.rtl,
      mainAxisSize: MainAxisSize.min,
    );
    flex.addAll(<RenderBox>[box1, box2, box3]);
    layout(flex);
    expect(flex.constraints.hasTightWidth, isTrue);
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 250.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 250.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 250.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));
  });

462
  test('Flex RTL', () {
463
    const BoxConstraints square = BoxConstraints.tightFor(width: 100.0, height: 100.0);
464 465 466 467
    final RenderConstrainedBox box1 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box2 = RenderConstrainedBox(additionalConstraints: square);
    final RenderConstrainedBox box3 = RenderConstrainedBox(additionalConstraints: square);
    final RenderFlex flex = RenderFlex(textDirection: TextDirection.ltr, children: <RenderBox>[box1, box2, box3]);
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
    layout(flex);
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 250.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(100.0, 250.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 250.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.mainAxisAlignment = MainAxisAlignment.end;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 250.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 250.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 250.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.textDirection = TextDirection.rtl;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 250.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(100.0, 250.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 250.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.mainAxisAlignment = MainAxisAlignment.start;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 250.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 250.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 250.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.start; // vertical direction is down
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 0.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 0.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.end;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 500.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 500.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.verticalDirection = VerticalDirection.up;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 0.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 0.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.start;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 500.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 500.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.direction = Axis.vertical; // and main=start, cross=start, up, rtl
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 300.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.end;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.stretch;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(box1.size, const Size(800.0, 100.0));
    expect(box2.size, const Size(800.0, 100.0));
    expect(box3.size, const Size(800.0, 100.0));

    flex.textDirection = TextDirection.ltr;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(box1.size, const Size(800.0, 100.0));
    expect(box2.size, const Size(800.0, 100.0));
    expect(box3.size, const Size(800.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.start;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.crossAxisAlignment = CrossAxisAlignment.end;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 500.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 300.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.verticalDirection = VerticalDirection.down;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 0.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 100.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 200.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));

    flex.mainAxisAlignment = MainAxisAlignment.end;
    pumpFrame();
    expect(box1.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 300.0));
    expect(box2.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 400.0));
    expect(box3.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 500.0));
    expect(box1.size, const Size(100.0, 100.0));
    expect(box2.size, const Size(100.0, 100.0));
    expect(box3.size, const Size(100.0, 100.0));
  });
611
}