Synopsis : normalisation SÛRE des text ajouté par formulaire

- fins de ligne \r\n/\r → \n,
- blocs de lignes vides → \n\n, è
- espaces/tabulations/NBSP → espace unique,
- trim.
Les retours à la ligne simples intra-paragraphe sont LAISSÉS INTACTS :
une coupure de ligne peut être une vraie frontière de mot (→ espace)
ou une coupure du mot ("dyna\nmiques" → "dynamiques"),
indistinguables sans dictionnaire — automatiser corromprait l'entrée
("poursuivantsur").

Migration batch 045 (backfill des données existantes) RETIRÉE : le
nettoyage automatique fiable des synopsis existants est impossible.
Chaque modification est testée (277 tests PHPUnit).
This commit is contained in:
Pontoporeia
2026-09-18 16:26:36 +02:00
parent 6e1fc6a781
commit 0896c4b8c8
4 changed files with 122 additions and 5 deletions
@@ -263,6 +263,96 @@ class ThesisCreateValidationTest extends TestCase
$this->assertStringContainsString('Bold synopsis', $data['synopsis']);
}
// ── Whitespace normalisation (safe, unambiguous subset only) ────────────────
// Single newlines inside a paragraph are deliberately LEFT untouched: they can
// be a word boundary (→ space) or a word split across a line ("dyna\nmiques"
// → "dynamiques") and are indistinguishable, so we never guess and risk
// corrupting valid input (e.g. "se poursuivant\nsur" → "poursuivantsur").
public function testSingleIntraParagraphNewlineIsLeftUntouched(): void
{
// A mid-word line break is ambiguous (could be a real split or a wrap),
// so we do not auto-alter it — the author is responsible for cleaning it.
$post = $this->validPost();
$post['synopsis'] = "…les dyn\namiques complexes…";
$data = $this->validate($post);
$this->assertSame("…les dyn\namiques complexes…", $data['synopsis']);
}
public function testWordWrapSingleNewlineNotMerged(): void
{
// We must NOT merge two real words across a line break ("poursuivantsur").
$post = $this->validPost();
$post['synopsis'] = "se poursuivant\nsur une seconde ligne";
$data = $this->validate($post);
$this->assertSame(
"se poursuivant\nsur une seconde ligne",
$data['synopsis']
);
}
public function testLegitimateParagraphBreakPreserved(): void
{
$post = $this->validPost();
$post['synopsis'] = "Premier paragraphe\n\nSecond paragraphe";
$data = $this->validate($post);
$this->assertSame(
"Premier paragraphe\n\nSecond paragraphe",
$data['synopsis']
);
}
public function testMultipleBlankLinesCollapseToSingleParagraphBreak(): void
{
$post = $this->validPost();
$post['synopsis'] = "A\n\n\n\nB";
$data = $this->validate($post);
$this->assertSame("A\n\nB", $data['synopsis']);
}
public function testMixedWindowsAndUnixLineEndingsNormalised(): void
{
$post = $this->validPost();
$post['synopsis'] = "une pause\r\n\r\ner une future";
$data = $this->validate($post);
// \r\n and \r line-endings all collapse to \n, and blank lines mark
// a single paragraph separator.
$this->assertSame("une pause\n\ner une future", $data['synopsis']);
}
public function testConsecutiveSpacesAndTabsCollapse(): void
{
$post = $this->validPost();
$post['synopsis'] = "Très espacé\t\ttab";
$data = $this->validate($post);
$this->assertSame('Très espacé tab', $data['synopsis']);
}
public function testNonBreakingSpacesNormalised(): void
{
$post = $this->validPost();
// Word pasted NBSP (U+00A0) between words must become a regular space.
$post['synopsis'] = "Premier\u{00A0}mot second mot";
$data = $this->validate($post);
$this->assertSame('Premier mot second mot', $data['synopsis']);
}
public function testSynopsisSingleLineFieldTrimmed(): void
{
$post = $this->validPost();
$post['synopsis'] = " texte qui flotte ";
$data = $this->validate($post);
$this->assertSame('texte qui flotte', $data['synopsis']);
}
// ── Author processing ────────────────────────────────────────────────────
public function testMultipleAuthorsAreSorted(): void