slivers_block_global_key_test.dart 4.61 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Ian Hickson's avatar
Ian Hickson committed
2 3 4 5 6
// 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/widgets.dart';
7
import 'package:flutter_test/flutter_test.dart';
Ian Hickson's avatar
Ian Hickson committed
8 9 10 11

int globalGeneration = 0;

class GenerationText extends StatefulWidget {
12
  const GenerationText(this.value, { super.key });
Ian Hickson's avatar
Ian Hickson committed
13 14
  final int value;
  @override
15
  State<GenerationText> createState() => _GenerationTextState();
Ian Hickson's avatar
Ian Hickson committed
16 17 18 19 20 21
}

class _GenerationTextState extends State<GenerationText> {
  _GenerationTextState() : generation = globalGeneration;
  final int generation;
  @override
22
  Widget build(BuildContext context) => Text('${widget.value}:$generation ', textDirection: TextDirection.ltr);
Ian Hickson's avatar
Ian Hickson committed
23 24
}

25 26
// Creates a SliverList with `keys.length` children and each child having a key from `keys` and a text of `key:generation`.
// The generation is increased with every call to this method.
27
Future<void> test(WidgetTester tester, double offset, List<int> keys) {
Ian Hickson's avatar
Ian Hickson committed
28
  globalGeneration += 1;
29
  return tester.pumpWidget(
30
    Directionality(
31
      textDirection: TextDirection.ltr,
32
      child: Viewport(
33
        cacheExtent: 0.0,
34
        offset: ViewportOffset.fixed(offset),
35
        slivers: <Widget>[
36
          SliverList(
37
            delegate: SliverChildListDelegate(keys.map<Widget>((int key) {
38
              return SizedBox(key: GlobalObjectKey(key), height: 100.0, child: GenerationText(key));
39 40 41
            }).toList()),
          ),
        ],
Ian Hickson's avatar
Ian Hickson committed
42
      ),
43 44
    ),
  );
Ian Hickson's avatar
Ian Hickson committed
45 46
}

47 48
// `answerKey`: Expected offsets of visible SliverList children in global coordinate system.
// `text`: A space-separated list of expected `key:generation` pairs for the visible SliverList children.
49 50
void verify(WidgetTester tester, List<Offset> answerKey, String text) {
  final List<Offset> testAnswers = tester.renderObjectList<RenderBox>(find.byType(SizedBox)).map<Offset>(
51
    (RenderBox target) => target.localToGlobal(Offset.zero),
Ian Hickson's avatar
Ian Hickson committed
52 53 54
  ).toList();
  expect(testAnswers, equals(answerKey));
  final String foundText =
Ian Hickson's avatar
Ian Hickson committed
55
    tester.widgetList<Text>(find.byType(Text))
56
        .map<String>((Text widget) => widget.data!)
57
        .reduce((String value, String element) => value + element);
Ian Hickson's avatar
Ian Hickson committed
58 59 60 61
  expect(foundText, equals(text));
}

void main() {
Adam Barth's avatar
Adam Barth committed
62
  testWidgets('Viewport+SliverBlock with GlobalKey reparenting', (WidgetTester tester) async {
Ian Hickson's avatar
Ian Hickson committed
63
    await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
64
    verify(tester, <Offset>[
65
      Offset.zero,
66 67 68 69 70
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
71 72 73
    ], '1:1 2:1 3:1 4:1 5:1 6:1 ');
    // gen 2 - flipping the order:
    await test(tester, 0.0, <int>[9,8,7,6,5,4,3,2,1]);
74
    verify(tester, <Offset>[
75
      Offset.zero,
76 77 78 79 80
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
81 82 83
    ], '9:2 8:2 7:2 6:1 5:1 4:1 ');
    // gen 3 - flipping the order back:
    await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
84
    verify(tester, <Offset>[
85
      Offset.zero,
86 87 88 89 90
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
91 92 93
    ], '1:3 2:3 3:3 4:1 5:1 6:1 ');
    // gen 4 - removal:
    await test(tester, 0.0, <int>[1,2,3,5,6,7,8,9]);
94
    verify(tester, <Offset>[
95
      Offset.zero,
96 97 98 99 100
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
101 102 103
    ], '1:3 2:3 3:3 5:1 6:1 7:4 ');
    // gen 5 - insertion:
    await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]);
104
    verify(tester, <Offset>[
105
      Offset.zero,
106 107 108 109 110
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
111 112 113
    ], '1:3 2:3 3:3 4:5 5:1 6:1 ');
    // gen 6 - adjacent reordering:
    await test(tester, 0.0, <int>[1,2,3,5,4,6,7,8,9]);
114
    verify(tester, <Offset>[
115
      Offset.zero,
116 117 118 119 120
      const Offset(0.0, 100.0),
      const Offset(0.0, 200.0),
      const Offset(0.0, 300.0),
      const Offset(0.0, 400.0),
      const Offset(0.0, 500.0),
Ian Hickson's avatar
Ian Hickson committed
121 122 123
    ], '1:3 2:3 3:3 5:1 4:5 6:1 ');
    // gen 7 - scrolling:
    await test(tester, 120.0, <int>[1,2,3,5,4,6,7,8,9]);
124 125 126 127 128 129 130 131
    verify(tester, <Offset>[
      const Offset(0.0, -20.0),
      const Offset(0.0, 80.0),
      const Offset(0.0, 180.0),
      const Offset(0.0, 280.0),
      const Offset(0.0, 380.0),
      const Offset(0.0, 480.0),
      const Offset(0.0, 580.0),
Ian Hickson's avatar
Ian Hickson committed
132 133 134
    ], '2:3 3:3 5:1 4:5 6:1 7:7 8:7 ');
  });
}