This repository has been archived on 2026-10-23. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
halkyon_shared/packages/halkyon_interop/test/halkyon_interop_test.dart
Tizian 「ティツィアーン」 80fa7b9628
Halkyon's shared packages
A pub workspace of the Dart packages Halkyon's apps share: halkyon_ui,
Halkyon's look (the theme, fonts, layout and shared widgets, with texts
in English and German), halkyon_core's low-level primitives and
halkyon_interop's cross-app contracts. Dart 3.13 with LeanCode's lints,
configured once at the root; apps take a package by git, pinned to a
signed commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-18 21:50:15 +02:00

174 lines
4.9 KiB
Dart

import 'package:halkyon_interop/halkyon_interop.dart';
import 'package:test/test.dart';
void main() {
group('TaskShape', () {
final fixedTime = DateTime.utc(2026, 1, 15, 12);
final deepLink = Uri.parse('halkyon-learn://review/spanish-vocab');
TaskShape build({
String sourceAppId = 'eu.halkyon.learn',
String externalId = 'review-12',
String title = 'Review 12 cards',
String? subtitle = 'Spanish vocabulary',
DateTime? dueAt,
Uri? linkOverride,
}) => TaskShape(
sourceAppId: sourceAppId,
externalId: externalId,
title: title,
subtitle: subtitle,
dueAt: dueAt ?? fixedTime,
deepLink: linkOverride ?? deepLink,
);
test('exposes provided fields', () {
final task = build();
expect(task.sourceAppId, 'eu.halkyon.learn');
expect(task.externalId, 'review-12');
expect(task.title, 'Review 12 cards');
expect(task.subtitle, 'Spanish vocabulary');
expect(task.dueAt, fixedTime);
expect(task.deepLink, deepLink);
});
test('allows null for optional fields', () {
final task = TaskShape(
sourceAppId: 'eu.halkyon.learn',
externalId: 'review-12',
title: 'Review',
deepLink: deepLink,
);
expect(task.subtitle, isNull);
expect(task.dueAt, isNull);
});
test('two instances with identical fields are equal', () {
expect(build(), equals(build()));
expect(build().hashCode, equals(build().hashCode));
});
test('differs on any field change', () {
expect(build(), isNot(equals(build(title: 'Different'))));
expect(build(), isNot(equals(build(externalId: 'different-id'))));
expect(build(), isNot(equals(build(sourceAppId: 'eu.halkyon.todo'))));
expect(build(), isNot(equals(build(dueAt: DateTime.utc(2026, 2)))));
expect(
build(),
isNot(equals(build(linkOverride: Uri.parse('halkyon-todo://x')))),
);
});
test('toString includes identifying fields', () {
final str = build().toString();
expect(str, contains('eu.halkyon.learn'));
expect(str, contains('review-12'));
expect(str, contains('Review 12 cards'));
});
});
group('HalkyonEvent / ReviewDueEvent', () {
final fixedTime = DateTime.utc(2026, 1, 15, 12);
test('ReviewDueEvent is a HalkyonEvent', () {
final event = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
expect(event, isA<HalkyonEvent>());
});
test('exposes provided fields', () {
final event = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
expect(event.occurredAt, fixedTime);
expect(event.studysetId, 'spanish-vocab');
expect(event.dueCount, 12);
});
test('events with identical fields are equal', () {
final a = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
final b = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
expect(a, equals(b));
expect(a.hashCode, equals(b.hashCode));
});
test('differs on field changes', () {
final base = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
expect(
base,
isNot(
equals(
ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 13,
),
),
),
);
expect(
base,
isNot(
equals(
ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'french-vocab',
dueCount: 12,
),
),
),
);
});
test('switch on sealed type is exhaustive', () {
final HalkyonEvent event = ReviewDueEvent(
occurredAt: fixedTime,
studysetId: 'spanish-vocab',
dueCount: 12,
);
// If a new HalkyonEvent subtype is added without updating this switch,
// the analyzer/compiler will flag it. That's the value of `sealed`.
final description = switch (event) {
ReviewDueEvent(:final studysetId, :final dueCount) =>
'$dueCount cards due in $studysetId',
};
expect(description, '12 cards due in spanish-vocab');
});
});
group('DormantPublisher', () {
test('accepts publish calls without throwing', () async {
const publisher = DormantPublisher();
final event = ReviewDueEvent(
occurredAt: DateTime.utc(2026, 1, 15),
studysetId: 'spanish-vocab',
dueCount: 5,
);
await expectLater(publisher.publish(event), completes);
});
test('implements EventPublisher', () {
const publisher = DormantPublisher();
expect(publisher, isA<EventPublisher>());
});
});
}