// Copyright 2014 The Flutter 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/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

import 'rendering_tester.dart';

class RenderLayoutTestBox extends RenderProxyBox {
  RenderLayoutTestBox(this.onLayout, {this.onPerformLayout});

  final VoidCallback onLayout;
  final VoidCallback? onPerformLayout;

  @override
  void layout(Constraints constraints, {bool parentUsesSize = false}) {
    // Doing this in tests is ok, but if you're writing your own
    // render object, you want to override performLayout(), not
    // layout(). Overriding layout() would remove many critical
    // performance optimizations of the rendering system, as well as
    // many bypassing many checked-mode integrity checks.
    super.layout(constraints, parentUsesSize: parentUsesSize);
    onLayout();
  }

  @override
  bool get sizedByParent => true;

  @override
  void performLayout() {
    child?.layout(constraints, parentUsesSize: true);
    onPerformLayout?.call();
  }
}

void main() {
  TestRenderingFlutterBinding.ensureInitialized();

  test('moving children', () {
    RenderBox child1, child2;
    var movedChild1 = false;
    var movedChild2 = false;
    final block = RenderFlex(textDirection: TextDirection.ltr);
    block.add(
      child1 = RenderLayoutTestBox(() {
        movedChild1 = true;
      }),
    );
    block.add(
      child2 = RenderLayoutTestBox(() {
        movedChild2 = true;
      }),
    );

    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);
    layout(block);
    expect(movedChild1, isTrue);
    expect(movedChild2, isTrue);

    movedChild1 = false;
    movedChild2 = false;

    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);
    pumpFrame();
    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);

    block.move(child1, after: child2);
    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);
    pumpFrame();
    expect(movedChild1, isTrue);
    expect(movedChild2, isTrue);

    movedChild1 = false;
    movedChild2 = false;

    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);
    pumpFrame();
    expect(movedChild1, isFalse);
    expect(movedChild2, isFalse);
  });

  group('Throws when illegal mutations are attempted: ', () {
    FlutterError catchLayoutError(RenderBox box) {
      Object? error;
      layout(
        box,
        onErrors: () {
          error = TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!.exception;
        },
      );
      expect(error, isFlutterError);
      return error! as FlutterError;
    }

    test('on disposed render objects', () {
      final RenderBox box = RenderLayoutTestBox(() {});
      box.dispose();

      Object? error;
      try {
        box.markNeedsLayout();
      } catch (e) {
        error = e;
      }

      expect(error, isFlutterError);
      expect(
        (error! as FlutterError).message,
        equalsIgnoringWhitespace(
          'A disposed RenderObject was mutated.\n'
          'The disposed RenderObject was:\n'
          '${box.toStringShort()}',
        ),
      );
    });

    test('marking itself dirty in performLayout', () {
      late RenderBox child1;
      final block = RenderFlex(textDirection: TextDirection.ltr);
      block.add(
        child1 = RenderLayoutTestBox(
          () {},
          onPerformLayout: () {
            child1.markNeedsLayout();
          },
        ),
      );

      expect(
        catchLayoutError(block).message,
        equalsIgnoringWhitespace(
          'A RenderLayoutTestBox was mutated in its own performLayout implementation.\n'
          'A RenderObject must not re-dirty itself while still being laid out.\n'
          'The RenderObject being mutated was:\n'
          '${child1.toStringShort()}\n'
          'Consider using the LayoutBuilder widget to dynamically change a subtree during layout.',
        ),
      );
    });

    test('marking a sibling dirty in performLayout', () {
      late RenderBox child1, child2;
      final block = RenderFlex(textDirection: TextDirection.ltr);
      block.add(child1 = RenderLayoutTestBox(() {}));
      block.add(
        child2 = RenderLayoutTestBox(
          () {},
          onPerformLayout: () {
            child1.markNeedsLayout();
          },
        ),
      );

      expect(
        catchLayoutError(block).message,
        equalsIgnoringWhitespace(
          'A RenderLayoutTestBox was mutated in RenderLayoutTestBox.performLayout.\n'
          'A RenderObject must not mutate another RenderObject from a different render subtree in its performLayout method.\n'
          'The RenderObject being mutated was:\n'
          '${child1.toStringShort()}\n'
          'The RenderObject that was mutating the said RenderLayoutTestBox was:\n'
          '${child2.toStringShort()}\n'
          'Their common ancestor was:\n'
          '${block.toStringShort()}\n'
          'Mutating the layout of another RenderObject may cause some RenderObjects in its subtree to be laid out more than once. Consider using the LayoutBuilder widget to dynamically mutate a subtree during layout.',
        ),
      );
    });

    test('marking a descendant dirty in performLayout', () {
      late RenderBox child1;
      final block = RenderFlex(textDirection: TextDirection.ltr);
      block.add(child1 = RenderLayoutTestBox(() {}));
      block.add(RenderLayoutTestBox(child1.markNeedsLayout));

      expect(
        catchLayoutError(block).message,
        equalsIgnoringWhitespace(
          'A RenderLayoutTestBox was mutated in RenderFlex.performLayout.\n'
          'A RenderObject must not mutate its descendants in its performLayout method.\n'
          'The RenderObject being mutated was:\n'
          '${child1.toStringShort()}\n'
          'The ancestor RenderObject that was mutating the said RenderLayoutTestBox was:\n'
          '${block.toStringShort()}\n'
          'Mutating the layout of another RenderObject may cause some RenderObjects in its subtree to be laid out more than once. Consider using the LayoutBuilder widget to dynamically mutate a subtree during layout.',
        ),
      );
    });

    test('marking an out-of-band mutation in performLayout', () {
      late RenderProxyBox child1, child11, child2, child21;
      final block = RenderFlex(textDirection: TextDirection.ltr);
      block.add(child1 = RenderLayoutTestBox(() {}));
      block.add(child2 = RenderLayoutTestBox(() {}));
      child1.child = child11 = RenderLayoutTestBox(() {});
      layout(block);

      expect(block.debugNeedsLayout, false);
      expect(child1.debugNeedsLayout, false);
      expect(child11.debugNeedsLayout, false);
      expect(child2.debugNeedsLayout, false);

      // Add a new child to child2 which is a relayout boundary.
      child2.child = child21 = RenderLayoutTestBox(() {}, onPerformLayout: child11.markNeedsLayout);

      FlutterError? error;
      pumpFrame(
        onErrors: () {
          error =
              TestRenderingFlutterBinding.instance.takeFlutterErrorDetails()!.exception
                  as FlutterError;
        },
      );

      expect(
        error?.message,
        equalsIgnoringWhitespace(
          'A RenderLayoutTestBox was mutated in RenderLayoutTestBox.performLayout.\n'
          'The RenderObject was mutated when none of its ancestors is actively performing layout.\n'
          'The RenderObject being mutated was:\n'
          '${child11.toStringShort()}\n'
          'The RenderObject that was mutating the said RenderLayoutTestBox was:\n'
          '${child21.toStringShort()}',
        ),
      );
    });
  });
}
