import 'package:flutter_test/flutter_test.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_search_controller.dart'; GetChatResponseObject _msg({ required int id, required int timestamp, String actorDisplayName = 'Anyone', String message = '', String systemMessage = '', GetRoomResponseObjectMessageType type = GetRoomResponseObjectMessageType.comment, Map? params, }) => GetChatResponseObject( id, 'token', GetRoomResponseObjectMessageActorType.user, 'actor-id', actorDisplayName, timestamp, systemMessage, type, true, '', message, params, null, null, null, ); GetChatResponse _response(List messages) => GetChatResponse(messages.toSet()); void main() { group('ChatSearchController.findMatches', () { test('empty query returns no matches', () { final response = _response([ _msg(id: 1, timestamp: 100, message: 'Hallo'), ]); expect(ChatSearchController.findMatches(response, ''), isEmpty); expect(ChatSearchController.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 = ChatSearchController.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 = ChatSearchController.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( ChatSearchController.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( ChatSearchController.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 = ChatSearchController.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 = ChatSearchController.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 = ChatSearchController.findMatches(response, 'x'); expect(matches.map((m) => m.messageId).toList(), [2, 3, 1]); }); }); }