// 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/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';

import 'semantics_tester.dart';

void main() {
  test('OverlayEntry dispatches memory events', () async {
    await expectLater(
      await memoryEvents(
        () => OverlayEntry(
              builder: (BuildContext context) => Container(),
            ).dispose(),
        OverlayEntry,
      ),
      areCreateAndDispose,
    );
  });

  testWidgets('OverflowEntries context contains Overlay', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    bool didBuild = false;
    late final OverlayEntry overlayEntry1;
    addTearDown(() => overlayEntry1..remove()..dispose());
    late final OverlayEntry overlayEntry2;
    addTearDown(() => overlayEntry2..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            overlayEntry1 = OverlayEntry(
              builder: (BuildContext context) {
                didBuild = true;
                final Overlay overlay = context.findAncestorWidgetOfExactType<Overlay>()!;
                expect(overlay.key, equals(overlayKey));
                return Container();
              },
            ),
            overlayEntry2 = OverlayEntry(
              builder: (BuildContext context) => Container(),
            ),
          ],
        ),
      ),
    );
    expect(didBuild, isTrue);
    final RenderObject theater = overlayKey.currentContext!.findRenderObject()!;

    expect(theater, hasAGoodToStringDeep);
    expect(
      theater.toStringDeep(minLevel: DiagnosticLevel.info),
      equalsIgnoringHashCodes(
        '_RenderTheater#744c9\n'
        ' │ parentData: <none>\n'
        ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' │ size: Size(800.0, 600.0)\n'
        ' │ skipCount: 0\n'
        ' │ textDirection: ltr\n'
        ' │\n'
        ' ├─onstage 1: RenderLimitedBox#bb803\n'
        ' │ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use\n'
        ' │ │   size)\n'
        ' │ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' │ │ size: Size(800.0, 600.0)\n'
        ' │ │ maxWidth: 0.0\n'
        ' │ │ maxHeight: 0.0\n'
        ' │ │\n'
        ' │ └─child: RenderConstrainedBox#62707\n'
        ' │     parentData: <none> (can use size)\n'
        ' │     constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' │     size: Size(800.0, 600.0)\n'
        ' │     additionalConstraints: BoxConstraints(biggest)\n'
        ' │\n'
        ' ├─onstage 2: RenderLimitedBox#af5f1\n'
        ' ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use\n'
        ' ╎ │   size)\n'
        ' ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' ╎ │ size: Size(800.0, 600.0)\n'
        ' ╎ │ maxWidth: 0.0\n'
        ' ╎ │ maxHeight: 0.0\n'
        ' ╎ │\n'
        ' ╎ └─child: RenderConstrainedBox#69c48\n'
        ' ╎     parentData: <none> (can use size)\n'
        ' ╎     constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' ╎     size: Size(800.0, 600.0)\n'
        ' ╎     additionalConstraints: BoxConstraints(biggest)\n'
        ' ╎\n'
        ' └╌no offstage children\n',
      ),
    );
  });

  testWidgets('Offstage overlay', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    late final OverlayEntry overlayEntry1;
    addTearDown(() => overlayEntry1..remove()..dispose());
    late final OverlayEntry overlayEntry2;
    addTearDown(() => overlayEntry2..remove()..dispose());
    late final OverlayEntry overlayEntry3;
    addTearDown(() => overlayEntry3..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            overlayEntry1 = OverlayEntry(
              opaque: true,
              maintainState: true,
              builder: (BuildContext context) => Container(),
            ),
            overlayEntry2 = OverlayEntry(
              opaque: true,
              maintainState: true,
              builder: (BuildContext context) => Container(),
            ),
            overlayEntry3 = OverlayEntry(
              opaque: true,
              maintainState: true,
              builder: (BuildContext context) => Container(),
            ),
          ],
        ),
      ),
    );
    final RenderObject theater = overlayKey.currentContext!.findRenderObject()!;

    expect(theater, hasAGoodToStringDeep);
    expect(
      theater.toStringDeep(minLevel: DiagnosticLevel.info),
      equalsIgnoringHashCodes(
        '_RenderTheater#385b3\n'
        ' │ parentData: <none>\n'
        ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' │ size: Size(800.0, 600.0)\n'
        ' │ skipCount: 2\n'
        ' │ textDirection: ltr\n'
        ' │\n'
        ' ├─onstage 1: RenderLimitedBox#0a77a\n'
        ' ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0) (can use\n'
        ' ╎ │   size)\n'
        ' ╎ │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' ╎ │ size: Size(800.0, 600.0)\n'
        ' ╎ │ maxWidth: 0.0\n'
        ' ╎ │ maxHeight: 0.0\n'
        ' ╎ │\n'
        ' ╎ └─child: RenderConstrainedBox#21f3a\n'
        ' ╎     parentData: <none> (can use size)\n'
        ' ╎     constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' ╎     size: Size(800.0, 600.0)\n'
        ' ╎     additionalConstraints: BoxConstraints(biggest)\n'
        ' ╎\n'
        ' ╎╌offstage 1: RenderLimitedBox#62c8c NEEDS-LAYOUT NEEDS-PAINT\n'
        ' ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)\n'
        ' ╎ │ constraints: MISSING\n'
        ' ╎ │ size: MISSING\n'
        ' ╎ │ maxWidth: 0.0\n'
        ' ╎ │ maxHeight: 0.0\n'
        ' ╎ │\n'
        ' ╎ └─child: RenderConstrainedBox#425fa NEEDS-LAYOUT NEEDS-PAINT\n'
        ' ╎     parentData: <none>\n'
        ' ╎     constraints: MISSING\n'
        ' ╎     size: MISSING\n'
        ' ╎     additionalConstraints: BoxConstraints(biggest)\n'
        ' ╎\n'
        ' └╌offstage 2: RenderLimitedBox#03ae2 NEEDS-LAYOUT NEEDS-PAINT\n'
        '   │ parentData: not positioned; offset=Offset(0.0, 0.0)\n'
        '   │ constraints: MISSING\n'
        '   │ size: MISSING\n'
        '   │ maxWidth: 0.0\n'
        '   │ maxHeight: 0.0\n'
        '   │\n'
        '   └─child: RenderConstrainedBox#b4d48 NEEDS-LAYOUT NEEDS-PAINT\n'
        '       parentData: <none>\n'
        '       constraints: MISSING\n'
        '       size: MISSING\n'
        '       additionalConstraints: BoxConstraints(biggest)\n',
      ),
    );
  });

  testWidgets('insert top', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<String> buildOrder = <String>[];
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base']);

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    overlay.insert(
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New');
          return Container();
        },
      ),
    );
    await tester.pump();

    expect(buildOrder, <String>['Base', 'New']);
  });

  testWidgets('insert below', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());
    final List<String> buildOrder = <String>[];

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base']);

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    overlay.insert(
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New');
          return Container();
        },
      ),
      below: baseEntry,
    );
    await tester.pump();

    expect(buildOrder, <String>['New', 'Base']);
  });

  testWidgets('insert above', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());
    late final OverlayEntry topEntry;
    addTearDown(() => topEntry..remove()..dispose());
    final List<String> buildOrder = <String>[];

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
            topEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Top');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base', 'Top']);

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    overlay.insert(
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New');
          return Container();
        },
      ),
      above: baseEntry,
    );
    await tester.pump();

    expect(buildOrder, <String>['Base', 'New', 'Top']);
  });

  testWidgets('insertAll top', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<String> buildOrder = <String>[];
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base']);

    final List<OverlayEntry> entries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New1');
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New2');
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in entries) {
        entry..remove()..dispose();
      }
    });

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.insertAll(entries);
    await tester.pump();

    expect(buildOrder, <String>['Base', 'New1', 'New2']);
  });

  testWidgets('insertAll below', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());
    final List<String> buildOrder = <String>[];

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base']);

    final List<OverlayEntry> entries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New1');
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New2');
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in entries) {
        entry..remove()..dispose();
      }
    });

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.insertAll(entries, below: baseEntry);
    await tester.pump();

    expect(buildOrder, <String>['New1', 'New2','Base']);
  });

  testWidgets('insertAll above', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<String> buildOrder = <String>[];
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());
    late final OverlayEntry topEntry;
    addTearDown(() => topEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Base');
                return Container();
              },
            ),
            topEntry = OverlayEntry(
              builder: (BuildContext context) {
                buildOrder.add('Top');
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(buildOrder, <String>['Base', 'Top']);

    final List<OverlayEntry> entries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New1');
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add('New2');
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in entries) {
        entry..remove()..dispose();
      }
    });

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.insertAll(entries, above: baseEntry);
    await tester.pump();

    expect(buildOrder, <String>['Base', 'New1', 'New2', 'Top']);
  });

  testWidgets('rearrange', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<int> buildOrder = <int>[];
    final List<OverlayEntry> initialEntries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(0);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(1);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(2);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(3);
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in initialEntries) {
        entry..remove()..dispose();
      }
    });

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: initialEntries,
        ),
      ),
    );

    expect(buildOrder, <int>[0, 1, 2, 3]);

    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    final List<OverlayEntry> rearranged = <OverlayEntry>[
      initialEntries[3],
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(4);
          return Container();
        },
      ),
      initialEntries[2],
      // 1 intentionally missing, will end up on top
      initialEntries[0],
    ];

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.rearrange(rearranged);
    await tester.pump();

    expect(buildOrder, <int>[3, 4, 2, 0, 1]);
  });

  testWidgets('rearrange above', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<int> buildOrder = <int>[];

    final List<OverlayEntry> initialEntries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(0);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(1);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(2);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(3);
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in initialEntries) {
        entry..remove()..dispose();
      }
    });

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: initialEntries,
        ),
      ),
    );

    expect(buildOrder, <int>[0, 1, 2, 3]);

    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    final List<OverlayEntry> rearranged = <OverlayEntry>[
      initialEntries[3],
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(4);
          return Container();
        },
      ),
      initialEntries[2],
      // 1 intentionally missing
      initialEntries[0],
    ];

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.rearrange(rearranged, above: initialEntries[2]);
    await tester.pump();

    expect(buildOrder, <int>[3, 4, 2, 1, 0]);
  });

  testWidgets('rearrange below', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    final List<int> buildOrder = <int>[];
    final List<OverlayEntry> initialEntries = <OverlayEntry>[
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(0);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(1);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(2);
          return Container();
        },
      ),
      OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(3);
          return Container();
        },
      ),
    ];
    addTearDown(() {
      for (final OverlayEntry entry in initialEntries) {
        entry..remove()..dispose();
      }
    });

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: initialEntries,
        ),
      ),
    );

    expect(buildOrder, <int>[0, 1, 2, 3]);

    late final OverlayEntry newEntry;
    addTearDown(() => newEntry..remove()..dispose());
    final List<OverlayEntry> rearranged = <OverlayEntry>[
      initialEntries[3],
      newEntry = OverlayEntry(
        builder: (BuildContext context) {
          buildOrder.add(4);
          return Container();
        },
      ),
      initialEntries[2],
      // 1 intentionally missing
      initialEntries[0],
    ];

    buildOrder.clear();
    final OverlayState overlay = overlayKey.currentState! as OverlayState;
    overlay.rearrange(rearranged, below: initialEntries[2]);
    await tester.pump();

    expect(buildOrder, <int>[3, 4, 1, 2, 0]);
  });

  testWidgets('debugVerifyInsertPosition', (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    late OverlayEntry base;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            base = _buildOverlayEntry((BuildContext context) {
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    final OverlayState overlay = overlayKey.currentState! as OverlayState;

    try {
      overlay.insert(
        _buildOverlayEntry((BuildContext context) {
          return Container();
        }),
        above: _buildOverlayEntry((BuildContext context) {
            return Container();
          },
        ),
        below: _buildOverlayEntry((BuildContext context) {
            return Container();
          },
        ),
      );
    } on AssertionError catch (e) {
      expect(e.message, 'Only one of `above` and `below` may be specified.');
    }

    expect(() => overlay.insert(
      _buildOverlayEntry((BuildContext context) {
        return Container();
      }),
      above: base,
    ), isNot(throwsAssertionError));

    try {
      overlay.insert(
        _buildOverlayEntry((BuildContext context) {
          return Container();
        }),
        above: _buildOverlayEntry((BuildContext context) {
            return Container();
          },
        ),
      );
    } on AssertionError catch (e) {
      expect(e.message, 'The provided entry used for `above` must be present in the Overlay.');
    }

    try {
      overlay.rearrange(<OverlayEntry>[base], above: _buildOverlayEntry((BuildContext context) {
          return Container();
        },
      ));

    } on AssertionError catch (e) {
      expect(e.message, 'The provided entry used for `above` must be present in the Overlay and in the `newEntriesList`.');
    }

    await tester.pump();
  });

  testWidgets('OverlayState.of() throws when called if an Overlay does not exist', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Builder(
          builder: (BuildContext context) {
            late FlutterError error;
            final Widget debugRequiredFor = Container();
            try {
              Overlay.of(context, debugRequiredFor: debugRequiredFor);
            } on FlutterError catch (e) {
              error = e;
            } finally {
              expect(error, isNotNull);
              expect(error.diagnostics.length, 5);
              expect(error.diagnostics[2].level, DiagnosticLevel.hint);
              expect(error.diagnostics[2].toStringDeep(), equalsIgnoringHashCodes(
                'The most common way to add an Overlay to an application is to\n'
                'include a MaterialApp, CupertinoApp or Navigator widget in the\n'
                'runApp() call.\n'
              ));
              expect(error.diagnostics[3], isA<DiagnosticsProperty<Widget>>());
              expect(error.diagnostics[3].value, debugRequiredFor);
              expect(error.diagnostics[4], isA<DiagnosticsProperty<Element>>());
              expect(error.toStringDeep(), equalsIgnoringHashCodes(
                'FlutterError\n'
                '   No Overlay widget found.\n'
                '   Container widgets require an Overlay widget ancestor for correct\n'
                '   operation.\n'
                '   The most common way to add an Overlay to an application is to\n'
                '   include a MaterialApp, CupertinoApp or Navigator widget in the\n'
                '   runApp() call.\n'
                '   The specific widget that failed to find an overlay was:\n'
                '     Container\n'
                '   The context from which that widget was searching for an overlay\n'
                '   was:\n'
                '     Builder\n'
              ));
            }
            return Container();
          },
        ),
      ),
    );
  });

  testWidgets("OverlayState.maybeOf() works when an Overlay does and doesn't exist", (WidgetTester tester) async {
    final GlobalKey overlayKey = GlobalKey();
    OverlayState? foundState;
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                foundState = Overlay.maybeOf(context);
                return Container();
              },
            ),
          ],
        ),
      ),
    );

    expect(tester.takeException(), isNull);
    expect(foundState, isNotNull);
    foundState = null;

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Builder(
          builder: (BuildContext context) {
            foundState = Overlay.maybeOf(context);
            return const SizedBox();
          },
        ),
      ),
    );

    expect(tester.takeException(), isNull);
    expect(foundState, isNull);
  });

  testWidgets('OverlayEntry.opaque can be changed when OverlayEntry is not part of an Overlay (yet)', (WidgetTester tester) async {
    final GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
    final Key root = UniqueKey();
    final Key top = UniqueKey();
    final OverlayEntry rootEntry = OverlayEntry(
      builder: (BuildContext context) {
        return Container(key: root);
      },
    );
    addTearDown(() => rootEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            rootEntry,
          ],
        ),
      ),
    );

    expect(find.byKey(root), findsOneWidget);

    final OverlayEntry newEntry = OverlayEntry(
      builder: (BuildContext context) {
        return Container(key: top);
      },
    );
    addTearDown(() => newEntry..remove()..dispose());
    expect(newEntry.opaque, isFalse);
    newEntry.opaque = true; // Does neither trigger an assert nor throw.
    expect(newEntry.opaque, isTrue);

    // The new opaqueness is honored when inserted into an overlay.
    overlayKey.currentState!.insert(newEntry);
    await tester.pumpAndSettle();

    expect(find.byKey(root), findsNothing);
    expect(find.byKey(top), findsOneWidget);
  });

  testWidgets('OverlayEntries do not rebuild when opaqueness changes', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/45797.

    final GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
    final Key bottom = UniqueKey();
    final Key middle = UniqueKey();
    final Key top = UniqueKey();
    final Widget bottomWidget = StatefulTestWidget(key: bottom);
    final Widget middleWidget = StatefulTestWidget(key: middle);
    final Widget topWidget = StatefulTestWidget(key: top);

    final OverlayEntry bottomEntry = OverlayEntry(
      maintainState: true,
      builder: (BuildContext context) {
        return bottomWidget;
      },
    );
    addTearDown(() => bottomEntry..remove()..dispose());
    final OverlayEntry middleEntry = OverlayEntry(
      maintainState: true,
      builder: (BuildContext context) {
        return middleWidget;
      },
    );
    addTearDown(() => middleEntry..remove()..dispose());
    final OverlayEntry topEntry = OverlayEntry(
      maintainState: true,
      builder: (BuildContext context) {
        return topWidget;
      },
    );
    addTearDown(() => topEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            bottomEntry,
            middleEntry,
            topEntry,
          ],
        ),
      ),
    );

    // All widgets are onstage.
    expect(tester.state<StatefulTestState>(find.byKey(bottom)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(middle)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(top)).rebuildCount, 1);

    middleEntry.opaque = true;
    await tester.pump();

    // Bottom widget is offstage and did not rebuild.
    expect(find.byKey(bottom), findsNothing);
    expect(tester.state<StatefulTestState>(find.byKey(bottom, skipOffstage: false)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(middle)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(top)).rebuildCount, 1);
  });

  testWidgets('OverlayEntries do not rebuild when opaque entry is added', (WidgetTester tester) async {
    // Regression test for https://github.com/flutter/flutter/issues/45797.

    final GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
    final Key bottom = UniqueKey();
    final Key middle = UniqueKey();
    final Key top = UniqueKey();
    final Widget bottomWidget = StatefulTestWidget(key: bottom);
    final Widget middleWidget = StatefulTestWidget(key: middle);
    final Widget topWidget = StatefulTestWidget(key: top);

    final OverlayEntry bottomEntry = OverlayEntry(
      maintainState: true,
      builder: (BuildContext context) {
        return bottomWidget;
      },
    );
    addTearDown(() => bottomEntry..remove()..dispose());
    final OverlayEntry middleEntry = OverlayEntry(
      opaque: true,
      maintainState: true,
      builder: (BuildContext context) {
        return middleWidget;
      },
    );
    addTearDown(() => middleEntry..remove()..dispose());
    final OverlayEntry topEntry = OverlayEntry(
      maintainState: true,
      builder: (BuildContext context) {
        return topWidget;
      },
    );
    addTearDown(() => topEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            bottomEntry,
            topEntry,
          ],
        ),
      ),
    );

    // Both widgets are onstage.
    expect(tester.state<StatefulTestState>(find.byKey(bottom)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(top)).rebuildCount, 1);

    overlayKey.currentState!.rearrange(<OverlayEntry>[
      bottomEntry, middleEntry, topEntry,
    ]);
    await tester.pump();

    // Bottom widget is offstage and did not rebuild.
    expect(find.byKey(bottom), findsNothing);
    expect(tester.state<StatefulTestState>(find.byKey(bottom, skipOffstage: false)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(middle)).rebuildCount, 1);
    expect(tester.state<StatefulTestState>(find.byKey(top)).rebuildCount, 1);
  });

  testWidgets('entries below opaque entries are ignored for hit testing', (WidgetTester tester) async {
    final GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
    int bottomTapCount = 0;
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              maintainState: true,
              builder: (BuildContext context) {
                return GestureDetector(
                  onTap: () {
                    bottomTapCount++;
                  },
                );
              },
            ),
          ],
        ),
      ),
    );

    expect(bottomTapCount, 0);
    await tester.tap(find.byKey(overlayKey), warnIfMissed: false); // gesture detector is translucent; no hit is registered between it and the render view
    expect(bottomTapCount, 1);

    late final OverlayEntry newEntry1;
    addTearDown(() => newEntry1..remove()..dispose());
    overlayKey.currentState!.insert(
      newEntry1 = OverlayEntry(
        maintainState: true,
        opaque: true,
        builder: (BuildContext context) {
          return Container();
        },
      ),
    );
    await tester.pump();

    // Bottom is offstage and does not receive tap events.
    expect(find.byType(GestureDetector), findsNothing);
    expect(find.byType(GestureDetector, skipOffstage: false), findsOneWidget);
    await tester.tap(find.byKey(overlayKey), warnIfMissed: false); // gesture detector is translucent; no hit is registered between it and the render view
    expect(bottomTapCount, 1);

    int topTapCount = 0;
    late final OverlayEntry newEntry2;
    addTearDown(() => newEntry2..remove()..dispose());
    overlayKey.currentState!.insert(
      newEntry2 = OverlayEntry(
        maintainState: true,
        opaque: true,
        builder: (BuildContext context) {
          return GestureDetector(
            onTap: () {
              topTapCount++;
            },
          );
        },
      ),
    );
    await tester.pump();

    expect(topTapCount, 0);
    await tester.tap(find.byKey(overlayKey), warnIfMissed: false); // gesture detector is translucent; no hit is registered between it and the render view
    expect(topTapCount, 1);
    expect(bottomTapCount, 1);
  });

  testWidgets('Semantics of entries below opaque entries are ignored', (WidgetTester tester) async {
    final SemanticsTester semantics = SemanticsTester(tester);
    final GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
    late final OverlayEntry bottomEntry;
    addTearDown(() => bottomEntry..remove()..dispose());
    late final OverlayEntry topEntry;
    addTearDown(() => topEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          key: overlayKey,
          initialEntries: <OverlayEntry>[
            bottomEntry = OverlayEntry(
              maintainState: true,
              builder: (BuildContext context) {
                return const Text('bottom');
              },
            ),
            topEntry = OverlayEntry(
              maintainState: true,
              opaque: true,
              builder: (BuildContext context) {
                return const Text('top');
              },
            ),
          ],
        ),
      ),
    );
    expect(find.text('bottom'), findsNothing);
    expect(find.text('bottom', skipOffstage: false), findsOneWidget);
    expect(find.text('top'), findsOneWidget);
    expect(semantics, includesNodeWith(label: 'top'));
    expect(semantics, isNot(includesNodeWith(label: 'bottom')));

    semantics.dispose();
  });

  testWidgets('Can use Positioned within OverlayEntry', (WidgetTester tester) async {
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) {
                return const Positioned(
                  left: 145,
                  top: 123,
                  child: Text('positioned child'),
                );
              },
            ),
          ],
        ),
      ),
    );

    expect(tester.getTopLeft(find.text('positioned child')), const Offset(145, 123));
  });

  testWidgets('Overlay can set and update clipBehavior', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          initialEntries: <OverlayEntry>[
            _buildOverlayEntry((BuildContext context) => Positioned(left: 2000, right: 2500, child: Container())),
          ],
        ),
      ),
    );

    // By default, clipBehavior should be Clip.hardEdge
    final RenderObject renderObject = tester.renderObject(find.byType(Overlay));
    expect((renderObject as dynamic).clipBehavior, equals(Clip.hardEdge));

    for (final Clip clip in Clip.values) {
      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Overlay(
            initialEntries: <OverlayEntry>[
              _buildOverlayEntry((BuildContext context) => Container()),
            ],
            clipBehavior: clip,
          ),
        ),
      );

      expect((renderObject as dynamic).clipBehavior, clip);
      bool visited = false;
      renderObject.visitChildren((RenderObject child) {
        visited = true;
        switch (clip) {
          case Clip.none:
            expect(renderObject.describeApproximatePaintClip(child), null);
          case Clip.hardEdge:
          case Clip.antiAlias:
          case Clip.antiAliasWithSaveLayer:
            expect(
              renderObject.describeApproximatePaintClip(child),
              const Rect.fromLTRB(0, 0, 800, 600),
            );
        }
      });
      expect(visited, true);
    }
  });

  testWidgets('Overlay always applies clip', (WidgetTester tester) async {
    late final OverlayEntry baseEntry;
    addTearDown(() => baseEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(
          initialEntries: <OverlayEntry>[
            baseEntry = OverlayEntry(
              builder: (BuildContext context) => Positioned(left: 10, right: 10, child: Container()),
            ),
          ],
        ),
      ),
    );
    final RenderObject renderObject = tester.renderObject(find.byType(Overlay));
    expect((renderObject as dynamic).paint, paints
      ..save()
      ..clipRect(rect: const Rect.fromLTWH(0.0, 0.0, 800.0, 600.0))
      ..restore(),
    );
  });

  testWidgets('OverlayEntry throws if inserted to an invalid Overlay', (WidgetTester tester) async {
    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay(),
      ),
    );
    final OverlayState overlay = tester.state(find.byType(Overlay));
    final OverlayEntry entry = OverlayEntry(builder: (BuildContext context) => const SizedBox());
    addTearDown(() => entry..remove()..dispose());
    expect(
      () => overlay.insert(entry),
      returnsNormally,
    );

    // Throws when inserted to the same Overlay.
    expect(
      () => overlay.insert(entry),
      throwsA(isA<FlutterError>().having(
        (FlutterError error) => error.toString(),
        'toString()',
        allOf(
          contains('The specified entry is already present in the target Overlay.'),
          contains('The OverlayEntry was'),
          contains('The Overlay the OverlayEntry was trying to insert to was'),
        ),
      )),
    );

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: SizedBox(child: Overlay()),
      ),
    );

    // Throws if inserted to an already disposed Overlay.
    expect(
      () => overlay.insert(entry),
      throwsA(isA<FlutterError>().having(
        (FlutterError error) => error.toString(),
        'toString()',
        allOf(
          contains('Attempted to insert an OverlayEntry to an already disposed Overlay.'),
          contains('The OverlayEntry was'),
          contains('The Overlay the OverlayEntry was trying to insert to was'),
        ),
      )),
    );

    final OverlayState newOverlay = tester.state(find.byType(Overlay));
    // Throws when inserted to a different Overlay without calling remove.
    expect(
      () => newOverlay.insert(entry),
      throwsA(isA<FlutterError>().having(
        (FlutterError error) => error.toString(),
        'toString()',
        allOf(
          contains('The specified entry is already present in a different Overlay.'),
          contains('The OverlayEntry was'),
          contains('The Overlay the OverlayEntry was trying to insert to was'),
          contains("The OverlayEntry's current Overlay was"),
        ),
      )),
    );
  });

  group('OverlayEntry listenable', () {
    final GlobalKey overlayKey = GlobalKey();
    final Widget emptyOverlay = Directionality(
      textDirection: TextDirection.ltr,
      child: Overlay(key: overlayKey),
    );

    testWidgets('mounted state can be listened', (WidgetTester tester) async {
      await tester.pumpWidget(emptyOverlay);
      final OverlayState overlay = overlayKey.currentState! as OverlayState;
      final List<bool> mountedLog = <bool>[];
      final OverlayEntry entry = OverlayEntry(
        builder: (BuildContext context) => Container(),
      );
      addTearDown(entry.dispose);

      entry.addListener(() {
        mountedLog.add(entry.mounted);
      });

      overlay.insert(entry);
      expect(mountedLog, isEmpty);

      // Pump a frame. The Overlay entry will be mounted.
      await tester.pump();
      expect(mountedLog, <bool>[true]);

      entry.remove();
      expect(mountedLog, <bool>[true]);
      await tester.pump();
      expect(mountedLog, <bool>[true, false]);

      // Insert & remove again.
      overlay.insert(entry);
      await tester.pump();
      entry.remove();
      await tester.pump();

      expect(mountedLog, <bool>[true, false, true, false]);
    });

    testWidgets('throw if disposed before removal', (WidgetTester tester) async {
      await tester.pumpWidget(emptyOverlay);
      final OverlayState overlay = overlayKey.currentState! as OverlayState;
      final OverlayEntry entry = OverlayEntry(
        builder: (BuildContext context) => Container(),
      );
      addTearDown(() => entry..remove()..dispose());

      overlay.insert(entry);
      Object? error;
      try {
        entry.dispose();
      } catch (e) {
        error = e;
      }

      expect(error, isAssertionError);
    });

    test('dispose works', () {
      final OverlayEntry entry = OverlayEntry(
        builder: (BuildContext context) => Container(),
      );

      entry.dispose();

      Object? error;
      try {
        entry.addListener(() {  });
      } catch (e) {
        error = e;
      }
      expect(error, isAssertionError);
    });

    testWidgets('delayed dispose', (WidgetTester tester) async {
      await tester.pumpWidget(emptyOverlay);
      final OverlayState overlay = overlayKey.currentState! as OverlayState;
      final List<bool> mountedLog = <bool>[];
      final OverlayEntry entry = OverlayEntry(
        builder: (BuildContext context) => Container(),
      );
      entry.addListener(() {
        mountedLog.add(entry.mounted);
      });

      overlay.insert(entry);
      await tester.pump();
      expect(mountedLog, <bool>[true]);

      entry.remove();
      // Call dispose on the entry. The listeners should be notified for one
      // last time after this.
      entry.dispose();
      expect(mountedLog, <bool>[true]);
      await tester.pump();
      expect(mountedLog, <bool>[true, false]);
      expect(tester.takeException(), isNull);

      // The entry is no longer usable.
      Object? error;
      try {
        entry.addListener(() {  });
      } catch (e) {
        error = e;
      }
      expect(error, isAssertionError);
    });
  });

  group('LookupBoundary', () {
    testWidgets('hides Overlay from Overlay.maybeOf', (WidgetTester tester) async {
      OverlayState? overlay;
      late final OverlayEntry baseEntry;
      addTearDown(() => baseEntry..remove()..dispose());

      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Overlay(
            initialEntries: <OverlayEntry>[
              baseEntry = OverlayEntry(
                builder: (BuildContext context) {
                  return LookupBoundary(
                    child: Builder(
                      builder: (BuildContext context) {
                        overlay = Overlay.maybeOf(context);
                        return Container();
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );

      expect(overlay, isNull);
    });

    testWidgets('hides Overlay from Overlay.of', (WidgetTester tester) async {
      late final OverlayEntry baseEntry;
      addTearDown(() => baseEntry..remove()..dispose());

      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Overlay(
            initialEntries: <OverlayEntry>[
              baseEntry = OverlayEntry(
                builder: (BuildContext context) {
                  return LookupBoundary(
                    child: Builder(
                      builder: (BuildContext context) {
                        Overlay.of(context);
                        return Container();
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );
      final Object? exception = tester.takeException();
      expect(exception, isFlutterError);
      final FlutterError error = exception! as FlutterError;

      expect(
        error.toStringDeep(),
        'FlutterError\n'
        '   No Overlay widget found within the closest LookupBoundary.\n'
        '   There is an ancestor Overlay widget, but it is hidden by a\n'
        '   LookupBoundary.\n'
        '   Some widgets require an Overlay widget ancestor for correct\n'
        '   operation.\n'
        '   The most common way to add an Overlay to an application is to\n'
        '   include a MaterialApp, CupertinoApp or Navigator widget in the\n'
        '   runApp() call.\n'
        '   The context from which that widget was searching for an overlay\n'
        '   was:\n'
        '     Builder\n'
      );
    });

    testWidgets('hides Overlay from debugCheckHasOverlay', (WidgetTester tester) async {
      late final OverlayEntry baseEntry;
      addTearDown(() => baseEntry..remove()..dispose());

      await tester.pumpWidget(
        Directionality(
          textDirection: TextDirection.ltr,
          child: Overlay(
            initialEntries: <OverlayEntry>[
              baseEntry = OverlayEntry(
                builder: (BuildContext context) {
                  return LookupBoundary(
                    child: Builder(
                      builder: (BuildContext context) {
                        debugCheckHasOverlay(context);
                        return Container();
                      },
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );
      final Object? exception = tester.takeException();
      expect(exception, isFlutterError);
      final FlutterError error = exception! as FlutterError;

      expect(
        error.toStringDeep(), startsWith(
          'FlutterError\n'
          '   No Overlay widget found within the closest LookupBoundary.\n'
          '   There is an ancestor Overlay widget, but it is hidden by a\n'
          '   LookupBoundary.\n'
          '   Builder widgets require an Overlay widget ancestor within the\n'
          '   closest LookupBoundary.\n'
          '   An overlay lets widgets float on top of other widget children.\n'
          '   To introduce an Overlay widget, you can either directly include\n'
          '   one, or use a widget that contains an Overlay itself, such as a\n'
          '   Navigator, WidgetApp, MaterialApp, or CupertinoApp.\n'
          '   The specific widget that could not find a Overlay ancestor was:\n'
          '     Builder\n'
          '   The ancestors of this widget were:\n'
          '     LookupBoundary\n'
        ),
      );
    });
  });

  testWidgets('Overlay.wrap', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay.wrap(
          child: const Center(
            child: Text('Hello World'),
          ),
        ),
      ),
    );

    final State overlayState = tester.state(find.byType(Overlay));
    expect(find.text('Hello World'), findsOneWidget);
    expect(find.text('Bye, bye'), findsNothing);

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Overlay.wrap(
          child: const Center(
            child: Text('Bye, bye'),
          ),
        ),
      ),
    );

    expect(find.text('Hello World'), findsNothing);
    expect(find.text('Bye, bye'), findsOneWidget);
    expect(tester.state(find.byType(Overlay)), same(overlayState));
  });

  testWidgets('Overlay.wrap is sized by child in an unconstrained environment', (WidgetTester tester) async {
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnconstrainedBox(
          child: Overlay.wrap(
            child: const Center(
              child: SizedBox(
                width: 123,
                height: 456,
              )
            ),
          ),
        ),
      ),
    );

    expect(tester.getSize(find.byType(Overlay)), const Size(123, 456));
  });

  testWidgets('Overlay is sized by child in an unconstrained environment', (WidgetTester tester) async {
    final OverlayEntry initialEntry = OverlayEntry(
      opaque: true,
      canSizeOverlay: true,
      builder: (BuildContext context) {
        return const SizedBox(width: 123, height: 456);
      }
    );
    addTearDown(() => initialEntry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnconstrainedBox(
          child: Overlay(
            initialEntries: <OverlayEntry>[initialEntry]
          ),
        ),
      ),
    );

    expect(tester.getSize(find.byType(Overlay)), const Size(123, 456));

    final OverlayState overlay = tester.state<OverlayState>(find.byType(Overlay));

    final OverlayEntry nonSizingEntry = OverlayEntry(
      builder: (BuildContext context) {
        return const SizedBox(
          width: 600,
          height: 600,
          child: Center(child: Text('Hello')),
        );
      },
    );
    addTearDown(nonSizingEntry.dispose);

    overlay.insert(nonSizingEntry);
    await tester.pump();
    expect(tester.getSize(find.byType(Overlay)), const Size(123, 456));
    expect(find.text('Hello'), findsOneWidget);

    final OverlayEntry sizingEntry = OverlayEntry(
      canSizeOverlay: true,
      builder: (BuildContext context) {
        return const SizedBox(
          width: 222,
          height: 111,
          child: Center(child: Text('World')),
        );
      },
    );
    addTearDown(sizingEntry.dispose);

    overlay.insert(sizingEntry);
    await tester.pump();
    expect(tester.getSize(find.byType(Overlay)), const Size(222, 111));
    expect(find.text('Hello'), findsOneWidget);
    expect(find.text('World'), findsOneWidget);

    nonSizingEntry.remove();
    await tester.pump();
    expect(tester.getSize(find.byType(Overlay)), const Size(222, 111));
    expect(find.text('Hello'), findsNothing);
    expect(find.text('World'), findsOneWidget);

    sizingEntry.remove();
    await tester.pump();
    expect(tester.getSize(find.byType(Overlay)), const Size(123, 456));
    expect(find.text('Hello'), findsNothing);
    expect(find.text('World'), findsNothing);
  });

  testWidgets('Overlay throws if unconstrained and has no child', (WidgetTester tester) async {
    final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[];
    final FlutterExceptionHandler? oldHandler = FlutterError.onError;
    FlutterError.onError = errors.add;

    await tester.pumpWidget(
      const Directionality(
        textDirection: TextDirection.ltr,
        child: UnconstrainedBox(
          child: Overlay(),
        ),
      ),
    );
    FlutterError.onError = oldHandler;

    expect(
      errors.first.toString().replaceAll('\n', ' '),
      contains('Overlay was given infinite constraints and cannot be sized by a suitable child.'),
    );
  });

  testWidgets('Overlay throws if unconstrained and only positioned child', (WidgetTester tester) async {
    final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[];
    final FlutterExceptionHandler? oldHandler = FlutterError.onError;
    FlutterError.onError = errors.add;

    final OverlayEntry entry = OverlayEntry(
      canSizeOverlay: true,
      builder: (BuildContext context) {
        return const Positioned(
          top: 100,
          child: SizedBox(width: 600, height: 600),
        );
      },
    );
    addTearDown(() => entry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnconstrainedBox(
          child: Overlay(
            initialEntries: <OverlayEntry>[entry],
          ),
        ),
      ),
    );
    FlutterError.onError = oldHandler;

    expect(
      errors.first.toString().replaceAll('\n', ' '),
      contains('Overlay was given infinite constraints and cannot be sized by a suitable child.'),
    );
  });

  testWidgets('Overlay throws if unconstrained and no canSizeOverlay child', (WidgetTester tester) async {
    final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[];
    final FlutterExceptionHandler? oldHandler = FlutterError.onError;
    FlutterError.onError = errors.add;

    final OverlayEntry entry = OverlayEntry(
      builder: (BuildContext context) {
        return const SizedBox(width: 600, height: 600);
      },
    );
    addTearDown(() => entry..remove()..dispose());

    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: UnconstrainedBox(
          child: Overlay(
            initialEntries: <OverlayEntry>[entry],
          ),
        ),
      ),
    );
    FlutterError.onError = oldHandler;

    expect(
      errors.first.toString().replaceAll('\n', ' '),
      contains('Overlay was given infinite constraints and cannot be sized by a suitable child.'),
    );
  });
}

class StatefulTestWidget extends StatefulWidget {
  const StatefulTestWidget({super.key});

  @override
  State<StatefulTestWidget> createState() => StatefulTestState();
}

class StatefulTestState extends State<StatefulTestWidget> {
  int rebuildCount = 0;

  @override
  Widget build(BuildContext context) {
    rebuildCount += 1;
    return Container();
  }
}

/// This helper makes leak tracker forgiving the entry is not disposed.
OverlayEntry _buildOverlayEntry(WidgetBuilder builder) => OverlayEntry(builder: builder);
