291 lines
8.0 KiB
Dart
291 lines
8.0 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ikar/backend/modules/message_copy.dart';
|
|
import 'package:ikar/backend/modules/messages.dart';
|
|
import 'package:ikar/backend/modules/forward_sender.dart';
|
|
import 'package:ikar/models/attachment.dart';
|
|
|
|
CachedMessage _message({
|
|
String? text,
|
|
List<Map<String, dynamic>> attaches = const [],
|
|
List<Map<String, dynamic>> elements = const [],
|
|
Map<String, dynamic>? link,
|
|
int e2ee = CachedMessage.e2eeNone,
|
|
}) {
|
|
final payload = <String, dynamic>{
|
|
'id': 501,
|
|
'sender': 9,
|
|
'text': text,
|
|
'attaches': attaches,
|
|
'elements': elements,
|
|
'link': ?link,
|
|
};
|
|
final (attachments, isControl) = CachedMessage.parseAttachments(payload);
|
|
return CachedMessage(
|
|
id: '501',
|
|
accountId: 1,
|
|
chatId: 10,
|
|
senderId: 9,
|
|
text: text,
|
|
time: 1000,
|
|
status: 'sent',
|
|
payload: payload,
|
|
attachments: attachments,
|
|
isControl: isControl,
|
|
e2ee: e2ee,
|
|
);
|
|
}
|
|
|
|
ForwardRequest _request(List<CachedMessage> messages) => ForwardRequest(
|
|
sourceChatId: 10,
|
|
sourceChatName: 'Synthetic chat',
|
|
sourceChatIconUrl: '',
|
|
sourceChatType: 'CHAT',
|
|
messages: messages,
|
|
);
|
|
|
|
void main() {
|
|
group('MessageCopy', () {
|
|
test('keeps text and formatting', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
text: 'Synthetic bold text',
|
|
elements: [
|
|
{'type': 'STRONG', 'from': 10, 'length': 4},
|
|
],
|
|
),
|
|
)!;
|
|
|
|
expect(copy.text, 'Synthetic bold text');
|
|
expect(copy.elements, [
|
|
{'type': 'STRONG', 'from': 10, 'length': 4},
|
|
]);
|
|
expect(copy.wireAttaches, isEmpty);
|
|
});
|
|
|
|
test('drops the inline keyboard but keeps the rest of the message', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
text: 'Synthetic bot greeting',
|
|
attaches: [
|
|
{
|
|
'_type': 'INLINE_KEYBOARD',
|
|
'keyboard': {
|
|
'buttons': [
|
|
[
|
|
{'type': 'CALLBACK', 'text': 'Synthetic button'},
|
|
],
|
|
],
|
|
},
|
|
},
|
|
],
|
|
),
|
|
)!;
|
|
|
|
expect(copy.text, 'Synthetic bot greeting');
|
|
expect(copy.attaches, isEmpty);
|
|
expect(copy.wireAttaches, isEmpty);
|
|
});
|
|
|
|
test('has nothing to send when only a keyboard is left', () {
|
|
final message = _message(
|
|
text: '',
|
|
attaches: [
|
|
{'_type': 'INLINE_KEYBOARD', 'keyboard': const {}},
|
|
],
|
|
);
|
|
|
|
expect(MessageCopy.of(message), isNull);
|
|
});
|
|
|
|
test('refuses polls, calls and service messages', () {
|
|
for (final type in ['POLL', 'CALL', 'CONTROL']) {
|
|
final message = _message(
|
|
text: 'Synthetic',
|
|
attaches: [
|
|
{'_type': type},
|
|
],
|
|
);
|
|
expect(MessageCopy.of(message), isNull, reason: type);
|
|
}
|
|
});
|
|
|
|
test('refuses an attachment it does not know', () {
|
|
final message = _message(
|
|
attaches: [
|
|
{'_type': 'SYNTHETIC_FUTURE_TYPE'},
|
|
],
|
|
);
|
|
|
|
expect(MessageCopy.of(message), isNull);
|
|
});
|
|
|
|
test('refuses an encrypted message', () {
|
|
final message = _message(
|
|
text: 'Synthetic ciphertext',
|
|
e2ee: CachedMessage.e2eeText,
|
|
);
|
|
|
|
expect(MessageCopy.of(message), isNull);
|
|
});
|
|
|
|
test('refuses media it has no reference for', () {
|
|
final message = _message(
|
|
attaches: [
|
|
{'_type': 'PHOTO', 'baseUrl': 'https://example.test/p.jpg'},
|
|
],
|
|
);
|
|
|
|
expect(MessageCopy.of(message), isNull);
|
|
});
|
|
|
|
test('re-sends media by reference', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
text: 'Synthetic caption',
|
|
attaches: [
|
|
{
|
|
'_type': 'PHOTO',
|
|
'photoId': 1,
|
|
'photoToken': 'photo-token',
|
|
'baseUrl': 'https://example.test/p.jpg',
|
|
'width': 10,
|
|
'height': 10,
|
|
},
|
|
{'_type': 'VIDEO', 'videoId': 2, 'token': 'video-token'},
|
|
{'_type': 'FILE', 'fileId': 3, 'name': 'synthetic.pdf'},
|
|
{'_type': 'STICKER', 'stickerId': '4'},
|
|
{'_type': 'CONTACT', 'contactId': 5, 'name': 'Synthetic'},
|
|
{'_type': 'LOCATION', 'latitude': 1, 'longitude': 2.5},
|
|
{'_type': 'SHARE', 'url': 'https://example.test'},
|
|
],
|
|
),
|
|
)!;
|
|
|
|
expect(copy.text, 'Synthetic caption');
|
|
expect(copy.attaches, hasLength(6));
|
|
expect(copy.wireAttaches, [
|
|
{'_type': 'PHOTO', 'photoToken': 'photo-token'},
|
|
{'videoType': 0, '_type': 'VIDEO', 'token': 'video-token'},
|
|
{'_type': 'FILE', 'fileId': 3},
|
|
{'_type': 'STICKER', 'stickerId': 4},
|
|
{'_type': 'CONTACT', 'contactId': 5},
|
|
{'_type': 'LOCATION', 'latitude': 1.0, 'longitude': 2.5, 'zoom': 15.0},
|
|
]);
|
|
});
|
|
|
|
test('keeps the waveform of voice and video messages', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
attaches: [
|
|
{
|
|
'_type': 'AUDIO',
|
|
'audioId': 6,
|
|
'token': 'audio-token',
|
|
'duration': 3000,
|
|
'wave': [1, 2, 3],
|
|
},
|
|
{
|
|
'_type': 'VIDEO',
|
|
'videoType': 1,
|
|
'token': 'note-token',
|
|
'duration': 4000,
|
|
'thumbhash': 'synthetic-hash',
|
|
},
|
|
],
|
|
),
|
|
)!;
|
|
|
|
final voice = copy.wireAttaches[0];
|
|
expect(voice['token'], 'audio-token');
|
|
expect(voice['duration'], 3000);
|
|
expect(voice['wave'], Uint8List.fromList([1, 2, 3]));
|
|
|
|
final note = copy.wireAttaches[1];
|
|
expect(note['videoType'], 1);
|
|
expect(note['token'], 'note-token');
|
|
expect(note['duration'], 4000);
|
|
expect(note['thumbhash'], 'synthetic-hash');
|
|
expect(note['wave'], hasLength(80));
|
|
});
|
|
|
|
test('copies the original of a forwarded message', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
link: {
|
|
'type': 'FORWARD',
|
|
'chatId': -20,
|
|
'messageId': 77,
|
|
'message': {
|
|
'id': 77,
|
|
'sender': 42,
|
|
'text': 'Synthetic original',
|
|
'attaches': [
|
|
{'_type': 'PHOTO', 'photoToken': 'original-token'},
|
|
],
|
|
},
|
|
},
|
|
),
|
|
)!;
|
|
|
|
expect(copy.text, 'Synthetic original');
|
|
expect(copy.wireAttaches, [
|
|
{'_type': 'PHOTO', 'photoToken': 'original-token'},
|
|
]);
|
|
});
|
|
|
|
test('builds an outgoing message that renders right away', () {
|
|
final copy = MessageCopy.of(
|
|
_message(
|
|
text: 'Synthetic caption',
|
|
attaches: [
|
|
{'_type': 'PHOTO', 'photoToken': 'photo-token'},
|
|
],
|
|
),
|
|
)!;
|
|
|
|
final outgoing = copy.toOutgoing(
|
|
accountId: 1,
|
|
chatId: 30,
|
|
tempId: 'temp_1',
|
|
time: 2000,
|
|
);
|
|
|
|
expect(outgoing.id, 'temp_1');
|
|
expect(outgoing.chatId, 30);
|
|
expect(outgoing.senderId, 1);
|
|
expect(outgoing.text, 'Synthetic caption');
|
|
expect(outgoing.status, 'sending');
|
|
expect(outgoing.forwardedAttachment, isNull);
|
|
expect(outgoing.attachments!.single, isA<PhotoAttachment>());
|
|
});
|
|
});
|
|
|
|
group('ForwardRequest', () {
|
|
test('hides the sender only when every message can be copied', () {
|
|
final text = _message(text: 'Synthetic');
|
|
final poll = _message(
|
|
attaches: [
|
|
{'_type': 'POLL', 'title': 'Synthetic poll'},
|
|
],
|
|
);
|
|
|
|
expect(_request([text]).canHideSender, isTrue);
|
|
expect(_request([text, poll]).canHideSender, isFalse);
|
|
});
|
|
|
|
test('keeps the chosen mode while messages are sent one by one', () {
|
|
final request = _request([
|
|
_message(text: 'First'),
|
|
_message(text: 'Second'),
|
|
]).withHideSender(true);
|
|
|
|
final rest = request.withMessages([request.messages.last]);
|
|
|
|
expect(rest.hideSender, isTrue);
|
|
expect(rest.messages.single.text, 'Second');
|
|
});
|
|
});
|
|
}
|