228 lines
7.1 KiB
Dart
228 lines
7.1 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:marianum_mobile/api/marianumcloud/search/search_chat_messages_response.dart';
|
|
import 'package:marianum_mobile/api/marianumcloud/talk/chat/get_chat_response.dart';
|
|
import 'package:marianum_mobile/api/marianumcloud/talk/room/get_room_response.dart';
|
|
import 'package:marianum_mobile/view/pages/talk/data/chat_message_matcher.dart';
|
|
|
|
GetChatResponseObject _msg({
|
|
required int id,
|
|
required int timestamp,
|
|
String actorDisplayName = 'Anyone',
|
|
String message = '',
|
|
String systemMessage = '',
|
|
GetRoomResponseObjectMessageType type =
|
|
GetRoomResponseObjectMessageType.comment,
|
|
Map<String, RichObjectString>? params,
|
|
}) => GetChatResponseObject(
|
|
id,
|
|
'token',
|
|
GetRoomResponseObjectMessageActorType.user,
|
|
'actor-id',
|
|
actorDisplayName,
|
|
timestamp,
|
|
systemMessage,
|
|
type,
|
|
true,
|
|
'',
|
|
message,
|
|
params,
|
|
null,
|
|
null,
|
|
null,
|
|
);
|
|
|
|
GetChatResponse _response(List<GetChatResponseObject> messages) =>
|
|
GetChatResponse(messages.toSet());
|
|
|
|
void main() {
|
|
group('ChatMessageMatcher.findMatches', () {
|
|
test('empty query returns no matches', () {
|
|
final response = _response([
|
|
_msg(id: 1, timestamp: 100, message: 'Hallo'),
|
|
]);
|
|
expect(ChatMessageMatcher.findMatches(response, ''), isEmpty);
|
|
expect(ChatMessageMatcher.findMatches(response, ' '), isEmpty);
|
|
});
|
|
|
|
test('matches message text case-insensitively', () {
|
|
final response = _response([
|
|
_msg(id: 1, timestamp: 100, message: 'Hallo Welt'),
|
|
_msg(id: 2, timestamp: 200, message: 'nichts hier'),
|
|
]);
|
|
final matches = ChatMessageMatcher.findMatches(response, 'WELT');
|
|
expect(matches.length, 1);
|
|
expect(matches.first.messageId, 1);
|
|
});
|
|
|
|
test('matches actor display name', () {
|
|
final response = _response([
|
|
_msg(
|
|
id: 1,
|
|
timestamp: 100,
|
|
actorDisplayName: 'Lisa Maier',
|
|
message: 'irgendwas',
|
|
),
|
|
_msg(
|
|
id: 2,
|
|
timestamp: 200,
|
|
actorDisplayName: 'Tom Weber',
|
|
message: 'auch was',
|
|
),
|
|
]);
|
|
final matches = ChatMessageMatcher.findMatches(response, 'lisa');
|
|
expect(matches.length, 1);
|
|
expect(matches.first.messageId, 1);
|
|
});
|
|
|
|
test('system messages match on text but not on actor', () {
|
|
final response = _response([
|
|
_msg(
|
|
id: 1,
|
|
timestamp: 100,
|
|
actorDisplayName: 'Lisa',
|
|
message: 'Lisa ist beigetreten',
|
|
type: GetRoomResponseObjectMessageType.system,
|
|
),
|
|
]);
|
|
// Match on text content
|
|
expect(ChatMessageMatcher.findMatches(response, 'beigetreten').length, 1);
|
|
// Actor name alone (not in text) should not match for system messages
|
|
final actorOnlyResponse = _response([
|
|
_msg(
|
|
id: 1,
|
|
timestamp: 100,
|
|
actorDisplayName: 'Lisa',
|
|
message: 'jemand ist beigetreten',
|
|
type: GetRoomResponseObjectMessageType.system,
|
|
),
|
|
]);
|
|
expect(
|
|
ChatMessageMatcher.findMatches(actorOnlyResponse, 'lisa'),
|
|
isEmpty,
|
|
);
|
|
});
|
|
|
|
test(
|
|
'reaction, poll_voted and message_deleted system messages are filtered out',
|
|
() {
|
|
final response = _response([
|
|
_msg(
|
|
id: 1,
|
|
timestamp: 100,
|
|
message: 'Treffer',
|
|
systemMessage: 'reaction',
|
|
type: GetRoomResponseObjectMessageType.system,
|
|
),
|
|
_msg(
|
|
id: 2,
|
|
timestamp: 200,
|
|
message: 'Treffer',
|
|
systemMessage: 'poll_voted',
|
|
type: GetRoomResponseObjectMessageType.system,
|
|
),
|
|
_msg(
|
|
id: 4,
|
|
timestamp: 250,
|
|
message: 'Treffer',
|
|
systemMessage: 'message_deleted',
|
|
type: GetRoomResponseObjectMessageType.system,
|
|
),
|
|
_msg(id: 3, timestamp: 300, message: 'Treffer'),
|
|
]);
|
|
final matches = ChatMessageMatcher.findMatches(response, 'Treffer');
|
|
expect(matches.length, 1);
|
|
expect(matches.first.messageId, 3);
|
|
},
|
|
);
|
|
|
|
test('rich object parameters are searchable (e.g. file names)', () {
|
|
final response = _response([
|
|
_msg(
|
|
id: 1,
|
|
timestamp: 100,
|
|
message: '{file}',
|
|
params: {
|
|
'file': RichObjectString(
|
|
RichObjectStringObjectType.file,
|
|
'42',
|
|
'hausaufgaben.pdf',
|
|
null,
|
|
null,
|
|
),
|
|
},
|
|
),
|
|
]);
|
|
final matches = ChatMessageMatcher.findMatches(response, 'hausaufgab');
|
|
expect(matches.length, 1);
|
|
expect(matches.first.messageId, 1);
|
|
});
|
|
|
|
test('matches are sorted newest first', () {
|
|
final response = _response([
|
|
_msg(id: 1, timestamp: 100, message: 'X'),
|
|
_msg(id: 2, timestamp: 300, message: 'X'),
|
|
_msg(id: 3, timestamp: 200, message: 'X'),
|
|
]);
|
|
final matches = ChatMessageMatcher.findMatches(response, 'x');
|
|
expect(matches.map((m) => m.messageId).toList(), [2, 3, 1]);
|
|
});
|
|
});
|
|
|
|
group('ChatMessageMatcher.merge', () {
|
|
test('dedupes by id preferring local hits, newest id first', () {
|
|
const local = [ChatSearchHit(messageId: 5, text: 'lokal')];
|
|
const server = [
|
|
ChatSearchHit(messageId: 9, text: 'neu'),
|
|
ChatSearchHit(messageId: 5, text: 'server'),
|
|
ChatSearchHit(messageId: 2, text: 'alt'),
|
|
];
|
|
final merged = ChatMessageMatcher.merge(local, server);
|
|
expect(merged.map((h) => h.messageId).toList(), [9, 5, 2]);
|
|
expect(merged[1].text, 'lokal');
|
|
});
|
|
});
|
|
|
|
group('SearchChatMessagesEntry.fromJson', () {
|
|
test('reads id and timestamp from attributes', () {
|
|
final entry = SearchChatMessagesEntry.fromJson({
|
|
'title': 'Lisa Maier',
|
|
'subline': 'Die Hausaufgabe ist bis Freitag',
|
|
'attributes': {
|
|
'messageId': '123',
|
|
'actorId': 'lmaier',
|
|
'timestamp': '1700000000',
|
|
},
|
|
}, term: 'hausaufgabe')!;
|
|
expect(entry.messageId, 123);
|
|
expect(entry.actorId, 'lmaier');
|
|
expect(entry.actorDisplayName, 'Lisa Maier');
|
|
expect(entry.excerpt, 'Die Hausaufgabe ist bis Freitag');
|
|
expect(entry.sentAt, DateTime.fromMillisecondsSinceEpoch(1700000000000));
|
|
});
|
|
|
|
test('detects excerpt in title and falls back to resourceUrl id', () {
|
|
final entry = SearchChatMessagesEntry.fromJson({
|
|
'title': '…die Hausaufgabe',
|
|
'subline': 'Lisa Maier',
|
|
'resourceUrl': 'https://cloud/index.php/call/abc#message_77',
|
|
}, term: 'hausaufgabe')!;
|
|
expect(entry.messageId, 77);
|
|
expect(entry.excerpt, '…die Hausaufgabe');
|
|
expect(entry.actorDisplayName, 'Lisa Maier');
|
|
expect(entry.sentAt, isNull);
|
|
});
|
|
|
|
test('entries without message id are dropped', () {
|
|
final response = SearchChatMessagesResponse.fromJson({
|
|
'isPaginated': true,
|
|
'cursor': 25,
|
|
'entries': [
|
|
{'title': 'x', 'subline': 'y'},
|
|
],
|
|
}, term: 'y');
|
|
expect(response.entries, isEmpty);
|
|
expect(response.cursor, isNull);
|
|
});
|
|
});
|
|
}
|