import 'dart:collection'; import 'dart:math'; import 'package:flutter_test/flutter_test.dart'; import 'package:relatica/friendica_client/paged_response.dart'; import 'package:relatica/friendica_client/pages_manager.dart'; import 'package:relatica/friendica_client/paging_data.dart'; import 'package:relatica/models/exec_error.dart'; import 'package:result_monad/result_monad.dart'; //Ensure works for ascending and descending tests void main() async { test('Full range test', () async { final pm = _buildPagesManager(); final numbers = []; final initial = await pm.initialize(10); for (var e in initial.value.data) { numbers.add(e.id); } var current = initial.value; while (current.next != null) { final result = await pm.nextWithResult(current); current = result.value; for (var e in result.value.data) { numbers.add(e.id); } } current = initial.value; while (current.previous != null) { final result = await pm.previousWithResult(current); current = result.value; for (var e in result.value.data) { numbers.add(e.id); } } numbers.sort(); final expected = elements.map((e) => e.id).toList(); expected.sort(); expect(numbers.length, equals(elements.length)); expect(numbers, equals(expected)); _checkPagesOrder(pm.pages); }); test('End fills test', () async { final pm = _buildPagesManager(); final numbers = []; final initial = await pm.initialize(10); for (var e in initial.value.data.reversed) { numbers.add(e.id); } var moreWork = true; while (moreWork) { final nextFromEnd = await pm.nextFromEnd(); final previousFromBeginning = await pm.previousFromBeginning(); nextFromEnd.andThenSuccess( (r) => r.data.reversed.forEach((e) => numbers.add(e.id))); previousFromBeginning.andThenSuccess( (r) => r.data.forEach((e) => numbers.insert(0, e.id))); moreWork = nextFromEnd.isSuccess || previousFromBeginning.isSuccess; } for (var i = 0; i < numbers.length - 1; i++) { expect(numbers[i], greaterThan(numbers[i + 1])); } numbers.sort(); expect(numbers.length, equals(elements.length)); expect(numbers, equals(elements.map((e) => e.id))); _checkPagesOrder(pm.pages); }); } void _checkPagesOrder(UnmodifiableListView pages) { expect(pages.first.previous, equals(null)); expect(pages.last.next, equals(null)); for (var i = 1; i < pages.length - 2; i++) { final p0 = pages[i]; final p1 = pages[i + 1]; expect(p0.previous!.minId, greaterThan(p1.previous!.minId!)); expect(p0.next!.maxId, greaterThan(p1.next!.maxId!)); } } class _DataElement { final int id; final int value; _DataElement({required this.id, required this.value}); @override String toString() { return '_DataElement{id: $id}'; } } const count = 1000; final elements = List.generate( count, (index) => _DataElement(id: index, value: Random().nextInt(100))); PagesManager, int> _buildPagesManager() => PagesManager( idMapper: (data) => data.map((e) => e.id).toList(), onRequest: getDataElements); FutureResult>, ExecError> getDataElements( PagingData page) async { final count = page.limit; late final int start; late final int stop; if (page.isLimitOnly) { stop = elements.length ~/ 2; start = stop - count; } else if (page.minId != null) { start = page.minId!; stop = start + count; } else if (page.maxId != null) { stop = page.maxId!; start = stop - count; } else { return buildErrorResult( type: ErrorType.serverError, message: 'Unknown paging type combo (only min and max supported)', ); } int previous = stop; int next = start; final data = elements.sublist(max(0, start), min(elements.length, stop)); return Result.ok( PagedResponse( data, previous: previous > elements.length - 1 ? null : PagingData(limit: count, minId: previous), next: next < 0 ? null : PagingData(limit: count, maxId: next), ), ); }