109 lines
3.3 KiB
Dart
109 lines
3.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:mews/mews/document.dart';
|
|
import 'package:mews/mews/gemtext.dart';
|
|
|
|
const page = '''
|
|
# A capsule
|
|
|
|
Some opening text.
|
|
A second line of it.
|
|
|
|
## A section
|
|
|
|
* one
|
|
* two
|
|
|
|
=> index.gmi The index
|
|
=> retro.gmi 2026-10-08 Collecting retro phones
|
|
=> first.gmi 2026-09-21 First post
|
|
|
|
> a quoted line
|
|
> and another
|
|
|
|
```rust
|
|
fn main() {}
|
|
```
|
|
|
|
#### four hashes are text
|
|
''';
|
|
|
|
void main() {
|
|
test('gemtext converts to the document model', () {
|
|
final parsed = parseGemtextPage(source: page, url: 'gemini://capsule.example/index.gmi');
|
|
|
|
expect(parsed.url, 'gemini://capsule.example/index.gmi');
|
|
expect(parsed.specVersion, gemtextSpecVersion);
|
|
expect(parsed.isMews, isTrue);
|
|
expect(parsed.title, 'A capsule');
|
|
expect(parsed.direction, TextDirection.ltr);
|
|
|
|
final headings = parsed.body
|
|
.whereType<HeadingBlock>()
|
|
.map((h) => (h.level, (h.inline.single as MewsText).text))
|
|
.toList();
|
|
expect(headings, [
|
|
(1, 'A capsule'),
|
|
(2, 'A section'),
|
|
]);
|
|
|
|
// Each text line is its own paragraph.
|
|
final paragraphs = parsed.body.whereType<ParagraphBlock>().length;
|
|
expect(paragraphs, 3); // Two opening lines and the four-hashes line.
|
|
|
|
final lists = parsed.body.whereType<ListBlock>().toList();
|
|
expect(lists, hasLength(2));
|
|
expect(lists.first.items, hasLength(2));
|
|
expect(
|
|
((lists.first.items.first.blocks.single as ParagraphBlock).inline.single as MewsText).text,
|
|
'one');
|
|
|
|
// Consecutive link lines form one list, so a menu reads as a menu.
|
|
expect(lists.last.items, hasLength(3));
|
|
|
|
final quotes = parsed.body.whereType<QuoteBlock>().toList();
|
|
expect(quotes, hasLength(1));
|
|
expect(quotes.first.children, hasLength(2));
|
|
|
|
final pre = parsed.body.whereType<PreBlock>().single;
|
|
expect(pre.text, 'fn main() {}');
|
|
});
|
|
|
|
test('dated links become entries, resolved absolute', () {
|
|
final parsed = parseGemtextPage(source: page, url: 'gemini://capsule.example/index.gmi');
|
|
|
|
expect(
|
|
parsed.entries.map((e) => (e.url, e.date, e.title)).toList(),
|
|
[
|
|
('gemini://capsule.example/retro.gmi', DateTime(2026, 10, 8), 'Collecting retro phones'),
|
|
('gemini://capsule.example/first.gmi', DateTime(2026, 9, 21), 'First post'),
|
|
],
|
|
);
|
|
});
|
|
|
|
test('a link without a label shows its address', () {
|
|
final parsed = parseGemtextPage(
|
|
source: '=> gemini://else.example/x.gmi', url: 'gemini://capsule.example/');
|
|
|
|
final list = parsed.body.whereType<ListBlock>().single;
|
|
final link = ((list.items.single.blocks.single as ParagraphBlock).inline.single as MewsLink);
|
|
expect(link.href, 'gemini://else.example/x.gmi');
|
|
expect((link.children.single as MewsText).text, 'gemini://else.example/x.gmi');
|
|
});
|
|
|
|
test('an unterminated pre block keeps its lines', () {
|
|
final parsed = parseGemtextPage(
|
|
source: '```\nstill inside', url: 'gemini://capsule.example/');
|
|
|
|
expect(parsed.body.whereType<PreBlock>().single.text, 'still inside');
|
|
});
|
|
|
|
test('right-to-left text is written in its own direction', () {
|
|
final parsed = parseGemtextPage(
|
|
source: '# שלום\nטקסט בעברית', url: 'gemini://capsule.example/he.gmi');
|
|
|
|
expect(parsed.direction, TextDirection.rtl);
|
|
expect(parsed.lang, 'he');
|
|
expect(parsed.title, 'שלום');
|
|
});
|
|
}
|