Verhaltensgleich aus search_modal.dart herausgeloest (gleiche Deckel 1500/60/500, gleiche Schleife; Medien-Filter jetzt Parameter). Tests laufen ueber die echte SDK-DB-Schicht mit synthetischen Daten (test/support/synthetic_matrix_data.dart). Co-Authored-By: Claude Opus 5.5 <[email protected]>
110 lines
3.9 KiB
Dart
110 lines
3.9 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:matrix/matrix.dart';
|
||
import 'package:pyramid/features/search/local_message_search.dart';
|
||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||
|
||
import 'support/synthetic_matrix_data.dart';
|
||
|
||
/// Vertragstests für die lokale Nachrichtensuche (Suchdialog, Strg+K).
|
||
/// Laufen auf der echten SDK-Datenbankschicht mit normalem sqlite – die
|
||
/// Suche selbst ist von der Verschlüsselung unabhängig (die misst
|
||
/// `benchmark/db_benchmark_test.dart`).
|
||
void main() {
|
||
late Client client;
|
||
|
||
Future<void> setUpClient({
|
||
required int rooms,
|
||
required int eventsPerRoom,
|
||
int? needleEvery,
|
||
}) async {
|
||
final factory = createDatabaseFactoryFfi(
|
||
ffiInit: sqfliteFfiInit,
|
||
noIsolate: true,
|
||
);
|
||
final db = await factory.openDatabase(inMemoryDatabasePath);
|
||
client = await SyntheticMatrixData.openClient(
|
||
db,
|
||
name: 'PyramidSearchTest',
|
||
);
|
||
await SyntheticMatrixData.populate(
|
||
client,
|
||
rooms: rooms,
|
||
eventsPerRoom: eventsPerRoom,
|
||
needleEvery: needleEvery,
|
||
);
|
||
await SyntheticMatrixData.loadRooms(client);
|
||
}
|
||
|
||
tearDown(() async {
|
||
await client.dispose(closeDatabase: true);
|
||
});
|
||
|
||
test(
|
||
'findet genau die Nachrichten mit dem Suchwort, neueste zuerst',
|
||
() async {
|
||
// 3 Räume × 40 Nachrichten, jede 7. Text-Nachricht trägt das Suchwort.
|
||
// Jede 10. Nachricht ist ein Bild (ohne Suchwort im Dateinamen).
|
||
await setUpClient(rooms: 3, eventsPerRoom: 40, needleEvery: 7);
|
||
final expectedPerRoom = [
|
||
for (var i = 0; i < 40; i += 7) i,
|
||
].where((i) => i % 10 != 9).length;
|
||
|
||
final results = await localMessageSearch(client, 'nadelwort');
|
||
|
||
expect(results, hasLength(3 * expectedPerRoom));
|
||
expect(results.every((e) => e.body.contains('nadelwort')), isTrue);
|
||
for (var i = 1; i < results.length; i++) {
|
||
expect(
|
||
results[i - 1].originServerTs.isAfter(results[i].originServerTs) ||
|
||
results[i - 1].originServerTs == results[i].originServerTs,
|
||
isTrue,
|
||
reason: 'Ergebnisse müssen absteigend nach Zeit sortiert sein',
|
||
);
|
||
}
|
||
},
|
||
);
|
||
|
||
test('Groß-/Kleinschreibung egal, auch bei Umlauten', () async {
|
||
await setUpClient(rooms: 1, eventsPerRoom: 30, needleEvery: 3);
|
||
for (final (lowerQuery, upperQuery) in [
|
||
('nadelwort', 'NADELWORT'),
|
||
('übermorgen', 'ÜBERMORGEN'),
|
||
]) {
|
||
final lower = await localMessageSearch(client, lowerQuery);
|
||
final upper = await localMessageSearch(client, upperQuery);
|
||
expect(lower, isNotEmpty, reason: '"$lowerQuery" kommt in den Daten vor');
|
||
expect(upper.map((e) => e.eventId), lower.map((e) => e.eventId));
|
||
}
|
||
});
|
||
|
||
test(
|
||
'Medien-Filter liefert nur Medien-Nachrichten (Dateiname passt)',
|
||
() async {
|
||
await setUpClient(rooms: 2, eventsPerRoom: 30);
|
||
// "g" steckt in "IMG_…jpg" UND in vielen Textwörtern ("morgen", …).
|
||
final all = await localMessageSearch(client, 'g');
|
||
final media = await localMessageSearch(client, 'g', mediaOnly: true);
|
||
expect(
|
||
all.any((e) => e.content['msgtype'] == 'm.text'),
|
||
isTrue,
|
||
reason: 'ohne Filter müssen auch Text-Treffer kommen',
|
||
);
|
||
// Jede 10. Nachricht ist ein Bild: i = 9, 19, 29 → 3 pro Raum.
|
||
expect(media, hasLength(6));
|
||
expect(media.every((e) => e.content['msgtype'] == 'm.image'), isTrue);
|
||
},
|
||
);
|
||
|
||
test('Trefferzahl ist auf searchTotalCap gedeckelt', () async {
|
||
// Jede Nachricht trägt das Suchwort → weit mehr Treffer als der Deckel.
|
||
await setUpClient(rooms: 2, eventsPerRoom: 80, needleEvery: 1);
|
||
final results = await localMessageSearch(client, 'nadelwort');
|
||
expect(results, hasLength(searchTotalCap));
|
||
});
|
||
|
||
test('kein Treffer → leere Liste, kein Fehler', () async {
|
||
await setUpClient(rooms: 2, eventsPerRoom: 20);
|
||
expect(await localMessageSearch(client, 'gibtsnicht'), isEmpty);
|
||
});
|
||
}
|