fix(tests): fix searchEmails FTS5 query, chaos monkey timeout, and format

_toFtsQuery was stripping non-word chars within tokens rather than
splitting on them — 'searchable-{timestamp}' became 'searchable{timestamp}*'
but FTS5 tokenizes on hyphens so the merged token never matched. Split on
non-word chars so each FTS token is queried separately.

chaos_monkey_test had no timeout annotation, hitting Dart's 30s default
for a test that needs ~60s with 30 SMTP/IMAP rounds. Added Timeout.none.

Also applied dart format to files from the merged main commit (#512) that
were committed without running the formatter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas SharedInbox
2026-06-07 02:21:23 +02:00
co-authored by Claude Sonnet 4.6
parent bbce46d0f2
commit 84e454dd7b
3 changed files with 15 additions and 25 deletions
@@ -2952,16 +2952,12 @@ class EmailRepositoryImpl implements EmailRepository {
String? mailboxPath, String? mailboxPath,
String query, String query,
) async { ) async {
final words = query final words =
.trim() query.trim().split(RegExp(r'\s+')).where((w) => w.isNotEmpty).toList();
.split(RegExp(r'\s+'))
.where((w) => w.isNotEmpty)
.toList();
if (words.isEmpty) return []; if (words.isEmpty) return [];
final noteConditions = words.map((_) => 'n.note_text LIKE ?').join(' AND '); final noteConditions = words.map((_) => 'n.note_text LIKE ?').join(' AND ');
final likeVars = final likeVars = words.map((w) => Variable<String>('%$w%')).toList();
words.map((w) => Variable<String>('%$w%')).toList();
final extraConditions = StringBuffer(); final extraConditions = StringBuffer();
final extraVars = <Variable<String>>[]; final extraVars = <Variable<String>>[];
@@ -2980,14 +2976,13 @@ class EmailRepositoryImpl implements EmailRepository {
' WHERE $noteConditions$extraConditions' ' WHERE $noteConditions$extraConditions'
' ORDER BY e.received_at DESC LIMIT 50'; ' ORDER BY e.received_at DESC LIMIT 50';
final rows = await _db final rows = await _db.customSelect(
.customSelect( sql,
sql, variables: [...likeVars, ...extraVars],
variables: [...likeVars, ...extraVars], readsFrom: {_db.emails, _db.emailNotes},
readsFrom: {_db.emails, _db.emailNotes}, ).get();
) final emailRows =
.get(); await Future.wait(rows.map((r) => _db.emails.mapFromRow(r)));
final emailRows = await Future.wait(rows.map((r) => _db.emails.mapFromRow(r)));
return emailRows.map(_toModel).toList(); return emailRows.map(_toModel).toList();
} }
@@ -2997,9 +2992,7 @@ class EmailRepositoryImpl implements EmailRepository {
static String _toFtsQuery(String query) { static String _toFtsQuery(String query) {
final words = query final words = query
.trim() .trim()
.split(RegExp(r'\s+')) .split(RegExp(r'[^\w]+'))
.where((w) => w.isNotEmpty)
.map((w) => w.replaceAll(RegExp(r'[^\w]'), ''))
.where((w) => w.isNotEmpty) .where((w) => w.isNotEmpty)
.toList(); .toList();
if (words.isEmpty) return ''; if (words.isEmpty) return '';
@@ -3124,8 +3117,7 @@ class EmailRepositoryImpl implements EmailRepository {
queryRows.map((r) => _db.emails.mapFromRow(r)), queryRows.map((r) => _db.emails.mapFromRow(r)),
); );
final noteRows = final noteRows = await _searchEmailsByNotes(accountId, mailboxPath, query);
await _searchEmailsByNotes(accountId, mailboxPath, query);
final seen = <String>{}; final seen = <String>{};
final merged = <model.Email>[]; final merged = <model.Email>[];
+1 -1
View File
@@ -132,7 +132,7 @@ void main() {
tearDown(() => db.close()); tearDown(() => db.close());
test('chaos monkey — random operations do not crash the repository', test('chaos monkey — random operations do not crash the repository',
() async { timeout: Timeout.none, () async {
final seedStr = _env('CHAOS_SEED'); final seedStr = _env('CHAOS_SEED');
final seed = seedStr.isEmpty final seed = seedStr.isEmpty
? DateTime.now().millisecondsSinceEpoch ? DateTime.now().millisecondsSinceEpoch
+2 -4
View File
@@ -514,8 +514,7 @@ void main() {
), ),
); );
final results = final results = await r.emails.searchEmailsGlobal(null, 'urgent');
await r.emails.searchEmailsGlobal(null, 'urgent');
expect(results, hasLength(1)); expect(results, hasLength(1));
expect(results.first.subject, 'Weekly report'); expect(results.first.subject, 'Weekly report');
}); });
@@ -569,8 +568,7 @@ void main() {
), ),
); );
final results = final results = await r.emails.searchEmails('acc-1', 'INBOX', 'client');
await r.emails.searchEmails('acc-1', 'INBOX', 'client');
expect(results, hasLength(1)); expect(results, hasLength(1));
expect(results.first.subject, 'Project update'); expect(results.first.subject, 'Project update');
expect(results.first.mailboxPath, 'INBOX'); expect(results.first.mailboxPath, 'INBOX');