slivers_test.dart 42.4 KB
Newer Older
1 2 3 4
// 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.

5
import 'package:flutter/gestures.dart';
6
import 'package:flutter/rendering.dart';
7
import 'package:flutter/widgets.dart';
8
import 'package:flutter_test/flutter_test.dart';
9
import 'package:vector_math/vector_math_64.dart';
10 11 12 13

import 'rendering_tester.dart';

void main() {
Adam Barth's avatar
Adam Barth committed
14
  test('RenderViewport basic test - no children', () {
15
    final RenderViewport root = RenderViewport(
16
      crossAxisDirection: AxisDirection.right,
17
      offset: ViewportOffset.zero(),
Ian Hickson's avatar
Ian Hickson committed
18
    );
19
    expect(root, hasAGoodToStringDeep);
20
    expect(
21
      root.toStringDeep(minLevel: DiagnosticLevel.info),
22 23
      equalsIgnoringHashCodes(
        'RenderViewport#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
24
        '   needs compositing\n'
Ian Hickson's avatar
Ian Hickson committed
25 26
        '   parentData: MISSING\n'
        '   constraints: MISSING\n'
27 28
        '   size: MISSING\n'
        '   axisDirection: down\n'
29
        '   crossAxisDirection: right\n'
30 31
        '   offset: _FixedViewportOffset#00000(offset: 0.0)\n'
        '   anchor: 0.0\n'
32 33
      ),
    );
34
    layout(root);
35
    root.offset = ViewportOffset.fixed(900.0);
36
    expect(root, hasAGoodToStringDeep);
37
    expect(
38
      root.toStringDeep(minLevel: DiagnosticLevel.info),
39 40
      equalsIgnoringHashCodes(
        'RenderViewport#00000 NEEDS-LAYOUT NEEDS-PAINT\n'
41
        '   needs compositing\n'
42 43 44 45
        '   parentData: <none>\n'
        '   constraints: BoxConstraints(w=800.0, h=600.0)\n'
        '   size: Size(800.0, 600.0)\n'
        '   axisDirection: down\n'
46
        '   crossAxisDirection: right\n'
47 48
        '   offset: _FixedViewportOffset#00000(offset: 900.0)\n'
        '   anchor: 0.0\n',
49 50 51
      ),
    );

52 53 54
    pumpFrame();
  });

Adam Barth's avatar
Adam Barth committed
55
  test('RenderViewport basic test - down', () {
56
    RenderBox a, b, c, d, e;
57
    final RenderViewport root = RenderViewport(
58
      crossAxisDirection: AxisDirection.right,
59
      offset: ViewportOffset.zero(),
60
      children: <RenderSliver>[
61 62 63 64 65
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(100.0, 400.0))),
66 67
      ],
    );
68
    expect(root, hasAGoodToStringDeep);
69 70 71 72 73
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

74 75
    expect(root, hasAGoodToStringDeep);
    expect(
76
      root.toStringDeep(minLevel: DiagnosticLevel.info),
77
      equalsIgnoringHashCodes(
78 79
        'RenderViewport#00000 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
        ' │ needs compositing\n'
80 81 82
        ' │ parentData: <none>\n'
        ' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
        ' │ size: Size(800.0, 600.0)\n'
83
        ' │ axisDirection: down\n'
84
        ' │ crossAxisDirection: right\n'
85 86 87
        ' │ offset: _FixedViewportOffset#00000(offset: 0.0)\n'
        ' │ anchor: 0.0\n'
        ' │\n'
88
        ' ├─center child: RenderSliverToBoxAdapter#00000 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
89 90 91 92
        ' │ │ parentData: paintOffset=Offset(0.0, 0.0) (can use size)\n'
        ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
        ' │ │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
        ' │ │   0.0, remainingPaintExtent: 600.0, crossAxisExtent: 800.0,\n'
93
        ' │ │   crossAxisDirection: AxisDirection.right,\n'
94 95
        ' │ │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 850.0\n'
        ' │ │   cacheOrigin: 0.0 )\n'
96
        ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 400.0,\n'
97
        ' │ │   maxPaintExtent: 400.0, cacheExtent: 400.0)\n'
98 99 100 101 102 103
        ' │ │\n'
        ' │ └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
        ' │     parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
        ' │     constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
        ' │     size: Size(800.0, 400.0)\n'
        ' │\n'
104
        ' ├─child 1: RenderSliverToBoxAdapter#00000 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
105 106 107 108
        ' │ │ parentData: paintOffset=Offset(0.0, 400.0) (can use size)\n'
        ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
        ' │ │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
        ' │ │   0.0, remainingPaintExtent: 200.0, crossAxisExtent: 800.0,\n'
109
        ' │ │   crossAxisDirection: AxisDirection.right,\n'
110 111
        ' │ │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 450.0\n'
        ' │ │   cacheOrigin: 0.0 )\n'
112
        ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, paintExtent: 200.0,\n'
113 114
        ' │ │   maxPaintExtent: 400.0, hasVisualOverflow: true, cacheExtent:\n'
        ' │ │   400.0)\n'
115 116 117 118 119 120
        ' │ │\n'
        ' │ └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
        ' │     parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
        ' │     constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
        ' │     size: Size(800.0, 400.0)\n'
        ' │\n'
121
        ' ├─child 2: RenderSliverToBoxAdapter#00000 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
122
        ' │ │ parentData: paintOffset=Offset(0.0, 800.0) (can use size)\n'
123 124 125
        ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
        ' │ │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
        ' │ │   0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
126
        ' │ │   crossAxisDirection: AxisDirection.right,\n'
127 128
        ' │ │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 50.0\n'
        ' │ │   cacheOrigin: 0.0 )\n'
129
        ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
130 131
        ' │ │   maxPaintExtent: 400.0, hasVisualOverflow: true, cacheExtent:\n'
        ' │ │   50.0)\n'
132 133 134 135 136 137
        ' │ │\n'
        ' │ └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
        ' │     parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
        ' │     constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
        ' │     size: Size(800.0, 400.0)\n'
        ' │\n'
138
        ' ├─child 3: RenderSliverToBoxAdapter#00000 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
139
        ' │ │ parentData: paintOffset=Offset(0.0, 1200.0) (can use size)\n'
140 141 142
        ' │ │ constraints: SliverConstraints(AxisDirection.down,\n'
        ' │ │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
        ' │ │   0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
143
        ' │ │   crossAxisDirection: AxisDirection.right,\n'
144 145
        ' │ │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 0.0\n'
        ' │ │   cacheOrigin: 0.0 )\n'
146
        ' │ │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
147
        ' │ │   maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
148 149 150 151 152 153
        ' │ │\n'
        ' │ └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
        ' │     parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
        ' │     constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
        ' │     size: Size(800.0, 400.0)\n'
        ' │\n'
154
        ' └─child 4: RenderSliverToBoxAdapter#00000 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE\n'
155
        '   │ parentData: paintOffset=Offset(0.0, 1600.0) (can use size)\n'
156 157 158
        '   │ constraints: SliverConstraints(AxisDirection.down,\n'
        '   │   GrowthDirection.forward, ScrollDirection.idle, scrollOffset:\n'
        '   │   0.0, remainingPaintExtent: 0.0, crossAxisExtent: 800.0,\n'
159
        '   │   crossAxisDirection: AxisDirection.right,\n'
160 161
        '   │   viewportMainAxisExtent: 600.0, remainingCacheExtent: 0.0\n'
        '   │   cacheOrigin: 0.0 )\n'
162
        '   │ geometry: SliverGeometry(scrollExtent: 400.0, hidden,\n'
163
        '   │   maxPaintExtent: 400.0, hasVisualOverflow: true)\n'
164 165 166 167
        '   │\n'
        '   └─child: RenderSizedBox#00000 NEEDS-PAINT\n'
        '       parentData: paintOffset=Offset(0.0, -0.0) (can use size)\n'
        '       constraints: BoxConstraints(w=800.0, 0.0<=h<=Infinity)\n'
168
        '       size: Size(800.0, 400.0)\n'
169 170
      ),
    );
171 172
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
173 174 175
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 800.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1200.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1600.0));
176 177 178

    expect(a.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 400.0));
    expect(b.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 800.0));
179 180 181
    expect(c.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 1200.0));
    expect(d.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 1600.0));
    expect(e.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 2000.0));
182

183
    root.offset = ViewportOffset.fixed(200.0);
184
    pumpFrame();
185 186 187
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 600.0));
188 189
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1000.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1400.0));
190

191
    root.offset = ViewportOffset.fixed(600.0);
192
    pumpFrame();
193 194 195 196
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -600.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 600.0));
197
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1000.0));
198

199
    root.offset = ViewportOffset.fixed(900.0);
200
    pumpFrame();
201 202 203 204
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -900.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -500.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -100.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
205
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 700.0));
206

207
    final BoxHitTestResult result = BoxHitTestResult();
208
    root.hitTest(result, position: const Offset(130.0, 150.0));
209
    expect(result.path.first.target, equals(c));
210 211
  });

Adam Barth's avatar
Adam Barth committed
212
  test('RenderViewport basic test - up', () {
213
    RenderBox a, b, c, d, e;
214
    final RenderViewport root = RenderViewport(
215
      axisDirection: AxisDirection.up,
216
      crossAxisDirection: AxisDirection.right,
217
      offset: ViewportOffset.zero(),
218
      children: <RenderSliver>[
219 220 221 222 223
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(100.0, 400.0))),
224 225 226 227 228 229 230
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

231 232
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
233 234 235
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -600.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1000.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1400.0));
236

237
    root.offset = ViewportOffset.fixed(200.0);
238
    pumpFrame();
239 240 241
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -400.0));
242 243
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -800.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1200.0));
244

245
    root.offset = ViewportOffset.fixed(600.0);
246
    pumpFrame();
247 248 249 250
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 800.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -400.0));
251
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -800.0));
252

253
    root.offset = ViewportOffset.fixed(900.0);
254
    pumpFrame();
255 256 257 258
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1100.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 700.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -100.0));
259
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -500.0));
260

261
    final BoxHitTestResult result = BoxHitTestResult();
262
    root.hitTest(result, position: const Offset(150.0, 350.0));
263
    expect(result.path.first.target, equals(c));
264 265
  });

266
  Offset _getPaintOrigin(RenderObject render) {
267 268
    final Vector3 transformed3 = render.getTransformTo(null).perspectiveTransform(Vector3(0.0, 0.0, 0.0));
    return Offset(transformed3.x, transformed3.y);
269 270
  }

Adam Barth's avatar
Adam Barth committed
271
  test('RenderViewport basic test - right', () {
272
    RenderBox a, b, c, d, e;
273
    final RenderViewport root = RenderViewport(
274
      axisDirection: AxisDirection.right,
275
      crossAxisDirection: AxisDirection.down,
276
      offset: ViewportOffset.zero(),
277
      children: <RenderSliver>[
278 279 280 281 282
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(400.0, 100.0))),
283 284 285 286 287 288 289
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

290 291 292 293 294 295
    final RenderSliver sliverA = a.parent;
    final RenderSliver sliverB = b.parent;
    final RenderSliver sliverC = c.parent;
    final RenderSliver sliverD = d.parent;
    final RenderSliver sliverE = e.parent;

296 297 298
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(400.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(800.0, 0.0));
299 300
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(1200.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1600.0, 0.0));
301

302 303 304
    expect(_getPaintOrigin(sliverA), const Offset(0.0, 0.0));
    expect(_getPaintOrigin(sliverB), const Offset(400.0, 0.0));
    expect(_getPaintOrigin(sliverC), const Offset(800.0, 0.0));
305 306
    expect(_getPaintOrigin(sliverD), const Offset(1200.0, 0.0));
    expect(_getPaintOrigin(sliverE), const Offset(1600.0, 0.0));
307

308
    root.offset = ViewportOffset.fixed(200.0);
309
    pumpFrame();
310 311 312
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
313 314
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1400.0, 0.0));
315

316 317 318
    expect(_getPaintOrigin(sliverA), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverB), const Offset(200.0, 0.0));
    expect(_getPaintOrigin(sliverC), const Offset(600.0, 0.0));
319 320
    expect(_getPaintOrigin(sliverD), const Offset(1000.0, 0.0));
    expect(_getPaintOrigin(sliverE), const Offset(1400.0, 0.0));
321

322
    root.offset = ViewportOffset.fixed(600.0);
323
    pumpFrame();
324 325 326 327
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
328
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
329

330 331 332 333
    expect(_getPaintOrigin(sliverA), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverB), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverC), const Offset(200.0, 0.0));
    expect(_getPaintOrigin(sliverD), const Offset(600.0, 0.0));
334
    expect(_getPaintOrigin(sliverE), const Offset(1000.0, 0.0));
335

336
    root.offset = ViewportOffset.fixed(900.0);
337
    pumpFrame();
338 339 340 341 342
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-900.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(-500.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-100.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(300.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 0.0));
343

344 345 346 347 348 349
    expect(_getPaintOrigin(sliverA), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverB), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverC), const Offset(000.0, 0.0));
    expect(_getPaintOrigin(sliverD), const Offset(300.0, 0.0));
    expect(_getPaintOrigin(sliverE), const Offset(700.0, 0.0));

350
    final BoxHitTestResult result = BoxHitTestResult();
351
    root.hitTest(result, position: const Offset(150.0, 450.0));
352
    expect(result.path.first.target, equals(c));
353 354
  });

Adam Barth's avatar
Adam Barth committed
355
  test('RenderViewport basic test - left', () {
356
    RenderBox a, b, c, d, e;
357
    final RenderViewport root = RenderViewport(
358
      axisDirection: AxisDirection.left,
359
      crossAxisDirection: AxisDirection.down,
360
      offset: ViewportOffset.zero(),
361
      children: <RenderSliver>[
362 363 364 365 366
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(400.0, 100.0))),
367 368 369 370 371 372 373
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

374 375 376
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(400.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-400.0, 0.0));
377 378
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-800.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-1200.0, 0.0));
379

380
    root.offset = ViewportOffset.fixed(200.0);
381
    pumpFrame();
382 383 384
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
385 386
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-1000.0, 0.0));
387

388
    root.offset = ViewportOffset.fixed(600.0);
389
    pumpFrame();
390 391 392 393
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
394
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
395

396
    root.offset = ViewportOffset.fixed(900.0);
397
    pumpFrame();
398 399 400 401 402
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(1300.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(900.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(100.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-300.0, 0.0));
403

404
    final BoxHitTestResult result = BoxHitTestResult();
405
    root.hitTest(result, position: const Offset(550.0, 150.0));
406
    expect(result.path.first.target, equals(c));
407 408 409 410 411 412
  });

  // TODO(ianh): test anchor
  // TODO(ianh): test center
  // TODO(ianh): test semantics

413
  test('RenderShrinkWrappingViewport basic test - no children', () {
414
    final RenderShrinkWrappingViewport root = RenderShrinkWrappingViewport(
415
      crossAxisDirection: AxisDirection.right,
416
      offset: ViewportOffset.zero(),
417
    );
418
    expect(root, hasAGoodToStringDeep);
419
    layout(root);
420
    root.offset = ViewportOffset.fixed(900.0);
421 422 423 424 425
    pumpFrame();
  });

  test('RenderShrinkWrappingViewport basic test - down', () {
    RenderBox a, b, c, d, e;
426
    final RenderShrinkWrappingViewport root = RenderShrinkWrappingViewport(
427
      crossAxisDirection: AxisDirection.right,
428
      offset: ViewportOffset.zero(),
429
      children: <RenderSliver>[
430 431 432 433 434
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(100.0, 400.0))),
435 436 437 438 439 440 441
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

442 443
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
444 445 446
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 800.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1200.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1600.0));
447

448 449
    expect(a.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 400.0));
    expect(b.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 800.0));
450 451 452
    expect(c.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 1200.0));
    expect(d.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 1600.0));
    expect(e.localToGlobal(const Offset(800.0, 400.0)), const Offset(800.0, 2000.0));
453

454
    root.offset = ViewportOffset.fixed(200.0);
455
    pumpFrame();
456 457 458
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 600.0));
459 460
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1000.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1400.0));
461

462
    root.offset = ViewportOffset.fixed(600.0);
463
    pumpFrame();
464 465 466 467
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -600.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 600.0));
468
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1000.0));
469

470
    root.offset = ViewportOffset.fixed(900.0);
471
    pumpFrame();
472 473 474 475
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -900.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -500.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -100.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
476
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 700.0));
477

478
    final BoxHitTestResult result = BoxHitTestResult();
479
    root.hitTest(result, position: const Offset(130.0, 150.0));
480 481 482 483 484
    expect(result.path.first.target, equals(c));
  });

  test('RenderShrinkWrappingViewport basic test - up', () {
    RenderBox a, b, c, d, e;
485
    final RenderShrinkWrappingViewport root = RenderShrinkWrappingViewport(
486
      axisDirection: AxisDirection.up,
487
      crossAxisDirection: AxisDirection.right,
488
      offset: ViewportOffset.zero(),
489
      children: <RenderSliver>[
490 491 492 493 494
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(100.0, 400.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(100.0, 400.0))),
495 496 497 498 499 500 501
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

502 503
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 200.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -200.0));
504 505 506
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -600.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1000.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1400.0));
507

508
    root.offset = ViewportOffset.fixed(200.0);
509
    pumpFrame();
510 511 512
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -400.0));
513 514
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -800.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -1200.0));
515

516
    root.offset = ViewportOffset.fixed(600.0);
517
    pumpFrame();
518 519 520 521
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 800.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 400.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -400.0));
522
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -800.0));
523

524
    root.offset = ViewportOffset.fixed(900.0);
525
    pumpFrame();
526 527 528 529
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 1100.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 700.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 300.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -100.0));
530
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, -500.0));
531

532
    final BoxHitTestResult result = BoxHitTestResult();
533
    root.hitTest(result, position: const Offset(150.0, 350.0));
534 535 536 537 538
    expect(result.path.first.target, equals(c));
  });

  test('RenderShrinkWrappingViewport basic test - right', () {
    RenderBox a, b, c, d, e;
539
    final RenderShrinkWrappingViewport root = RenderShrinkWrappingViewport(
540
      axisDirection: AxisDirection.right,
541
      crossAxisDirection: AxisDirection.down,
542
      offset: ViewportOffset.zero(),
543
      children: <RenderSliver>[
544 545 546 547 548
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(400.0, 100.0))),
549 550 551 552 553 554 555
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

556 557 558
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(400.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(800.0, 0.0));
559 560
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(1200.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1600.0, 0.0));
561

562
    root.offset = ViewportOffset.fixed(200.0);
563
    pumpFrame();
564 565 566
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
567 568
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1400.0, 0.0));
569

570
    root.offset = ViewportOffset.fixed(600.0);
571
    pumpFrame();
572 573 574 575
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
576
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
577

578
    root.offset = ViewportOffset.fixed(900.0);
579
    pumpFrame();
580 581 582 583 584
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(-900.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(-500.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-100.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(300.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(700.0, 0.0));
585

586
    final BoxHitTestResult result = BoxHitTestResult();
587
    root.hitTest(result, position: const Offset(150.0, 450.0));
588 589 590 591 592
    expect(result.path.first.target, equals(c));
  });

  test('RenderShrinkWrappingViewport basic test - left', () {
    RenderBox a, b, c, d, e;
593
    final RenderShrinkWrappingViewport root = RenderShrinkWrappingViewport(
594
      axisDirection: AxisDirection.left,
595
      crossAxisDirection: AxisDirection.down,
596
      offset: ViewportOffset.zero(),
597
      children: <RenderSliver>[
598 599 600 601 602
        RenderSliverToBoxAdapter(child: a = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: b = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: c = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: d = RenderSizedBox(const Size(400.0, 100.0))),
        RenderSliverToBoxAdapter(child: e = RenderSizedBox(const Size(400.0, 100.0))),
603 604 605 606 607 608 609
      ],
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));

610 611 612
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(400.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(0.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-400.0, 0.0));
613 614
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-800.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-1200.0, 0.0));
615

616
    root.offset = ViewportOffset.fixed(200.0);
617
    pumpFrame();
618 619 620
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
621 622
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-1000.0, 0.0));
623

624
    root.offset = ViewportOffset.fixed(600.0);
625
    pumpFrame();
626 627 628 629
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(1000.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(600.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(200.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(-200.0, 0.0));
630
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-600.0, 0.0));
631

632
    root.offset = ViewportOffset.fixed(900.0);
633
    pumpFrame();
634 635 636 637 638
    expect(a.localToGlobal(const Offset(0.0, 0.0)), const Offset(1300.0, 0.0));
    expect(b.localToGlobal(const Offset(0.0, 0.0)), const Offset(900.0, 0.0));
    expect(c.localToGlobal(const Offset(0.0, 0.0)), const Offset(500.0, 0.0));
    expect(d.localToGlobal(const Offset(0.0, 0.0)), const Offset(100.0, 0.0));
    expect(e.localToGlobal(const Offset(0.0, 0.0)), const Offset(-300.0, 0.0));
639

640
    final BoxHitTestResult result = BoxHitTestResult();
641
    root.hitTest(result, position: const Offset(550.0, 150.0));
642 643 644 645 646
    expect(result.path.first.target, equals(c));
  });

  test('RenderShrinkWrappingViewport shrinkwrap test - 1 child', () {
    RenderBox child;
647 648
    final RenderBox root = RenderPositionedBox(
      child: child = RenderShrinkWrappingViewport(
649
        axisDirection: AxisDirection.left,
650
        crossAxisDirection: AxisDirection.down,
651
        offset: ViewportOffset.fixed(200.0),
652
        children: <RenderSliver>[
653
          RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(400.0, 100.0))),
654 655 656 657 658 659 660 661 662 663 664 665 666
        ],
      ),
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));
    expect(child.size.width, equals(400.0));
    expect(child.size.height, equals(600.0));
  });

  test('RenderShrinkWrappingViewport shrinkwrap test - 2 children', () {
    RenderBox child;
667 668
    final RenderBox root = RenderPositionedBox(
      child: child = RenderShrinkWrappingViewport(
669
        axisDirection: AxisDirection.right,
670
        crossAxisDirection: AxisDirection.down,
671
        offset: ViewportOffset.fixed(200.0),
672
        children: <RenderSliver>[
673 674
          RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(300.0, 100.0))),
          RenderSliverToBoxAdapter(child: RenderSizedBox(const Size(150.0, 100.0))),
675 676 677 678 679 680 681 682 683 684
        ],
      ),
    );
    layout(root);

    expect(root.size.width, equals(800.0));
    expect(root.size.height, equals(600.0));
    expect(child.size.width, equals(450.0));
    expect(child.size.height, equals(600.0));
  });
685 686 687

  test('SliverGeometry toString', () {
    expect(
688 689 690
      const SliverGeometry().toString(),
      equals('SliverGeometry(scrollExtent: 0.0, hidden, maxPaintExtent: 0.0)'),
    );
691
    expect(
692 693 694 695 696 697 698
      const SliverGeometry(
        scrollExtent: 100.0,
        paintExtent: 50.0,
        layoutExtent: 20.0,
        visible: true,
      ).toString(),
      equals(
699
        'SliverGeometry(scrollExtent: 100.0, paintExtent: 50.0, layoutExtent: 20.0, maxPaintExtent: 0.0, cacheExtent: 20.0)',
700 701 702 703 704 705 706 707 708
      ),
    );
    expect(
      const SliverGeometry(
        scrollExtent: 100.0,
        paintExtent: 0.0,
        layoutExtent: 20.0,
      ).toString(),
      equals(
709
        'SliverGeometry(scrollExtent: 100.0, hidden, layoutExtent: 20.0, maxPaintExtent: 0.0, cacheExtent: 20.0)',
710 711
      ),
    );
712
  });
713 714 715 716

  test('Sliver paintBounds and semanticBounds - vertical', () {
    const double height = 150.0;

717 718
    final RenderSliver sliver = RenderSliverToBoxAdapter(
        child: RenderSizedBox(const Size(400.0, height)),
719
    );
720
    final RenderViewport root = RenderViewport(
721
      axisDirection: AxisDirection.down,
722
      crossAxisDirection: AxisDirection.right,
723
      offset: ViewportOffset.zero(),
724 725 726 727 728 729
      children: <RenderSliver>[
        sliver,
      ],
    );
    layout(root);

730
    final Rect expectedRect = Rect.fromLTWH(0.0, 0.0, root.size.width, height);
731 732 733 734 735 736 737 738

    expect(sliver.paintBounds, expectedRect);
    expect(sliver.semanticBounds, expectedRect);
  });

  test('Sliver paintBounds and semanticBounds - horizontal', () {
    const double width = 150.0;

739 740
    final RenderSliver sliver = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(width, 400.0)),
741
    );
742
    final RenderViewport root = RenderViewport(
743
      axisDirection: AxisDirection.right,
744
      crossAxisDirection: AxisDirection.down,
745
      offset: ViewportOffset.zero(),
746 747 748 749 750 751
      children: <RenderSliver>[
        sliver,
      ],
    );
    layout(root);

752
    final Rect expectedRect = Rect.fromLTWH(0.0, 0.0, width, root.size.height);
753 754 755 756

    expect(sliver.paintBounds, expectedRect);
    expect(sliver.semanticBounds, expectedRect);
  });
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830

  test('precedingScrollExtent is 0.0 for first Sliver in list', () {
    const double viewportWidth = 800.0;
    final RenderSliver sliver = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderViewport root = RenderViewport(
      axisDirection: AxisDirection.down,
      crossAxisDirection: AxisDirection.right,
      offset: ViewportOffset.zero(),
      children: <RenderSliver>[
        sliver,
      ],
    );
    layout(root);

    expect(sliver.constraints.precedingScrollExtent, 0.0);
  });

  test('precedingScrollExtent accumulates over multiple Slivers', () {
    const double viewportWidth = 800.0;
    final RenderSliver sliver1 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderSliver sliver2 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderSliver sliver3 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderViewport root = RenderViewport(
      axisDirection: AxisDirection.down,
      crossAxisDirection: AxisDirection.right,
      offset: ViewportOffset.zero(),
      children: <RenderSliver>[
        sliver1,
        sliver2,
        sliver3,
      ],
    );
    layout(root);

    // The 3rd Sliver comes after 300.0px of preceding scroll extent by first 2 Slivers.
    expect(sliver3.constraints.precedingScrollExtent, 300.0);
  });

  test('precedingScrollExtent is not impacted by scrollOffset', () {
    const double viewportWidth = 800.0;
    final RenderSliver sliver1 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderSliver sliver2 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderSliver sliver3 = RenderSliverToBoxAdapter(
      child: RenderSizedBox(const Size(viewportWidth, 150.0)),
    );
    final RenderViewport root = RenderViewport(
      axisDirection: AxisDirection.down,
      crossAxisDirection: AxisDirection.right,
      offset: ViewportOffset.fixed(100.0),
      children: <RenderSliver>[
        sliver1,
        sliver2,
        sliver3,
      ],
    );
    layout(root);

    // The 3rd Sliver comes after 300.0px of preceding scroll extent by first 2 Slivers.
    // In this test a ViewportOffset is applied to simulate a scrollOffset. That
    // offset is not expected to impact the precedingScrollExtent.
    expect(sliver3.constraints.precedingScrollExtent, 300.0);
  });
831 832 833 834 835 836

  group('hit testing', () {
    test('SliverHitTestResult wrapping HitTestResult', () {
      final HitTestEntry entry1 = HitTestEntry(_DummyHitTestTarget());
      final HitTestEntry entry2 = HitTestEntry(_DummyHitTestTarget());
      final HitTestEntry entry3 = HitTestEntry(_DummyHitTestTarget());
837
      final Matrix4 transform = Matrix4.translationValues(40.0, 150.0, 0.0);
838

839 840
      final HitTestResult wrapped = MyHitTestResult()
        ..publicPushTransform(transform);
841 842
      wrapped.add(entry1);
      expect(wrapped.path, equals(<HitTestEntry>[entry1]));
843
      expect(entry1.transform, transform);
844 845 846 847 848 849 850 851

      final SliverHitTestResult wrapping = SliverHitTestResult.wrap(wrapped);
      expect(wrapping.path, equals(<HitTestEntry>[entry1]));
      expect(wrapping.path, same(wrapped.path));

      wrapping.add(entry2);
      expect(wrapping.path, equals(<HitTestEntry>[entry1, entry2]));
      expect(wrapped.path, equals(<HitTestEntry>[entry1, entry2]));
852
      expect(entry2.transform, transform);
853 854 855 856

      wrapped.add(entry3);
      expect(wrapping.path, equals(<HitTestEntry>[entry1, entry2, entry3]));
      expect(wrapped.path, equals(<HitTestEntry>[entry1, entry2, entry3]));
857
      expect(entry3.transform, transform);
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
    });

    test('addWithAxisOffset', () {
      final SliverHitTestResult result = SliverHitTestResult();
      final List<double> mainAxisPositions = <double>[];
      final List<double> crossAxisPositions = <double>[];
      const Offset paintOffsetDummy = Offset.zero;

      bool isHit = result.addWithAxisOffset(
        paintOffset: paintOffsetDummy,
        mainAxisOffset: 0.0,
        crossAxisOffset: 0.0,
        mainAxisPosition: 0.0,
        crossAxisPosition: 0.0,
        hitTest: (SliverHitTestResult result, { double mainAxisPosition, double crossAxisPosition }) {
          expect(result, isNotNull);
          mainAxisPositions.add(mainAxisPosition);
          crossAxisPositions.add(crossAxisPosition);
          return true;
        },
      );
      expect(isHit, isTrue);
      expect(mainAxisPositions.single, 0.0);
      expect(crossAxisPositions.single, 0.0);
      mainAxisPositions.clear();
      crossAxisPositions.clear();

      isHit = result.addWithAxisOffset(
        paintOffset: paintOffsetDummy,
        mainAxisOffset: 5.0,
        crossAxisOffset: 6.0,
        mainAxisPosition: 10.0,
        crossAxisPosition: 20.0,
        hitTest: (SliverHitTestResult result, { double mainAxisPosition, double crossAxisPosition }) {
          expect(result, isNotNull);
          mainAxisPositions.add(mainAxisPosition);
          crossAxisPositions.add(crossAxisPosition);
          return false;
        },
      );
      expect(isHit, isFalse);
      expect(mainAxisPositions.single, 10.0 - 5.0);
      expect(crossAxisPositions.single, 20.0 - 6.0);
      mainAxisPositions.clear();
      crossAxisPositions.clear();

      isHit = result.addWithAxisOffset(
        paintOffset: paintOffsetDummy,
        mainAxisOffset: -5.0,
        crossAxisOffset: -6.0,
        mainAxisPosition: 10.0,
        crossAxisPosition: 20.0,
        hitTest: (SliverHitTestResult result, { double mainAxisPosition, double crossAxisPosition }) {
          expect(result, isNotNull);
          mainAxisPositions.add(mainAxisPosition);
          crossAxisPositions.add(crossAxisPosition);
          return false;
        },
      );
      expect(isHit, isFalse);
      expect(mainAxisPositions.single, 10.0 + 5.0);
      expect(crossAxisPositions.single, 20.0 + 6.0);
      mainAxisPositions.clear();
      crossAxisPositions.clear();
    });
  });
}

class _DummyHitTestTarget implements HitTestTarget {
  @override
  void handleEvent(PointerEvent event, HitTestEntry entry) {
    // Nothing to do.
  }
931
}
932 933 934 935

class MyHitTestResult extends HitTestResult {
  void publicPushTransform(Matrix4 transform) => pushTransform(transform);
}