Files
rely/test/features/ai_digest/anonymized_llm_context_builder_test.dart
T
2026-05-18 20:33:54 +02:00

113 lines
4.4 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:relationship_saver/app/state/local_data_state.dart';
import 'package:relationship_saver/features/ai_digest/application/anonymized_llm_context_builder.dart';
import 'package:relationship_saver/features/ai_digest/domain/ai_digest_models.dart';
import 'package:relationship_saver/features/dashboard/domain/dashboard_models.dart';
import 'package:relationship_saver/features/ideas/domain/idea_models.dart';
import 'package:relationship_saver/features/moments/domain/moment_models.dart';
import 'package:relationship_saver/features/people/domain/person_models.dart';
import 'package:relationship_saver/features/reminders/domain/reminder_models.dart';
import 'package:relationship_saver/features/share_intake/domain/share_models.dart';
void main() {
test('builds pseudonymous payload without identifiable profile data', () {
final LocalDataState state = LocalDataState(
people: <PersonProfile>[
PersonProfile(
id: 'p-1',
name: 'Alice Secret',
relationship: 'Sister',
affinityScore: 85,
nextMoment: DateTime(2026, 6, 1),
tags: const <String>['coffee', 'books'],
notes: 'Passport number and private address should stay local.',
aliases: const <String>['Ally'],
location: 'Zurich, Switzerland',
lastInteractedAt: DateTime(2026, 5, 1),
),
],
moments: const <RelationshipMoment>[],
ideas: const <RelationshipIdea>[],
reminders: const <ReminderRule>[],
tasks: const <DashboardTask>[],
sourceLinks: <SourceProfileLink>[
SourceProfileLink(
id: 'sl-1',
sourceApp: 'whatsapp',
normalizedDisplayName: 'Alice Secret',
profileId: 'p-1',
firstSeenAt: DateTime(2026, 5, 1),
lastSeenAt: DateTime(2026, 5, 1),
sourceUserId: 'wa:alice',
sourceThreadId: 'thread-secret',
sourceFingerprint: 'whatsapp|u:wa:alice',
),
],
sharedMessages: <SharedMessageEntry>[
SharedMessageEntry(
id: 'sm-1',
profileId: 'p-1',
payload: SharedPayload(
sourceApp: 'whatsapp',
payloadType: SharedPayloadType.text,
rawText: 'Raw private chat text',
createdAt: DateTime(2026, 5, 1),
receivedAt: DateTime(2026, 5, 1),
platform: 'ios',
sourceDisplayName: 'Alice Secret',
sourceUserId: 'wa:alice',
sourceThreadId: 'thread-secret',
),
importedAt: DateTime(2026, 5, 1),
resolvedAutomatically: true,
),
],
personFacts: <PersonFact>[
PersonFact(
id: 'pf-1',
personId: 'p-1',
type: CapturedFactType.note,
text: 'Secret medical detail',
sourceKind: CaptureSourceKind.manual,
createdAt: DateTime(2026, 5, 1),
updatedAt: DateTime(2026, 5, 1),
isSensitive: true,
),
],
aiSuggestionDrafts: <AiSuggestionDraft>[
AiSuggestionDraft(
id: 'ai-1',
personId: 'p-1',
kind: AiSuggestionKind.eventIdea,
title: 'Jazz concert downtown',
details: 'Should not need to repeat the details.',
suggestedAt: DateTime(2026, 5, 10),
confidence: 0.8,
status: AiSuggestionStatus.dismissed,
sourceRunId: 'digest-old',
),
],
);
final AnonymizedLlmDigestContext context = AnonymizedLlmContextBuilder(
now: () => DateTime(2026, 5, 16),
).build(state);
final String prompt = context.toPromptJson();
expect(context.tokenToPersonId, <String, String>{'person_001': 'p-1'});
expect(prompt, contains('person_001'));
expect(prompt, isNot(contains('Alice')));
expect(prompt, isNot(contains('Ally')));
expect(prompt, isNot(contains('Zurich')));
expect(prompt, isNot(contains('Passport')));
expect(prompt, isNot(contains('wa:alice')));
expect(prompt, isNot(contains('thread-secret')));
expect(prompt, isNot(contains('Raw private chat text')));
expect(prompt, isNot(contains('Secret medical detail')));
expect(prompt, contains('priorSuggestions'));
expect(prompt, contains('jazz concert downtown'));
expect(prompt, contains('dismissed'));
expect(prompt, isNot(contains('Should not need to repeat the details.')));
});
}