flutter/packages/flutter/test/rendering/sliver_fixed_extent_layout_test.dart

188 lines
6.4 KiB
Dart
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart';
import '../flutter_test_alternative.dart';
import 'rendering_tester.dart';
void main() {
test('RenderSliverFixedExtentList layout test - rounding error', () {
final List<RenderBox> children = <RenderBox>[
RenderSizedBox(const Size(400.0, 100.0)),
RenderSizedBox(const Size(400.0, 100.0)),
RenderSizedBox(const Size(400.0, 100.0)),
];
final TestRenderSliverBoxChildManager childManager = TestRenderSliverBoxChildManager(
children: children,
);
final RenderViewport root = RenderViewport(
axisDirection: AxisDirection.down,
crossAxisDirection: AxisDirection.right,
offset: ViewportOffset.zero(),
cacheExtent: 0,
children: <RenderSliver>[
childManager.createRenderSliverFillViewport(),
],
);
layout(root);
expect(children[0].attached, true);
expect(children[1].attached, false);
root.offset = ViewportOffset.fixed(600);
pumpFrame();
expect(children[0].attached, false);
expect(children[1].attached, true);
// Simulate double precision error.
root.offset = ViewportOffset.fixed(1199.999999999998);
pumpFrame();
expect(children[1].attached, false);
expect(children[2].attached, true);
});
group('getMaxChildIndexForScrollOffset', () {
// Regression test for https://github.com/flutter/flutter/issues/68182
const double genericItemExtent = 600.0;
const double extraValueToNotHaveRoundingIssues = 0.0000001; // 6 zeros
const double extraValueToHaveRoundingIssues = 0.00000001; // 7 zeros
test('should be 0 when item extent is 0', () {
const double offsetValueWhichDoesntCare = 1234;
final int actual = testGetMaxChildIndexForScrollOffset(offsetValueWhichDoesntCare, 0);
expect(actual, 0);
});
test('should be 0 when offset is 0', () {
final int actual = testGetMaxChildIndexForScrollOffset(0, genericItemExtent);
expect(actual, 0);
});
test('should be 0 when offset is equal to item extent', () {
final int actual = testGetMaxChildIndexForScrollOffset(genericItemExtent, genericItemExtent);
expect(actual, 0);
});
test('should be 1 when offset is greater than item extent', () {
final int actual = testGetMaxChildIndexForScrollOffset(
genericItemExtent + 1, genericItemExtent);
expect(actual, 1);
});
test('should be 1 when offset is slightly greater than item extent', () {
final int actual = testGetMaxChildIndexForScrollOffset(
genericItemExtent + extraValueToNotHaveRoundingIssues, genericItemExtent);
expect(actual, 1);
});
test('should be 4 when offset is four times and a half greater than item extent', () {
final int actual = testGetMaxChildIndexForScrollOffset(
genericItemExtent * 4.5, genericItemExtent);
expect(actual, 4);
});
test('should be 5 when offset is 6 times greater than item extent', () {
const double anotherGenericItemExtent = 414.0;
final int actual = testGetMaxChildIndexForScrollOffset(
anotherGenericItemExtent * 6, anotherGenericItemExtent);
expect(actual, 5);
});
test('should be 5 when offset is 6 times greater than a specific item extent where the division will return more than 13 zero decimals', () {
const double itemExtentSpecificForAProblematicSreenSize = 411.42857142857144;
final int actual = testGetMaxChildIndexForScrollOffset(
itemExtentSpecificForAProblematicSreenSize * 6 + extraValueToHaveRoundingIssues,
itemExtentSpecificForAProblematicSreenSize);
expect(actual, 5);
});
test('should be 0 when offset is 0.00000001 times greater than item extent where the divison will return more than 13 zero decimals', () {
final int actual = testGetMaxChildIndexForScrollOffset(
genericItemExtent + extraValueToHaveRoundingIssues, genericItemExtent);
expect(actual, 0);
});
});
}
int testGetMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
final TestRenderSliverFixedExtentBoxAdaptor renderSliver = TestRenderSliverFixedExtentBoxAdaptor();
return renderSliver.getMaxChildIndexForScrollOffset(scrollOffset, itemExtent);
}
class TestRenderSliverBoxChildManager extends RenderSliverBoxChildManager {
TestRenderSliverBoxChildManager({
required this.children,
});
RenderSliverMultiBoxAdaptor? _renderObject;
List<RenderBox> children;
RenderSliverFillViewport createRenderSliverFillViewport() {
assert(_renderObject == null);
_renderObject = RenderSliverFillViewport(
childManager: this,
);
return _renderObject! as RenderSliverFillViewport;
}
int? _currentlyUpdatingChildIndex;
@override
void createChild(int index, { required RenderBox? after }) {
if (index < 0 || index >= children.length)
return;
try {
_currentlyUpdatingChildIndex = index;
_renderObject!.insert(children[index], after: after);
} finally {
_currentlyUpdatingChildIndex = null;
}
}
@override
void removeChild(RenderBox child) {
_renderObject!.remove(child);
}
@override
double estimateMaxScrollOffset(
SliverConstraints constraints, {
int? firstIndex,
int? lastIndex,
double? leadingScrollOffset,
double? trailingScrollOffset,
}) {
assert(lastIndex! >= firstIndex!);
return children.length * (trailingScrollOffset! - leadingScrollOffset!) / (lastIndex! - firstIndex! + 1);
}
@override
int get childCount => children.length;
@override
void didAdoptChild(RenderBox child) {
assert(_currentlyUpdatingChildIndex != null);
final SliverMultiBoxAdaptorParentData childParentData = child.parentData! as SliverMultiBoxAdaptorParentData;
childParentData.index = _currentlyUpdatingChildIndex;
}
@override
void setDidUnderflow(bool value) { }
}
class TestRenderSliverFixedExtentBoxAdaptor extends RenderSliverFixedExtentBoxAdaptor {
TestRenderSliverFixedExtentBoxAdaptor()
:super(childManager: TestRenderSliverBoxChildManager(children: <RenderBox>[]));
@override
// ignore: unnecessary_overrides
int getMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
return super.getMaxChildIndexForScrollOffset(scrollOffset, itemExtent);
}
@override
double get itemExtent => throw UnimplementedError();
}