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:
co-authored by
Claude Sonnet 4.6
parent
bbce46d0f2
commit
84e454dd7b
@@ -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>[];
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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');
|
||||||
|
|||||||
Reference in New Issue
Block a user