Files
sync_replay_project/tool/test/changelog_test.dart
T
foxyzandClaude Opus 5.5 638a30e16c Changelog and What's new: CHANGELOG.md cut into each release, shown in the update band, a What's new card and once after updating
CHANGELOG.md keeps an Unreleased section (user-facing changes add a line in
the same commit); tool/release.sh cuts it into the version, the manifest
gets a structured "changes" field next to the one-line "notes" older
apps read, and the Gitea release text is that section. The app's update
band shows the top items, What's new opens a card (Added / Changed /
Fixed), and the first start after an update shows it once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 02:11:37 +03:00

86 lines
2.8 KiB
Dart

import 'dart:io';
import 'package:test/test.dart';
import '../changelog.dart';
const _sample = '''# Changelog
Intro text.
## Unreleased
Summary of the next one,
over two lines.
### Added
- Danmaku style notifications
+ Bilibili style chat box
that wraps
### Fixed
- Optimized relay
## 1.0.0
### Fixed
- Various bug fixes
''';
void main() {
test('parses sections, summaries, items and wrapped items', () {
final log = Changelog.parse(_sample);
expect(log.sections.map((s) => s.title), ['Unreleased', '1.0.0']);
final next = log.section('unreleased')!;
expect(next.summary, 'Summary of the next one, over two lines.');
expect(next.of('Added'), ['Danmaku style notifications', 'Bilibili style chat box that wraps']);
expect(next.of('Changed'), isEmpty);
expect(next.of('Fixed'), ['Optimized relay']);
expect(next.toManifest(), {
'notes': 'Summary of the next one, over two lines.',
'changes': {
'added': ['Danmaku style notifications', 'Bilibili style chat box that wraps'],
'changed': <String>[],
'fixed': ['Optimized relay'],
},
});
// No summary: the first items.
expect(log.section('1.0.0')!.notes, 'Various bug fixes');
});
test('cut: Unreleased becomes the version, a fresh empty one on top', () {
final cut = Changelog.parse(_sample).cutRelease('1.1.0');
final log = Changelog.parse(cut);
expect(log.sections.map((s) => s.title), ['Unreleased', '1.1.0', '1.0.0']);
expect(log.section('Unreleased')!.isEmpty, isTrue);
expect(log.section('1.1.0')!.of('Added'), hasLength(2));
expect(log.preamble, contains('Intro text.'));
expect(cut, contains(freshUnreleased));
// Nothing new: no release.
expect(() => log.cutRelease('1.2.0'), throwsStateError);
expect(() => Changelog.parse(_sample).cutRelease('1.0.0'), throwsStateError);
});
test('rejects unknown kinds and stray text', () {
expect(() => Changelog.parse('## 1.0.0\n\n### Removed\n\n- x\n'), throwsFormatException);
expect(() => Changelog.parse('## 1.0.0\n\n- no kind\n'), throwsFormatException);
expect(() => Changelog.parse('## 1.0.0\n\n### Fixed\n\nprose\n'), throwsFormatException);
});
test('release body: heading, summary, lists', () {
final body = Changelog.parse(_sample).section('unreleased')!.releaseBody('1.1.0');
expect(body, startsWith('## Starsync 1.1.0\n\nSummary of the next one'));
expect(body, contains('### Added\n\n- Danmaku style notifications\n'));
expect(body, isNot(contains('### Changed')));
});
test("the repo's CHANGELOG.md parses and has an Unreleased section", () {
final log = Changelog.parse(File('../CHANGELOG.md').readAsStringSync());
expect(log.sections.first.title, unreleased);
expect(log.section('1.3.0')!.of('Added'), isNotEmpty);
});
}