diff --git a/ecrire/tests/Xml/XmlHackTest.php b/ecrire/tests/Xml/XmlHackTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..80ea872246616dfd0b4d138d756fc78e22bbe94e
--- /dev/null
+++ b/ecrire/tests/Xml/XmlHackTest.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Spip\Test\Xml;
+
+use PHPUnit\Framework\Attributes\DataProvider;
+use Spip\Test\SquelettesTestCase;
+
+/**
+ * Le hack xml repère dans le squelette la sequence "< ?xml"
+ * et évite de l'éxecuter en php
+ */
+class XmlHackTest extends SquelettesTestCase
+{
+	#[DataProvider('providerXmlIsNotPhp')]
+	public function testXmlIsNotPhp(string $squelette): void {
+		$skel = $this->relativePath(__DIR__ . '/data/' . $squelette);
+		$out = recuperer_fond($skel, [], [
+			'raw' => true,
+			'trim' => true
+		]);
+		$this->assertEmpty($out['erreur'] ?? null);
+		$this->assertNotEmpty($out['texte']);
+		$xml = simplexml_load_string($out['texte']);
+		$this->assertOk((string) $xml[0]);
+	}
+
+	public static function providerXmlIsNotPhp(): array {
+		return [
+			['xmlhack'],
+			['xmlhack_php'],
+			['xmlhack_inclure'],
+			['xmlhack_inclure_php'],
+			['xmlhack_inclure_dyn'],
+			['xmlhack_inclure_dyn_php'],
+		];
+	}
+}
diff --git a/ecrire/tests/Xml/data/xmlhack.html b/ecrire/tests/Xml/data/xmlhack.html
new file mode 100644
index 0000000000000000000000000000000000000000..8d90939bae439b59299881d2454d68f82a3cbec8
--- /dev/null
+++ b/ecrire/tests/Xml/data/xmlhack.html
@@ -0,0 +1,2 @@
+<?xml version="1.0"[ encoding="(#CHARSET)"]?>
+<tag>OK</tag>
diff --git a/ecrire/tests/Xml/data/xmlhack_inclure.html b/ecrire/tests/Xml/data/xmlhack_inclure.html
new file mode 100644
index 0000000000000000000000000000000000000000..950b7e8edf0368e89c826aaa4f3bfe8251491272
--- /dev/null
+++ b/ecrire/tests/Xml/data/xmlhack_inclure.html
@@ -0,0 +1 @@
+[(#INCLURE{fond=#DOSSIER_SQUELETTE/xmlhack})]
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_inclure_dyn.html b/ecrire/tests/Xml/data/xmlhack_inclure_dyn.html
similarity index 100%
rename from ecrire/tests/legacy/unit/xml/xmlhack_inclure_dyn.html
rename to ecrire/tests/Xml/data/xmlhack_inclure_dyn.html
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_inclure_dyn_php.html b/ecrire/tests/Xml/data/xmlhack_inclure_dyn_php.html
similarity index 100%
rename from ecrire/tests/legacy/unit/xml/xmlhack_inclure_dyn_php.html
rename to ecrire/tests/Xml/data/xmlhack_inclure_dyn_php.html
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_inclure_php.html b/ecrire/tests/Xml/data/xmlhack_inclure_php.html
similarity index 100%
rename from ecrire/tests/legacy/unit/xml/xmlhack_inclure_php.html
rename to ecrire/tests/Xml/data/xmlhack_inclure_php.html
diff --git a/ecrire/tests/Xml/data/xmlhack_php.html b/ecrire/tests/Xml/data/xmlhack_php.html
new file mode 100644
index 0000000000000000000000000000000000000000..b771fb9c9541f56722da55f67072efd0c31cbc44
--- /dev/null
+++ b/ecrire/tests/Xml/data/xmlhack_php.html
@@ -0,0 +1,2 @@
+<?xml version="1.0"[ encoding="(#CHARSET)"]?>
+<tag><?php echo 'OK'; ?></tag>
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack.html b/ecrire/tests/legacy/unit/xml/xmlhack.html
deleted file mode 100644
index 839ecf4701c7519207f73635b74edf7568b73969..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack.html
+++ /dev/null
@@ -1,14 +0,0 @@
-[(#REM)
-
-	le hack xml repere dans le squelette la sequence "< ?xml"
-	et evite de l'executer en php
-
-]
-
-#CACHE{0}<!--
-filtre:spip_xml_parse
-filtre:reset
-filtre:reset
--->
-<?xml version="1.0"[ encoding="(#CHARSET)"]?>
-<tag>OK</tag>
\ No newline at end of file
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_fonctions.php b/ecrire/tests/legacy/unit/xml/xmlhack_fonctions.php
deleted file mode 100644
index f53060ed3ca4845f4e01cbdafbe40571a3a286a5..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack_fonctions.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-include_spip('inc/xml');
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_inclure.html b/ecrire/tests/legacy/unit/xml/xmlhack_inclure.html
deleted file mode 100644
index 8b8017680cca11e96b2832d542ae2cd318037961..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack_inclure.html
+++ /dev/null
@@ -1 +0,0 @@
-[(#INCLURE{fond=#DOSSIER_SQUELETTE/xmlhack})]
\ No newline at end of file
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_php.html b/ecrire/tests/legacy/unit/xml/xmlhack_php.html
deleted file mode 100644
index c7f8c11df941e06d11d1ff27b13dc7258a6660d2..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack_php.html
+++ /dev/null
@@ -1,14 +0,0 @@
-[(#REM)
-
-	le hack xml repere dans le squelette la sequence "< ?xml"
-	et evite de l'executer en php
-
-]
-
-#CACHE{0}<!--
-filtre:spip_xml_parse
-filtre:reset
-filtre:reset
--->
-<?xml version="1.0"[ encoding="(#CHARSET)"]?>
-<tag><?php echo 'OK'; ?></tag>
\ No newline at end of file
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_php_fonctions.php b/ecrire/tests/legacy/unit/xml/xmlhack_php_fonctions.php
deleted file mode 100644
index f53060ed3ca4845f4e01cbdafbe40571a3a286a5..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack_php_fonctions.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-include_spip('inc/xml');
diff --git a/ecrire/tests/legacy/unit/xml/xmlhack_recuperer_fond.php b/ecrire/tests/legacy/unit/xml/xmlhack_recuperer_fond.php
deleted file mode 100644
index e59c46405140e53824b4ef4cb64ca4141d0c1358..0000000000000000000000000000000000000000
--- a/ecrire/tests/legacy/unit/xml/xmlhack_recuperer_fond.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-$test = 'xmlhack_recuperer_fond';
-
-$remonte = __DIR__ . '/';
-
-while (!is_file($remonte . 'test.inc')) {
-	$remonte .= '../';
-}
-
-require $remonte . 'test.inc';
-
-include_spip('public/assembler');
-
-$dir = substr(dirname(__DIR__, 2), strlen(_SPIP_TEST_CHDIR) + 1);
-
-$out = recuperer_fond($dir . '/unit/xml/xmlhack');
-
-// regarder si le hack a marche
-
-include_spip('inc/xml');
-
-$tree = spip_xml_parse($out);
-
-$ok = reset($tree);
-
-$ok = reset($ok);
-
-if ($ok !== 'OK') {
-	echo '<dl> Erreur sur le xml produit (xmlhack) : ' . serialize($tree) . '</dl>';
-}
-
-$out = recuperer_fond($dir . '/unit/xml/xmlhack_php');
-
-// regarder si le hack a marche
-
-include_spip('inc/xml');
-
-$tree = spip_xml_parse($out);
-
-$ok1 = reset($tree);
-
-$ok1 = reset($ok1);
-
-if ($ok1 !== 'OK') {
-	echo '<dl> Erreur sur le xml produit (xmlhack_php) : ' . serialize($tree) . '</dl>';
-}
-
-if ($ok && $ok1) {
-	echo 'OK';
-}