chore: Halkyon Learn moves into apps/learn
Its server, client, app and curator, and the tools that write its assets (maps, Anki fixtures, icons), as they are; paths are fixed in the commits that follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
11abd9afce
commit
649499be23
1 changed files with 0 additions and 0 deletions
|
|
@ -0,0 +1,80 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/note/model/note_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/note/model/note_merge.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/note/model/note_revision.dart';
|
||||
|
||||
/// Rich content holding just [text], enough to tell versions apart.
|
||||
RichContent text(String text) => RichContent({
|
||||
'document': {'type': 'page', 'note': text},
|
||||
});
|
||||
|
||||
NoteContent note(String title, String body) =>
|
||||
NoteContent(title: title, body: text(body));
|
||||
|
||||
/// A revision with the id [id] (ids sort by creation, like UUID v7).
|
||||
NoteRevision revision(
|
||||
String id,
|
||||
NoteContent content, {
|
||||
Set<String> parents = const {},
|
||||
}) => NoteRevision(id: id, parents: parents, content: content);
|
||||
|
||||
void main() {
|
||||
test('the newest revision of a chain is the current one', () {
|
||||
final merged = mergeNoteRevisions([
|
||||
revision('r1', note('Particles', 'は marks the topic')),
|
||||
revision('r2', note('Particles', 'は and が'), parents: {'r1'}),
|
||||
])!;
|
||||
|
||||
expect(merged.content, note('Particles', 'は and が'));
|
||||
expect(merged.heads, {'r2'});
|
||||
expect(merged.conflicts, isEmpty);
|
||||
});
|
||||
|
||||
test('a title changed on one device and the body on another both '
|
||||
'survive', () {
|
||||
final merged = mergeNoteRevisions([
|
||||
revision('r1', note('Particles', 'は marks the topic')),
|
||||
revision('r2', note('は and が', 'は marks the topic'), parents: {'r1'}),
|
||||
revision('r3', note('Particles', 'は and が'), parents: {'r1'}),
|
||||
])!;
|
||||
|
||||
expect(merged.content, note('は and が', 'は and が'));
|
||||
expect(merged.conflicts, isEmpty);
|
||||
});
|
||||
|
||||
test('a body changed differently on two devices is a conflict with both '
|
||||
'versions, the newest showing', () {
|
||||
final merged = mergeNoteRevisions([
|
||||
revision('r1', note('Particles', 'は marks the topic')),
|
||||
revision('r2', note('Particles', 'は: topic'), parents: {'r1'}),
|
||||
revision('r3', note('Particles', 'が: subject'), parents: {'r1'}),
|
||||
])!;
|
||||
|
||||
expect(merged.conflicts, {
|
||||
NoteField.body: [text('は: topic'), text('が: subject')],
|
||||
});
|
||||
expect(merged.content.body, text('が: subject'));
|
||||
expect(merged.heads, {'r2', 'r3'});
|
||||
});
|
||||
|
||||
test('without revisions there is no note', () {
|
||||
expect(mergeNoteRevisions(const []), isNull);
|
||||
});
|
||||
|
||||
group('NoteContent', () {
|
||||
test('is blank with neither title nor text', () {
|
||||
expect(NoteContent.empty().isBlank, isTrue);
|
||||
expect(note(' ', '').isBlank, isTrue);
|
||||
expect(note('Particles', '').isBlank, isFalse);
|
||||
expect(
|
||||
NoteContent(body: RichContent.plain('は')).isBlank,
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('is stored with its title trimmed', () {
|
||||
expect(note(' Particles ', 'は').normalized, note('Particles', 'は'));
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue