Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
165 lines
5.0 KiB
Dart
165 lines
5.0 KiB
Dart
import 'dart:io';
|
||
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:qlyra/core/share/share_labels.dart';
|
||
import 'package:qlyra/models/shared_payload.dart';
|
||
|
||
late Directory _dir;
|
||
|
||
String _makeFile(String name, {int bytes = 8}) {
|
||
final file = File('${_dir.path}${Platform.pathSeparator}$name')
|
||
..writeAsBytesSync(List<int>.filled(bytes, 0x41));
|
||
return file.path;
|
||
}
|
||
|
||
Map<String, Object?> _entry(String path, String mime, {int size = 8}) => {
|
||
'path': path,
|
||
'name': path.split(Platform.pathSeparator).last,
|
||
'mime': mime,
|
||
'size': size,
|
||
};
|
||
|
||
void main() {
|
||
setUp(() {
|
||
_dir = Directory.systemTemp.createTempSync('synthetic_share_test');
|
||
addTearDown(() {
|
||
if (_dir.existsSync()) _dir.deleteSync(recursive: true);
|
||
});
|
||
});
|
||
|
||
group('SharedPayload.fromMap', () {
|
||
test('classifies photos, videos and documents by mime', () {
|
||
final payload = SharedPayload.fromMap({
|
||
'files': [
|
||
_entry(_makeFile('a.jpg'), 'image/jpeg'),
|
||
_entry(_makeFile('b.mp4'), 'video/mp4'),
|
||
_entry(_makeFile('c.pdf'), 'application/pdf'),
|
||
],
|
||
'text': null,
|
||
});
|
||
|
||
expect(payload, isNotNull);
|
||
expect(payload!.photos.map((f) => f.name), ['a.jpg']);
|
||
expect(payload.videos.map((f) => f.name), ['b.mp4']);
|
||
expect(payload.documents.map((f) => f.name), ['c.pdf']);
|
||
expect(payload.dominantKind, SharedFileKind.file);
|
||
});
|
||
|
||
test('an svg is a document, not a photo', () {
|
||
final payload = SharedPayload.fromMap({
|
||
'files': [_entry(_makeFile('d.svg'), 'image/svg+xml')],
|
||
});
|
||
|
||
expect(payload!.files.single.kind, SharedFileKind.file);
|
||
});
|
||
|
||
test('drops entries whose file is gone', () {
|
||
final payload = SharedPayload.fromMap({
|
||
'files': [
|
||
_entry(_makeFile('present.jpg'), 'image/jpeg'),
|
||
_entry('${_dir.path}/missing.jpg', 'image/jpeg'),
|
||
],
|
||
});
|
||
|
||
expect(payload!.files.map((f) => f.name), ['present.jpg']);
|
||
});
|
||
|
||
test('a text-only share survives with no files', () {
|
||
final payload = SharedPayload.fromMap({
|
||
'files': const [],
|
||
'text': ' https://qlyra.pw ',
|
||
});
|
||
|
||
expect(payload!.isTextOnly, isTrue);
|
||
expect(payload.text, 'https://qlyra.pw');
|
||
});
|
||
|
||
test('an empty share is rejected', () {
|
||
expect(SharedPayload.fromMap({'files': const [], 'text': ' '}), isNull);
|
||
expect(SharedPayload.fromMap(null), isNull);
|
||
expect(SharedPayload.fromMap('nonsense'), isNull);
|
||
});
|
||
|
||
test('a missing mime falls back to a document', () {
|
||
final payload = SharedPayload.fromMap({
|
||
'files': [
|
||
{'path': _makeFile('e.bin'), 'name': 'e.bin', 'size': 8},
|
||
],
|
||
});
|
||
|
||
expect(payload!.files.single.mime, 'application/octet-stream');
|
||
expect(payload.files.single.kind, SharedFileKind.file);
|
||
});
|
||
});
|
||
|
||
group('shareTitleFor', () {
|
||
test('photos use Russian plural forms', () {
|
||
expect(
|
||
shareTitleFor(photos: 1, videos: 0, documents: 0),
|
||
'Отправить фотографию',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 3, videos: 0, documents: 0),
|
||
'Отправить 3 фотографии',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 5, videos: 0, documents: 0),
|
||
'Отправить 5 фотографий',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 11, videos: 0, documents: 0),
|
||
'Отправить 11 фотографий',
|
||
);
|
||
});
|
||
|
||
test('videos stay uninflected', () {
|
||
expect(
|
||
shareTitleFor(photos: 0, videos: 1, documents: 0),
|
||
'Отправить видео',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 0, videos: 2, documents: 0),
|
||
'Отправить 2 видео',
|
||
);
|
||
});
|
||
|
||
test('documents and mixed sets fall back to file wording', () {
|
||
expect(
|
||
shareTitleFor(photos: 0, videos: 0, documents: 1),
|
||
'Отправить файл',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 0, videos: 0, documents: 4),
|
||
'Отправить 4 файла',
|
||
);
|
||
expect(
|
||
shareTitleFor(photos: 1, videos: 1, documents: 0),
|
||
'Отправить 2 файла',
|
||
);
|
||
});
|
||
|
||
test('a text share has no media wording', () {
|
||
expect(
|
||
shareTitleFor(photos: 0, videos: 0, documents: 0, textOnly: true),
|
||
'Отправить сообщение',
|
||
);
|
||
});
|
||
});
|
||
|
||
group('shareSubtitleFor', () {
|
||
test('names are listed up to two recipients', () {
|
||
expect(shareSubtitleFor(const ['ЛУКА']), 'В чат ЛУКА');
|
||
expect(shareSubtitleFor(const ['ЛУКА', 'Zarub']), 'В чат ЛУКА, Zarub');
|
||
});
|
||
|
||
test('three or more recipients collapse to a count', () {
|
||
expect(shareSubtitleFor(const ['a', 'b', 'c']), 'В 3 чата');
|
||
expect(shareSubtitleFor(List.filled(5, 'x')), 'В 5 чатов');
|
||
});
|
||
|
||
test('an empty selection asks for one', () {
|
||
expect(shareSubtitleFor(const []), 'Выберите чат');
|
||
});
|
||
});
|
||
}
|