Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions tests/table/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
//! Integration tests for table reflow and HTML table conversion.
//!
//! Covers `reflow_table`, `convert_html_tables` and related `process_stream` behaviour.
//! This module provides comprehensive test coverage for the table processing
//! functionality in `mdtablefix`, including Markdown table reflowing and
//! HTML-to-Markdown conversion.
//!
//! The module is organised into focused submodules:
//! - `reflow`: Tests for `reflow_table` covering basic reflow, malformed tables,
//! header preservation, escaped pipes and indentation.
//! - `process_stream_tests`: Tests for `process_stream` verifying normalisation
//! of various HTML table variants and handling of multiple tables.
//! - `uniform`: Regression tests ensuring uniform column widths after reflowing.
//! - `convert_html`: Parameterised tests for HTML table conversion edge cases.
//! - `regressions`: Real-world data validation tests.
//!
//! Each test uses fixtures defined in this module to ensure consistent test data
//! across different scenarios whilst avoiding duplication.

use mdtablefix::{convert_html_tables, process_stream, reflow_table};

Expand All @@ -10,8 +24,7 @@ use prelude::*;

#[fixture]
fn malformed_table() -> Vec<String> {
let lines = lines_vec!["| A | |", "| 1 | 2 | 3 |"];
lines
lines_vec!["| A | |", "| 1 | 2 | 3 |"]
}

#[fixture]
Expand All @@ -26,8 +39,7 @@ fn escaped_pipe_table() -> Vec<String> {

#[fixture]
fn indented_table() -> Vec<String> {
let lines = lines_vec![" | I | J | |", " | 1 | 2 | | 3 | 4 |"];
lines
lines_vec![" | I | J | |", " | 1 | 2 | | 3 | 4 |"]
}

#[fixture]
Expand Down Expand Up @@ -102,14 +114,12 @@ fn html_table_inconsistent_first_row() -> Vec<String> {

#[fixture]
fn html_table_empty() -> Vec<String> {
let lines = lines_vec!["<table></table>"];
lines
lines_vec!["<table></table>"]
}

#[fixture]
fn html_table_unclosed() -> Vec<String> {
let lines = lines_vec!["<table>", "<tr><td>1</td></tr>"];
lines
lines_vec!["<table>", "<tr><td>1</td></tr>"]
}

#[fixture]
Expand Down
41 changes: 17 additions & 24 deletions tests/table/uniform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,7 @@

use super::*;

#[test]
fn test_uniform_example_one() {
let input = lines_vec![
"| Logical type | PostgreSQL | SQLite notes |",
"|--------------|-------------------------|-------------------------------------------|",
"| strings | `TEXT` (or `VARCHAR`) | `TEXT` - SQLite ignores the length specifier anyway |",
"| booleans | `BOOLEAN DEFAULT FALSE` | declare as `BOOLEAN`; Diesel serialises to 0 / 1 so this is fine |",
"| integers | `INTEGER` / `BIGINT` | ditto |",
"| decimals | `NUMERIC` | stored as FLOAT in SQLite; Diesel `Numeric` round-trips, but beware precision |",
"| blobs / raw | `BYTEA` | `BLOB` |",
];
let output = reflow_table(&input);
fn assert_uniform_column_widths(output: &[String]) {
assert!(!output.is_empty());
let widths: Vec<usize> = output[0]
.trim_matches('|')
Expand All @@ -28,6 +17,21 @@ fn test_uniform_example_one() {
}
}

#[test]
fn test_uniform_example_one() {
let input = lines_vec![
"| Logical type | PostgreSQL | SQLite notes |",
"|--------------|-------------------------|-------------------------------------------|",
"| strings | `TEXT` (or `VARCHAR`) | `TEXT` - SQLite ignores the length specifier anyway |",
"| booleans | `BOOLEAN DEFAULT FALSE` | declare as `BOOLEAN`; Diesel serialises to 0 / 1 so this is fine |",
"| integers | `INTEGER` / `BIGINT` | ditto |",
"| decimals | `NUMERIC` | stored as FLOAT in SQLite; Diesel `Numeric` round-trips, but beware precision |",
"| blobs / raw | `BYTEA` | `BLOB` |",
];
let output = reflow_table(&input);
assert_uniform_column_widths(&output);
}

#[test]
fn test_uniform_example_two() {
let input = lines_vec![
Expand All @@ -38,16 +42,5 @@ fn test_uniform_example_two() {
"| **D. Two separate migration trees** | Maintain `migrations/sqlite` and `migrations/postgres` directories with identical version numbers. Use `embed_migrations!(\"migrations/<backend>\")` to compile the right set. | You ship a single binary with migrations baked in. |",
];
let output = reflow_table(&input);
assert!(!output.is_empty());
let widths: Vec<usize> = output[0]
.trim_matches('|')
.split('|')
.map(str::len)
.collect();
for row in output {
let cols: Vec<&str> = row.trim_matches('|').split('|').collect();
for (i, col) in cols.iter().enumerate() {
assert_eq!(col.len(), widths[i]);
}
}
assert_uniform_column_widths(&output);
}
4 changes: 4 additions & 0 deletions tests/wrap/cli.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//! CLI wrapping option tests.
//!
//! Validates that the `--wrap` command-line flag correctly triggers text
//! wrapping behaviour when processing Markdown content through the `mdtablefix`
//! binary.

use super::*;

Expand Down
17 changes: 17 additions & 0 deletions tests/wrap/footnotes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//! Footnote wrapping tests.
//!
//! Validates wrapping behaviour for Markdown footnotes, ensuring proper
//! indentation is maintained and inline code spans are not broken across lines.
//! Tests various footnote formats including those with URLs and code.

use super::*;

Expand All @@ -12,6 +16,19 @@ fn test_wrap_footnote_multiline() {
assert_wrapped_list_item(&output, "[^note]: ", 2);
}

#[test]
fn test_wrap_footnote_multiline_with_blank_lines() {
let input = lines_vec![
"[^note]: This footnote begins with a paragraph long enough to trigger wrapping so that indentation can be checked.",
"",
" This second paragraph should also wrap correctly and remain indented.",
];
let output = process_stream(&input);
assert_eq!(output[1], "");
assert!(output.iter().skip(2).all(|l| l.starts_with(" ")));
assert!(output.iter().all(|l| l.len() <= 80));
}

#[test]
fn test_wrap_footnote_with_inline_code() {
let input = lines_vec![concat!(
Expand Down
3 changes: 1 addition & 2 deletions tests/wrap/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ fn test_wrap_paragraph_with_nested_link() {
#[test]
fn test_wrap_link_with_trailing_punctuation() {
let input = lines_vec![
"[`rust-multithreaded-logging-framework-for-python-design.md`](./\\
rust-multithreaded-logging-framework-for-python-design.md).",
"[`rust-multithreaded-logging-framework-for-python-design.md`](./rust-multithreaded-logging-framework-for-python-design.md).",
];
let output = process_stream(&input);
assert_eq!(output, input);
Expand Down
12 changes: 10 additions & 2 deletions tests/wrap/paragraphs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
//! Paragraph wrapping tests.
//!
//! Validates text wrapping behaviour for paragraph content, including handling
//! of long words that exceed the 80-column limit and cannot be broken.

use rstest::rstest;
use super::*;

#[test]
Expand All @@ -14,8 +18,12 @@ fn test_wrap_paragraph() {
}

#[test]
fn test_wrap_paragraph_with_long_word() {
let long_word = "a".repeat(100);
#[rstest]
#[case(100)]
#[case(150)]
#[case(200)]
fn test_wrap_paragraph_with_long_word_parameterised(#[case] word_length: usize) {
let long_word = "a".repeat(word_length);
let input = lines_vec![&long_word];
let output = process_stream(&input);
assert_eq!(output.len(), 1);
Expand Down
Loading