#![cfg(test)]
use rstest::rstest;
mod line_wrapping_issues;
mod list;
mod table;
mod text_formatting;
#[rstest(input,
case("---"),
case(
r#"word1 word2"#),
case(
r#"paragraph1
paragraph2"#),
case(
r#"# heading1
## heading2
heading 3
=========="#),
// case( "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."),
case(r#" 100. item1 paragraph1
item1 paragraph2
101. item2 paragraph1
item2 paragraph2
item2 paragraph3
102. item3 paragraph1
item3 paragraph2"#),
case(
r#" 1. item 1
* nested list item 1
* nested list item 2
2. item 2"#),
case(
r#"> line1 line1 line1 line1 line1 line1 line1 line1 line1 line1 line1 line1 line1
> line1 line1 line1 line1 line1 line1 line1 line1"#),
case(
r#"> line1 line1 line1 line1 line1 line1 line1 line1 line1 line1 line1 line1
>
> > line1 line1 line1 line1 line1 line1 line1 line1 line1"#),
case(
r#"Это *курсив, но внутри **жирный и *обратно курсив*** снова жирный* конец."#),
case(
r#"Это \*не курсив\*, а просто звёздочки."#),
case(
r#"Вот [ссылка *с курсивом внутри*](https://example.com) и ещё текст."#),
case(
r#"Инлайн код `внутри *курсива*` не должен парситься как курсив."#),
case(
r#"Параграф первый с **жирным** текстом.
Параграф второй с *курсивом* и списком:
- Первый пункт **жирный**
- Второй пункт *курсивный*
Конец."#),
case(
r#"Список с задачами:
- Первый пункт
- [ ] Второй пункт
- [X] Третий пункт
Конец."#),
case(
r#"> Список внутри цитаты:
> - Пункт *первый*
> - Пункт **второй**
>
> - Подпункт `третий`
>
> Конец цитаты."#),
case(
r#"## Это *курсивный* заголовок с [ссылкой](https://example.com)"#),
case(
r#"Это просто текст** а потом *ещё* звёздочки."#),
case(
r#"[ссылка с `кодом` внутри](https://example.com)"#),
case(
r#"Здесь *курсив без конца и **жирный без конца"#),
case(
"**Всё жирное и *курсивное и `кодовое внутри курсивного` и снова курсивное* снова\nжирное**"),
case(
r#"[Ссылка с \*экранированной звездочкой\* внутри](https://example.com)"#),
case(
r#"Текст с сноской[^1].
[^1]: Это текст сноски."#),
case(
r#"Это *курсивный текст со сноской[^note]*.
[^note]: Сноска для курсивного текста."#),
case(
r#"[Ссылка с сноской[^linknote]](https://example.com)
[^linknote]: Сноска для ссылки."#),
case(
r#"# Заголовок со сноской[^headnote]
[^headnote]: Пояснение к заголовку."#),
case(
r#"| Заголовок 1 | Заголовок 2 | Заголовок 3 |
| ----------- | ----------: | :---------: |
| Ячейка 1 | Ячейка 2 | Ячейка 3 |
| Ячейка 4 | Ячейка 5 | Ячейка 6 |"#),
case(
r#"| **Заголовок 1** | Заголовок 2 | Заголовок 3 |
| --------------- | ----------: | :---------: |
| Ячейка 1 | Ячейка 2 | Ячейка 3 |
| Ячейка 4 | Ячейка 5 | Ячейка 6 |"#),
case(
r#"> | Заголовок 1 | Заголовок 2 | Заголовок 3 |
> | ----------- | ----------: | :---------: |
> | Ячейка 1 | Ячейка 2 | Ячейка 3 |
> | Ячейка 4 | Ячейка 5 | Ячейка 6 |"#),
case(
r#"> blockquote level 1
>
> > blockquote level 2"#),
case(
r#"text
```rust
let s = "hello\n";
```"#),
case(
r#"Autolinks test: <http://example.com> and <johnlepikhin@gmail.com>"#),
// GitHub Alert tests
case(
r#"> [!NOTE]
> This is a note"#),
case(
r#"> [!TIP]
> Here's a helpful tip with **bold** and *italic* text"#),
case(
r#"> [!IMPORTANT]
> This is important information
>
> With multiple paragraphs"#),
case(
r#"> [!WARNING]
> Warning with a list:
>
> - First item
> - Second item
> - Third item"#),
case(
r#"> [!CAUTION]
> Caution alert with `inline code` and [a link](https://example.com)"#),
// Edge case: Empty alert
case(
r#"> [!NOTE]"#),
// Edge case: Alert with nested blockquote
case(
r#"> [!TIP]
> This contains a nested quote:
>
> > Nested quote inside alert
> >
> > Second line of nested quote"#),
// Edge case: Alert with code block
case(
r#"> [!WARNING]
> Here's some code:
>
> ```python
> def hello():
> print("Hello, world!")
> ```
>
> Be careful!"#),
// Edge case: Multiple alerts in sequence
case(
r#"> [!NOTE]
> First alert
> [!TIP]
> Second alert"#),
// Edge case: Alert with table
case(
r#"> [!IMPORTANT]
> Here's a table:
>
> | Column 1 | Column 2 |
> | -------- | -------- |
> | Cell 1 | Cell 2 |"#),
// Edge case: Alert with footnote
case(
r#"> [!CAUTION]
> Text with footnote[^1]
[^1]: This is the footnote"#),
// Edge case: Alert with task list
// Note: Current printer uses [X] for completed tasks - this is expected behavior
case(
r#"> [!TIP]
> Task list:
>
> - [X] Completed task
> - [ ] Incomplete task
> - [ ] Another task"#),
// Edge case: Alert with horizontal rule
case(
r#"> [!NOTE]
> Before rule
>
> ---
>
> After rule"#),
// Edge case: Alert with escaped content
case(
r#"> [!WARNING]
> This has \*escaped\* content and \[brackets\]"#),
// Edge case: Alert with HTML entity
// Note: Parser converts © to © symbol
case(
r#"> [!IMPORTANT]
> Copyright © 2024"#),
// Edge case: Alert with autolink
case(
r#"> [!CAUTION]
> Visit <https://example.com> for more info"#),
// Edge case: Alert with strikethrough
case(
r#"> [!TIP]
> This is ~~deprecated~~ text"#),
// Edge case: Alert with image
case(
r#"> [!NOTE]
> "#),
// Edge case: Alert with reference link
case(
r#"> [!WARNING]
> See [this link][ref] for details
[ref]: https://example.com"#),
// Edge case: Alert with complex mixed content
case(
r#"> [!IMPORTANT]
> # Heading inside alert
>
> This has **bold**, *italic*, `code`, and ~~strikethrough~~.
>
> - List item 1
> - List item 2
>
> ```js
> console.log("code block");
> ```
>
> End of alert"#),
// Table tests with line wrapping issues
case(
r#"| Very long header that would normally wrap on narrow displays | Another extremely long header that tests table rendering |
| ------------------------------------------------------------------------ | -------------------------------------------------------- |
| Very long cell content that should not wrap regardless of width settings | Another long cell with extensive content |"#),
case(
r#"| Участок | Протяженность | Крутизна | Характер рельефа | Кат. сл. | Кол-во Крючьев / закладок |
| ------------------------------------------- | ------------------------------------ | -------- | ------------------ | -------- | ------------------------- |
| R0 — начало маршрута — цирк балки Гнилая | Удобное место для организации связок | Empty | Empty | Empty | Empty |
| R0–R1 — Подъем на перемычку (пер. Липецкий) | 250 м | 30–35° | Снег, летом — фирн | 2– | Кр. — 0/0, Закл. — 0/0 |"#),
case(
r#"| Header with content | Another header |
| ------------------- | -------------- |
| Cell content | Normal cell |"#),
case(
r#"| Short | Very very very very very very very very very very very long content that definitely exceeds any reasonable line width limit |
| ----- | --------------------------------------------------------------------------------------------------------------------------- |
| A | Another extremely long cell that tests the table width handling capabilities of the markdown parser and printer combination |
| B | Yet another cell with extensive content to verify that tables preserve their structure regardless of content length |"#),
case(
r#"| Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 |
| -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
| Data 1 | Data 2 | Data 3 | Data 4 | Data 5 | Data 6 | Data 7 | Data 8 |
| More 1 | More 2 | More 3 | More 4 | More 5 | More 6 | More 7 | More 8 |"#),
)]
fn symmetric_round_trip(input: &str) {
let config = crate::printer::config::Config::default();
let doc = crate::parser::parse_markdown(crate::parser::MarkdownParserState::default(), input)
.unwrap();
println!("{input:?} => {doc:#?}");
let result = crate::printer::render_markdown(&doc, config);
assert_eq!(input, result);
}