'abc-123', 'name' => 'Ma vidéo', 'previewPath' => '/lazy/abc.jpg', 'duration' => 125, 'channel' => [ 'displayName' => 'Chaîne', 'avatars' => [['path' => '/avatars/a.png']] ], 'views' => 42, 'publishedAt' => '2024-01-01T00:00:00.000Z', 'aspectRatio' => 1.78, 'description' => 'Une description', 'tags' => ['musique'], 'isLive' => true, ], [ // Vidéo minimale : sans vignette, avatar, description, tags ni isLive 'uuid' => 'def-456', 'name' => 'Minimale', 'duration' => 5, 'channel' => ['displayName' => 'Autre chaîne'], 'views' => 0, 'publishedAt' => '2024-01-02T00:00:00.000Z', 'aspectRatio' => 1.78, ], ]; $videos = formatVideosData($rawVideos); assertEquals(2, count($videos), 'formatVideosData retourne une entrée par vidéo'); assertEquals('abc-123', $videos[0]['id'], 'formatVideosData mappe uuid vers id'); assertEquals('Ma vidéo', $videos[0]['title'], 'formatVideosData mappe name vers title'); assertEquals( PEERTUBE_URL . '/lazy/abc.jpg', $videos[0]['thumbnail'], 'formatVideosData préfixe la vignette avec PEERTUBE_URL' ); assertEquals( PEERTUBE_URL . '/avatars/a.png', $videos[0]['channelAvatar'], 'formatVideosData préfixe l\'avatar avec PEERTUBE_URL' ); assertEquals(125, $videos[0]['duration'], 'formatVideosData conserve la durée'); assertEquals('Chaîne', $videos[0]['channel'], 'formatVideosData mappe le nom de la chaîne'); assertEquals(42, $videos[0]['views'], 'formatVideosData conserve les vues'); assertEquals('2024-01-01T00:00:00.000Z', $videos[0]['date'], 'formatVideosData mappe publishedAt vers date'); assertEquals('Une description', $videos[0]['description'], 'formatVideosData conserve la description'); assertEquals(['musique'], $videos[0]['tags'], 'formatVideosData conserve les tags'); assertTrue($videos[0]['isLive'], 'formatVideosData conserve isLive'); assertEquals( 'img/default-thumbnail.jpg', $videos[1]['thumbnail'], 'formatVideosData utilise une vignette par défaut si absente' ); assertEquals( 'img/default-avatar.png', $videos[1]['channelAvatar'], 'formatVideosData utilise un avatar par défaut si absent' ); assertEquals('', $videos[1]['description'], 'formatVideosData met une description vide par défaut'); assertEquals([], $videos[1]['tags'], 'formatVideosData met des tags vides par défaut'); assertFalse($videos[1]['isLive'], 'formatVideosData met isLive à false par défaut'); // --- formatVideosData : données API incomplètes ------------------------------- $incompleteVideos = formatVideosData([ [ // Sans uuid : doit être ignorée 'name' => 'Sans uuid', 'duration' => 10, ], [ // uuid vide : doit être ignorée aussi 'uuid' => '', 'name' => 'Uuid vide', ], [ // uuid seul : valeurs par défaut partout ailleurs 'uuid' => 'ghi-789', ], [ // channel présent mais sans displayName ni avatars 'uuid' => 'jkl-012', 'channel' => ['name' => 'compte'], ], ]); assertEquals(2, count($incompleteVideos), 'formatVideosData ignore les entrées sans uuid'); assertEquals('ghi-789', $incompleteVideos[0]['id'], 'formatVideosData conserve l\'uuid seul'); assertEquals('', $incompleteVideos[0]['title'], 'formatVideosData met un titre vide par défaut'); assertEquals(0, $incompleteVideos[0]['duration'], 'formatVideosData met une durée à 0 par défaut'); assertEquals('', $incompleteVideos[0]['channel'], 'formatVideosData met une chaîne vide par défaut'); assertEquals(0, $incompleteVideos[0]['views'], 'formatVideosData met les vues à 0 par défaut'); assertEquals('', $incompleteVideos[0]['date'], 'formatVideosData met une date vide par défaut'); assertNull($incompleteVideos[0]['aspectRatio'], 'formatVideosData met aspectRatio à null par défaut'); assertFalse($incompleteVideos[0]['isLive'], 'formatVideosData met isLive à false par défaut'); assertEquals( 'img/default-thumbnail.jpg', $incompleteVideos[0]['thumbnail'], 'formatVideosData met la vignette par défaut pour une entrée minimale' ); assertEquals( 'img/default-avatar.png', $incompleteVideos[0]['channelAvatar'], 'formatVideosData met l\'avatar par défaut pour une entrée minimale' ); assertEquals('', $incompleteVideos[1]['channel'], 'formatVideosData met une chaîne vide si displayName absent'); assertEquals( 'img/default-avatar.png', $incompleteVideos[1]['channelAvatar'], 'formatVideosData met l\'avatar par défaut si le tableau avatars est absent' ); // --- truncateText (includes/structured-data.php) ---------------------------- assertEquals('court', truncateText('court', 200), 'truncateText laisse un texte court intact'); assertEquals('exact', truncateText('exact', 5), 'truncateText laisse un texte à la limite exacte intact'); $textWithSpace = str_repeat('a', 150) . ' ' . str_repeat('b', 100); // 251 caractères assertEquals( str_repeat('a', 150) . '...', truncateText($textWithSpace, 200), 'truncateText coupe au dernier espace avant la limite' ); $textNoSpace = str_repeat('a', 250); assertEquals( str_repeat('a', 200) . '...', truncateText($textNoSpace, 200), 'truncateText coupe à la limite quand il n\'y a pas d\'espace' ); // --- truncateText : UTF-8 multioctet (mb_substr) ----------------------------- $utf8WithSpace = str_repeat('é', 150) . ' ' . str_repeat('b', 100); // 251 caractères assertEquals( str_repeat('é', 150) . '...', truncateText($utf8WithSpace, 200), 'truncateText compte les caractères UTF-8 et non les octets' ); $utf8NoSpace = str_repeat('€', 250); // 3 octets par caractère $truncatedUtf8 = truncateText($utf8NoSpace, 200); assertEquals( str_repeat('€', 200) . '...', $truncatedUtf8, 'truncateText ne coupe pas un caractère multioctet en deux' ); assertEquals(1, preg_match('//u', $truncatedUtf8), 'truncateText retourne de l\'UTF-8 valide'); // --- formatDateFr (includes/structured-data.php) ----------------------------- $dateFr = new DateTime('2025-10-11 00:00:00', new DateTimeZone('Indian/Reunion')); assertEquals('11 octobre 2025', formatDateFr($dateFr), 'formatDateFr formate la date longue en français'); assertEquals( '11 octobre 2025 à 00:00', formatDateFr($dateFr, true), 'formatDateFr ajoute l\'heure quand demandé' ); $dateFrSummer = new DateTime('2026-07-04 12:30:00', new DateTimeZone('UTC')); assertEquals('4 juillet 2026', formatDateFr($dateFrSummer), 'formatDateFr sans zéro initial sur le jour'); assertEquals( '4 juillet 2026 à 12:30', formatDateFr($dateFrSummer, true), 'formatDateFr utilise le fuseau de la date fournie' );