// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

class OrderPainter extends CustomPainter {
  const OrderPainter(this.index);

  final int index;

  static List<int> log = <int>[];

  @override
  void paint(Canvas canvas, Size size) {
    log.add(index);
  }

  @override
  bool shouldRepaint(OrderPainter old) => false;
}

Widget log(int index) => CustomPaint(painter: OrderPainter(index));

void main() {
  // NO DIRECTION

  testWidgets('Row with one Flexible child - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // Default is MainAxisAlignment.start so this should fail, asking for a direction.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Expanded(child: Container(key: child1Key, width: 100.0, height: 100.0, child: log(2))),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with default main axis parameters - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // Default is MainAxisAlignment.start so this should fail too.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with MainAxisAlignment.center - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // More than one child, so it's not clear what direction to lay out in: should fail.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with MainAxisAlignment.end - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // No direction so this should fail, asking for a direction.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with MainAxisAlignment.spaceBetween - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // More than one child, so it's not clear what direction to lay out in: should fail.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with MainAxisAlignment.spaceAround - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');
    const Key child3Key = Key('child3');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // More than one child, so it's not clear what direction to lay out in: should fail.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
          Container(key: child3Key, width: 100.0, height: 100.0, child: log(4)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row with MainAxisAlignment.spaceEvenly - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // More than one child, so it's not clear what direction to lay out in: should fail.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Container(key: child0Key, width: 200.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 200.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 200.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row and MainAxisSize.min - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('rowKey');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    final FlutterExceptionHandler oldHandler = FlutterError.onError;
    dynamic exception;
    FlutterError.onError = (FlutterErrorDetails details) {
      exception ??= details.exception;
    };

    // Default is MainAxisAlignment.start so this should fail, asking for a direction.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 150.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    FlutterError.onError = oldHandler;
    expect(exception, isAssertionError);
    expect(exception.toString(), contains('textDirection'));
    expect(OrderPainter.log, <int>[]);
  });

  testWidgets('Row MainAxisSize.min layout at zero size - no textDirection', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key childKey = Key('childKey');

    await tester.pumpWidget(Center(
      child: Container(
        width: 0.0,
        height: 0.0,
        child: Row(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              key: childKey,
              width: 100.0,
              height: 100.0,
            ),
          ],
        ),
      ),
    ));

    final RenderBox renderBox = tester.renderObject(find.byKey(childKey));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(0.0));
  });


  // LTR

  testWidgets('Row with one Flexible child - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // Default is MainAxisAlignment.start so children so the children's
    // left edges should be at 0, 100, 700, child2's width should be 600
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Expanded(child: Container(key: child1Key, width: 100.0, height: 100.0, child: log(2))),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(600.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with default main axis parameters - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // Default is MainAxisAlignment.start so children so the children's
    // left edges should be at 0, 100, 200
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(200.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.center - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's left edges should be at 300, 400
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.center,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(300.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(400.0));

    expect(OrderPainter.log, <int>[1, 2]);
  });

  testWidgets('Row with MainAxisAlignment.end - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's left edges should be at 500, 600, 700.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.ltr,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(500.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(600.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.spaceBetween - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's left edges should be at 0, 350, 700
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(350.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.spaceAround - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');
    const Key child3Key = Key('child3');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's left edges should be at 50, 250, 450, 650
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
          Container(key: child3Key, width: 100.0, height: 100.0, child: log(4)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(50.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(250.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(450.0));

    renderBox = tester.renderObject(find.byKey(child3Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(650.0));

    expect(OrderPainter.log, <int>[1, 2, 3, 4]);
  });

  testWidgets('Row with MainAxisAlignment.spaceEvenly - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 200x100 children's left edges should be at 50, 300, 550
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 200.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 200.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 200.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(50.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(300.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(550.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row and MainAxisSize.min - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('rowKey');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    // Row with MainAxisSize.min without flexible children shrink wraps.
    // Row's width should be 250, children should be at 0, 100.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisSize: MainAxisSize.min,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 150.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(250.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(150.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(100.0));

    expect(OrderPainter.log, <int>[1, 2]);
  });

  testWidgets('Row MainAxisSize.min layout at zero size - LTR', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key childKey = Key('childKey');

    await tester.pumpWidget(Center(
      child: Container(
        width: 0.0,
        height: 0.0,
        child: Row(
          textDirection: TextDirection.ltr,
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              key: childKey,
              width: 100.0,
              height: 100.0,
            ),
          ],
        ),
      ),
    ));

    final RenderBox renderBox = tester.renderObject(find.byKey(childKey));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(0.0));
  });


  // RTL

  testWidgets('Row with one Flexible child - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // Default is MainAxisAlignment.start so children so the children's
    // right edges should be at 0, 100, 700 from the right, child2's width should be 600
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Expanded(child: Container(key: child1Key, width: 100.0, height: 100.0, child: log(2))),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(600.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with default main axis parameters - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // Default is MainAxisAlignment.start so children so the children's
    // right edges should be at 0, 100, 200 from the right
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(600.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(500.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.center - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's right edges should be at 300, 400 from the right
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.center,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(400.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(300.0));

    expect(OrderPainter.log, <int>[1, 2]);
  });

  testWidgets('Row with MainAxisAlignment.end - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's right edges should be at 500, 600, 700 from the right.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        textDirection: TextDirection.rtl,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(200.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.spaceBetween - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's right edges should be at 0, 350, 700 from the right
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(700.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(350.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row with MainAxisAlignment.spaceAround - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');
    const Key child3Key = Key('child3');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 100x100 children's right edges should be at 50, 250, 450, 650 from the right
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 100.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 100.0, height: 100.0, child: log(3)),
          Container(key: child3Key, width: 100.0, height: 100.0, child: log(4)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(650.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(450.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(250.0));

    renderBox = tester.renderObject(find.byKey(child3Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(50.0));

    expect(OrderPainter.log, <int>[1, 2, 3, 4]);
  });

  testWidgets('Row with MainAxisAlignment.spaceEvenly - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('row');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');
    const Key child2Key = Key('child2');

    // Default is MainAxisSize.max so the Row should be as wide as the test: 800.
    // The 200x100 children's right edges should be at 50, 300, 550 from the right
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 200.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 200.0, height: 100.0, child: log(2)),
          Container(key: child2Key, width: 200.0, height: 100.0, child: log(3)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(800.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(550.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(300.0));

    renderBox = tester.renderObject(find.byKey(child2Key));
    expect(renderBox.size.width, equals(200.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(50.0));

    expect(OrderPainter.log, <int>[1, 2, 3]);
  });

  testWidgets('Row and MainAxisSize.min - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key rowKey = Key('rowKey');
    const Key child0Key = Key('child0');
    const Key child1Key = Key('child1');

    // Row with MainAxisSize.min without flexible children shrink wraps.
    // Row's width should be 250, children should be at 0, 100 from right.
    await tester.pumpWidget(Center(
      child: Row(
        key: rowKey,
        mainAxisSize: MainAxisSize.min,
        textDirection: TextDirection.rtl,
        children: <Widget>[
          Container(key: child0Key, width: 100.0, height: 100.0, child: log(1)),
          Container(key: child1Key, width: 150.0, height: 100.0, child: log(2)),
        ],
      ),
    ));

    RenderBox renderBox;
    BoxParentData boxParentData;

    renderBox = tester.renderObject(find.byKey(rowKey));
    expect(renderBox.size.width, equals(250.0));
    expect(renderBox.size.height, equals(100.0));

    renderBox = tester.renderObject(find.byKey(child0Key));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(150.0));

    renderBox = tester.renderObject(find.byKey(child1Key));
    expect(renderBox.size.width, equals(150.0));
    expect(renderBox.size.height, equals(100.0));
    boxParentData = renderBox.parentData;
    expect(boxParentData.offset.dx, equals(0.0));

    expect(OrderPainter.log, <int>[1, 2]);
  });

  testWidgets('Row MainAxisSize.min layout at zero size - RTL', (WidgetTester tester) async {
    OrderPainter.log.clear();
    const Key childKey = Key('childKey');

    await tester.pumpWidget(Center(
      child: Container(
        width: 0.0,
        height: 0.0,
        child: Row(
          textDirection: TextDirection.rtl,
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              key: childKey,
              width: 100.0,
              height: 100.0,
            ),
          ],
        ),
      ),
    ));

    final RenderBox renderBox = tester.renderObject(find.byKey(childKey));
    expect(renderBox.size.width, equals(100.0));
    expect(renderBox.size.height, equals(0.0));
  });
}
