about summary refs log tree commit diff
path: root/nixpkgs/pkgs/tools/nix/nixos-render-docs/src/tests/test_plugins.py
blob: 8564297efdd3aac78c2c84737578f24d9146f24a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
import nixos_render_docs as nrd
import pytest

from markdown_it.token import Token

class Converter(nrd.md.Converter[nrd.docbook.DocBookRenderer]):
    # actual renderer doesn't matter, we're just parsing.
    def __init__(self, manpage_urls: dict[str, str]) -> None:
        super().__init__()
        self._renderer = nrd.docbook.DocBookRenderer(manpage_urls)

def test_attr_span_parsing() -> None:
    c = Converter({})
    assert c._parse("[]{#test}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[]{#test}',
              markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'test'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("[]{.test}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[]{.test}',
              markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'class': 'test'}, map=None,
                        level=0, children=None, content='', markup='', info='', meta={}, block=False,
                        hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("[]{.test1 .test2 #foo .test3 .test4}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='[]{.test1 .test2 #foo .test3 .test4}',
              markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='attr_span_begin', tag='span', nesting=1,
                        attrs={'class': 'test1 test2 test3 test4', 'id': 'foo'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("[]{#a #a}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='[]{#a #a}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='[]{#a #a}', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("[]{foo}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='[]{foo}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='[]{foo}', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_attr_span_formatted() -> None:
    c = Converter({})
    assert c._parse("a[b c `d` ***e***]{#test}f") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='a[b c `d` ***e***]{#test}f', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0,
                        children=None, content='a', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'test'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content='b c ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='code_inline', tag='code', nesting=0, attrs={}, map=None, level=1,
                        children=None, content='d', markup='`', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content=' ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=1, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
                        content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='strong_open', tag='strong', nesting=1, attrs={}, map=None, level=2,
                        children=None, content='', markup='**', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=3, children=None,
                        content='e', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='strong_close', tag='strong', nesting=-1, attrs={}, map=None, level=2,
                        children=None, content='', markup='**', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
                        content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=1, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='f', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_attr_span_in_heading() -> None:
    c = Converter({})
    # inline anchors in headers are allowed, but header attributes should be preferred
    assert c._parse("# foo []{#bar} baz") == [
        Token(type='heading_open', tag='h1', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='foo []{#bar} baz', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='foo ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                   Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                         children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content=' baz', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False)
    ]

def test_attr_span_on_links() -> None:
    c = Converter({})
    assert c._parse("[ [a](#bar) ]{#foo}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1, content='[ [a](#bar) ]{#foo}',
              markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'foo'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content=' ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='link_open', tag='a', nesting=1, attrs={'href': '#bar'}, map=None, level=1,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
                        content='a', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='link_close', tag='a', nesting=-1, attrs={}, map=None, level=1, children=None,
                        content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content=' ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_attr_span_nested() -> None:
    # inline anchors may contain more anchors (even though this is a bit pointless)
    c = Converter({})
    assert c._parse("[ [a]{#bar} ]{#foo}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='[ [a]{#bar} ]{#foo}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'foo'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content=' ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=1,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=2, children=None,
                        content='a', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=1,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content=' ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_attr_span_escaping() -> None:
    c = Converter({})
    assert c._parse("\\[a]{#bar}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='[a]{#bar}', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("\\\\[a]{#bar}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='\\\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='\\', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_begin', tag='span', nesting=1, attrs={'id': 'bar'}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content='a', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='attr_span_end', tag='span', nesting=-1, attrs={}, map=None, level=0,
                        children=None, content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("\\\\\\[a]{#bar}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='\\[a]{#bar}', markup='', info='', meta={}, block=False, hidden=False)
              ],
              content='\\\\\\[a]{#bar}', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_inline_comment_basic() -> None:
    c = Converter({})
    assert c._parse("a <!-- foo --><!----> b") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='a <!-- foo --><!----> b', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a  b', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("a<!-- b -->") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='a<!-- b -->', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_inline_comment_does_not_nest_in_code() -> None:
    c = Converter({})
    assert c._parse("`a<!-- b -->c`") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='`a<!-- b -->c`', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='code_inline', tag='code', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a<!-- b -->c', markup='`', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_inline_comment_does_not_nest_elsewhere() -> None:
    c = Converter({})
    assert c._parse("*a<!-- b -->c*") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='*a<!-- b -->c*', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=0, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content='ac', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=0, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_inline_comment_can_be_escaped() -> None:
    c = Converter({})
    assert c._parse("a\\<!-- b -->c") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='a\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a<!-- b -->c', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("a\\\\<!-- b -->c") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a\\c', markup='', info='', meta={}, block=False, hidden=False)
              ],
              content='a\\\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("a\\\\\\<!-- b -->c") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='a\\<!-- b -->c', markup='', info='', meta={}, block=False, hidden=False)
              ],
              content='a\\\\\\<!-- b -->c', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]

def test_block_comment() -> None:
    c = Converter({})
    assert c._parse("<!-- a -->") == []
    assert c._parse("<!-- a\n-->") == []
    assert c._parse("<!--\na\n-->") == []
    assert c._parse("<!--\n\na\n\n-->") == []
    assert c._parse("<!--\n\n```\n\n\n```\n\n-->") == []

def test_heading_attributes() -> None:
    c = Converter({})
    assert c._parse("# foo *bar* {#hid}") == [
        Token(type='heading_open', tag='h1', nesting=1, attrs={'id': 'hid'}, map=[0, 1], level=0,
              children=None, content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='foo *bar* {#hid}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='foo ', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='em_open', tag='em', nesting=1, attrs={}, map=None, level=0, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=1, children=None,
                        content='bar', markup='', info='', meta={}, block=False, hidden=False),
                  Token(type='em_close', tag='em', nesting=-1, attrs={}, map=None, level=0, children=None,
                        content='', markup='*', info='', meta={}, block=False, hidden=False),
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("# foo--bar {#id-with--double-dashes}") == [
        Token(type='heading_open', tag='h1', nesting=1, attrs={'id': 'id-with--double-dashes'}, map=[0, 1],
              level=0, children=None, content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='foo--bar {#id-with--double-dashes}', markup='', info='', meta={}, block=True,
              hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='foo–bar', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='heading_close', tag='h1', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False)
    ]

def test_admonitions() -> None:
    c = Converter({})
    assert c._parse("::: {.note}") == [
        Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup=':::', info=' {.note}', meta={'kind': 'note'}, block=True,
              hidden=False),
        Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.caution}") == [
        Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup=':::', info=' {.caution}', meta={'kind': 'caution'},
              block=True, hidden=False),
        Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.tip}") == [
        Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup=':::', info=' {.tip}', meta={'kind': 'tip'}, block=True,
              hidden=False),
        Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.important}") == [
        Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup=':::', info=' {.important}', meta={'kind': 'important'},
              block=True, hidden=False),
        Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.warning}") == [
        Token(type='admonition_open', tag='div', nesting=1, attrs={}, map=[0, 1], level=0,
              children=None, content='', markup=':::', info=' {.warning}', meta={'kind': 'warning'},
              block=True, hidden=False),
        Token(type='admonition_close', tag='div', nesting=-1, attrs={}, map=None, level=0,
              children=None, content='', markup=':::', info='', meta={}, block=True, hidden=False)
    ]

def test_example() -> None:
    c = Converter({})
    assert c._parse("::: {.example}\n# foo") == [
        Token(type='example_open', tag='div', nesting=1, attrs={}, map=[0, 2], level=0, children=None,
              content='', markup=':::', info=' {.example}', meta={}, block=True, hidden=False),
        Token(type='example_title_open', tag='h1', nesting=1, attrs={}, map=[1, 2], level=1, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[1, 2], level=2,
              content='foo', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='foo', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='example_title_close', tag='h1', nesting=-1, attrs={}, map=None, level=1, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='example_close', tag='div', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {#eid .example}\n# foo") == [
        Token(type='example_open', tag='div', nesting=1, attrs={'id': 'eid'}, map=[0, 2], level=0,
              children=None, content='', markup=':::', info=' {#eid .example}', meta={}, block=True,
              hidden=False),
        Token(type='example_title_open', tag='h1', nesting=1, attrs={}, map=[1, 2], level=1, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[1, 2], level=2,
              content='foo', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='foo', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='example_title_close', tag='h1', nesting=-1, attrs={}, map=None, level=1, children=None,
              content='', markup='#', info='', meta={}, block=True, hidden=False),
        Token(type='example_close', tag='div', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.example .note}") == [
        Token(type='paragraph_open', tag='p', nesting=1, attrs={}, map=[0, 1], level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, attrs={}, map=[0, 1], level=1,
              content='::: {.example .note}', markup='', info='', meta={}, block=True, hidden=False,
              children=[
                  Token(type='text', tag='', nesting=0, attrs={}, map=None, level=0, children=None,
                        content='::: {.example .note}', markup='', info='', meta={}, block=False, hidden=False)
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, attrs={}, map=None, level=0, children=None,
              content='', markup='', info='', meta={}, block=True, hidden=False)
    ]
    assert c._parse("::: {.example}\n### foo: `code`\nbar\n:::\nbaz") == [
        Token(type='example_open', tag='div', nesting=1, map=[0, 3], markup=':::', info=' {.example}',
              block=True),
        Token(type='example_title_open', tag='h3', nesting=1, map=[1, 2], level=1, markup='###', block=True),
        Token(type='inline', tag='', nesting=0, map=[1, 2], level=2, content='foo: `code`', block=True,
              children=[
                  Token(type='text', tag='', nesting=0, content='foo: '),
                  Token(type='code_inline', tag='code', nesting=0, content='code', markup='`')
              ]),
        Token(type='example_title_close', tag='h3', nesting=-1, level=1, markup='###', block=True),
        Token(type='paragraph_open', tag='p', nesting=1, map=[2, 3], level=1, block=True),
        Token(type='inline', tag='', nesting=0, map=[2, 3], level=2, content='bar', block=True,
              children=[
                  Token(type='text', tag='', nesting=0, content='bar')
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, level=1, block=True),
        Token(type='example_close', tag='div', nesting=-1, markup=':::', block=True),
        Token(type='paragraph_open', tag='p', nesting=1, map=[4, 5], block=True),
        Token(type='inline', tag='', nesting=0, map=[4, 5], level=1, content='baz', block=True,
              children=[
                  Token(type='text', tag='', nesting=0, content='baz')
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, block=True)
    ]

    with pytest.raises(RuntimeError) as exc:
        c._parse("::: {.example}\n### foo\n### bar\n:::")
    assert exc.value.args[0] == 'unexpected non-title heading in example in line 3'

def test_footnotes() -> None:
    c = Converter({})
    assert c._parse("text [^foo]\n\n[^foo]: bar") == [
        Token(type='paragraph_open', tag='p', nesting=1, map=[0, 1], block=True),
        Token(type='inline', tag='', nesting=0, map=[0, 1], level=1, content='text [^foo]', block=True,
              children=[
                  Token(type='text', tag='', nesting=0, content='text '),
                  Token(type='footnote_ref', tag='', nesting=0, attrs={'id': 'foo.__back.0'},
                        meta={'id': 0, 'subId': 0, 'label': 'foo', 'target': 'foo'})
              ]),
        Token(type='paragraph_close', tag='p', nesting=-1, block=True),
        Token(type='footnote_block_open', tag='', nesting=1),
        Token(type='footnote_open', tag='', nesting=1, attrs={'id': 'foo'}, meta={'id': 0, 'label': 'foo'}),
        Token(type='paragraph_open', tag='p', nesting=1, map=[2, 3], level=1, block=True, hidden=False),
        Token(type='inline', tag='', nesting=0, map=[2, 3], level=2, content='bar', block=True,
              children=[
                  Token(type='text', tag='', nesting=0, content='bar')
              ]),
        Token(type='footnote_anchor', tag='', nesting=0,
              meta={'id': 0, 'label': 'foo', 'subId': 0, 'target': 'foo.__back.0'}),
        Token(type='paragraph_close', tag='p', nesting=-1, level=1, block=True),
        Token(type='footnote_close', tag='', nesting=-1),
        Token(type='footnote_block_close', tag='', nesting=-1),
    ]