refactored broad range of the application, split files, modularized calendar and file views, centralized bottom sheets and clipboard handling, and implemented unit test coverage
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:marianum_mobile/api/marianumcloud/webdav/queries/list_files/cacheable_file.dart';
|
||||
import 'package:marianum_mobile/api/marianumcloud/webdav/queries/list_files/list_files_response.dart';
|
||||
import 'package:marianum_mobile/view/pages/files/data/sort_options.dart';
|
||||
|
||||
CacheableFile _file({
|
||||
required String name,
|
||||
bool isDirectory = false,
|
||||
int? size,
|
||||
DateTime? modifiedAt,
|
||||
}) =>
|
||||
CacheableFile(
|
||||
path: '/$name',
|
||||
isDirectory: isDirectory,
|
||||
name: name,
|
||||
size: size,
|
||||
modifiedAt: modifiedAt,
|
||||
);
|
||||
|
||||
void main() {
|
||||
group('SortOptions.options', () {
|
||||
test('name comparator is alphabetic', () {
|
||||
final cmp = SortOptions.getOption(SortOption.name).compare;
|
||||
expect(cmp(_file(name: 'a'), _file(name: 'b')), lessThan(0));
|
||||
expect(cmp(_file(name: 'b'), _file(name: 'a')), greaterThan(0));
|
||||
expect(cmp(_file(name: 'a'), _file(name: 'a')), 0);
|
||||
});
|
||||
|
||||
test('date comparator is chronological by modifiedAt', () {
|
||||
final cmp = SortOptions.getOption(SortOption.date).compare;
|
||||
final older = _file(name: 'a', modifiedAt: DateTime(2026, 1, 1));
|
||||
final newer = _file(name: 'b', modifiedAt: DateTime(2026, 5, 1));
|
||||
expect(cmp(older, newer), lessThan(0));
|
||||
expect(cmp(newer, older), greaterThan(0));
|
||||
});
|
||||
|
||||
test('size comparator pushes directories to the end (positional 1 vs 0)', () {
|
||||
final cmp = SortOptions.getOption(SortOption.size).compare;
|
||||
final dir = _file(name: 'd', isDirectory: true);
|
||||
final file = _file(name: 'f', size: 100);
|
||||
// (dir, file) → returns 1 (dir.isDirectory true) → file sorts before dir.
|
||||
expect(cmp(dir, file), 1);
|
||||
expect(cmp(file, dir), 0);
|
||||
});
|
||||
|
||||
test('size comparator handles null sizes', () {
|
||||
final cmp = SortOptions.getOption(SortOption.size).compare;
|
||||
final noSize = _file(name: 'a');
|
||||
final withSize = _file(name: 'b', size: 100);
|
||||
// a.size == null → returns 0
|
||||
expect(cmp(noSize, withSize), 0);
|
||||
// b.size == null → returns 1
|
||||
expect(cmp(withSize, noSize), 1);
|
||||
});
|
||||
|
||||
test('size comparator orders by file size when both known', () {
|
||||
final cmp = SortOptions.getOption(SortOption.size).compare;
|
||||
expect(cmp(_file(name: 'a', size: 100), _file(name: 'b', size: 200)), lessThan(0));
|
||||
expect(cmp(_file(name: 'a', size: 200), _file(name: 'b', size: 100)), greaterThan(0));
|
||||
});
|
||||
|
||||
test('options map contains all enum values exactly once', () {
|
||||
expect(SortOptions.options.keys.toSet(), SortOption.values.toSet());
|
||||
});
|
||||
});
|
||||
|
||||
group('ListFilesResponse.sortBy', () {
|
||||
final folderA = _file(name: 'A', isDirectory: true);
|
||||
final folderB = _file(name: 'B', isDirectory: true);
|
||||
final fileA = _file(name: 'aaa', size: 100, modifiedAt: DateTime(2026, 1, 1));
|
||||
final fileB = _file(name: 'bbb', size: 50, modifiedAt: DateTime(2026, 5, 1));
|
||||
|
||||
// Note: sortBy uses a string-buffer sort + compareTo descending. The actual
|
||||
// list ordering reflects what users see in the file list.
|
||||
test('foldersToTop=true keeps folders before files regardless of name', () {
|
||||
final response = ListFilesResponse({fileA, fileB, folderA, folderB});
|
||||
final sorted = response.sortBy(sortOption: SortOption.name);
|
||||
final folderCount = sorted.takeWhile((f) => f.isDirectory).length;
|
||||
expect(folderCount, 2, reason: 'both folders should sit at the top');
|
||||
});
|
||||
|
||||
test('foldersToTop=false intermixes folders and files', () {
|
||||
final response = ListFilesResponse({fileA, fileB, folderA, folderB});
|
||||
final sorted = response.sortBy(sortOption: SortOption.name, foldersToTop: false);
|
||||
final folderPositions = <int>[];
|
||||
for (var i = 0; i < sorted.length; i++) {
|
||||
if (sorted[i].isDirectory) folderPositions.add(i);
|
||||
}
|
||||
// Without foldersToTop, folders aren't guaranteed to be at the front:
|
||||
// assert at least one folder is somewhere other than the very top of
|
||||
// a folders-first ordering.
|
||||
expect(folderPositions, isNot([0, 1]));
|
||||
});
|
||||
|
||||
test('reversed flips the order within each section', () {
|
||||
final response = ListFilesResponse({fileA, fileB});
|
||||
final asc = response.sortBy(sortOption: SortOption.name, foldersToTop: false);
|
||||
final desc = response.sortBy(
|
||||
sortOption: SortOption.name, foldersToTop: false, reversed: true);
|
||||
expect(desc, asc.reversed.toList());
|
||||
});
|
||||
|
||||
test('empty input yields an empty list', () {
|
||||
final response = ListFilesResponse({});
|
||||
expect(response.sortBy(), isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user