Add PHPUnit setup (Phase 0) and pure-logic tests (Phase 1): Crypto, EmailObfuscator, SystemController helpers, StudentEmail, TfeController OG tags

This commit is contained in:
Pontoporeia
2026-05-20 01:28:22 +02:00
parent d9e4541749
commit 7a4d0fafb2
12 changed files with 2811 additions and 14 deletions

View File

@@ -0,0 +1,199 @@
<?php
use PHPUnit\Framework\TestCase;
/**
* TfeControllerOgTest — Pure logic tests for TfeController::buildOgTags()
* and buildMetaDescription().
*
* These methods are protected; we use a thin subclass to expose them.
*/
class TfeControllerOgTest extends TestCase
{
/**
* Subclass that exposes protected methods for testing.
*/
private static function makeController(): object
{
return new class extends TfeController {
public function __construct()
{
// Skip parent constructor — we don't need DB for these pure methods
}
public function exposedBuildOgTags(array $data, int $thesisId, string $metaDescription): array
{
return $this->buildOgTags($data, $thesisId, $metaDescription);
}
public function exposedBuildMetaDescription(string $synopsis): string
{
return $this->buildMetaDescription($synopsis);
}
public function exposedResolveOgImage(array $files): string
{
return $this->resolveOgImage($files);
}
};
}
// ── buildOgTags() ─────────────────────────────────────────────────────────
public function testBuildOgTagsReturnsAllRequiredKeys(): void
{
$ctrl = self::makeController();
$data = [
'title' => 'My Thesis',
'authors' => 'Jane Doe',
'year' => '2024',
'files' => [],
];
$tags = $ctrl->exposedBuildOgTags($data, 42, 'A description');
$requiredKeys = ['type', 'title', 'description', 'url', 'image', 'image_alt', 'site_name', 'article_author', 'article_published_time'];
foreach ($requiredKeys as $key) {
$this->assertArrayHasKey($key, $tags);
$this->assertIsString($tags[$key]);
}
}
public function testBuildOgTagsTitleIncludesAuthors(): void
{
$ctrl = self::makeController();
$data = [
'title' => 'The Title',
'authors' => 'Author Name',
'year' => '2024',
'files' => [],
];
$tags = $ctrl->exposedBuildOgTags($data, 1, 'desc');
$this->assertStringContainsString('The Title Author Name', $tags['title']);
// Without authors, just the title
$data['authors'] = '';
$tags2 = $ctrl->exposedBuildOgTags($data, 1, 'desc');
$this->assertSame('The Title', $tags2['title']);
}
public function testBuildOgTagsImageEmptyWhenNoFiles(): void
{
$ctrl = self::makeController();
$data = [
'title' => 'No Files',
'authors' => 'A',
'year' => '2023',
'files' => [],
];
$tags = $ctrl->exposedBuildOgTags($data, 5, 'desc');
$this->assertSame('', $tags['image']);
}
public function testBuildOgTagsImageFromCover(): void
{
$ctrl = self::makeController();
$data = [
'title' => 'Cover Test',
'authors' => 'Author',
'year' => '2024',
'files' => [
['file_path' => 'documents/2024-001/cover.jpg', 'file_type' => 'cover'],
],
];
$tags = $ctrl->exposedBuildOgTags($data, 1, 'desc');
$this->assertStringContainsString('cover.jpg', $tags['image']);
}
public function testBuildOgTagsImageFallbackToFirstImage(): void
{
$ctrl = self::makeController();
$data = [
'title' => 'Image Test',
'authors' => 'B',
'year' => '2024',
'files' => [
['file_path' => 'documents/2024-001/doc.pdf', 'file_type' => 'tfe'],
['file_path' => 'documents/2024-001/screenshot.png', 'file_type' => 'tfe'],
],
];
$tags = $ctrl->exposedBuildOgTags($data, 2, 'desc');
$this->assertStringContainsString('screenshot.png', $tags['image']);
}
public function testBuildOgTagsUrlIncludesThesisId(): void
{
$ctrl = self::makeController();
$data = ['title' => 'URL Test', 'authors' => '', 'year' => '2024', 'files' => []];
$tags = $ctrl->exposedBuildOgTags($data, 99, 'desc');
$this->assertStringContainsString('tfe?id=99', $tags['url']);
}
public function testBuildOgTagsPublishedTimeFormatted(): void
{
$ctrl = self::makeController();
$data = ['title' => 'T', 'authors' => '', 'year' => '2025', 'files' => []];
$tags = $ctrl->exposedBuildOgTags($data, 1, 'desc');
$this->assertSame('2025-01-01', $tags['article_published_time']);
}
public function testBuildOgTagsPublishedTimeEmptyWhenNoYear(): void
{
$ctrl = self::makeController();
$data = ['title' => 'T', 'authors' => '', 'files' => []];
$tags = $ctrl->exposedBuildOgTags($data, 1, 'desc');
$this->assertSame('', $tags['article_published_time']);
}
// ── buildMetaDescription() ────────────────────────────────────────────────
public function testBuildMetaDescriptionTruncatesLongSynopsis(): void
{
$ctrl = self::makeController();
$long = str_repeat('abcdefghij', 20); // 200 chars
$desc = $ctrl->exposedBuildMetaDescription($long);
$this->assertLessThanOrEqual(160, strlen($desc));
$this->assertStringEndsWith('…', $desc);
}
public function testBuildMetaDescriptionKeepsShortSynopsis(): void
{
$ctrl = self::makeController();
$desc = $ctrl->exposedBuildMetaDescription('A short synopsis.');
$this->assertSame('A short synopsis.', $desc);
}
public function testBuildMetaDescriptionEmptySynopsisReturnsDefault(): void
{
$ctrl = self::makeController();
$desc = $ctrl->exposedBuildMetaDescription('');
$this->assertStringContainsString('Mémoire', $desc);
$this->assertStringContainsString('XAMXAM', $desc);
}
public function testBuildMetaDescriptionStripsHtmlTags(): void
{
$ctrl = self::makeController();
$desc = $ctrl->exposedBuildMetaDescription('<p>Hello <b>world</b></p>');
$this->assertStringNotContainsString('<p>', $desc);
$this->assertStringNotContainsString('<b>', $desc);
$this->assertStringContainsString('Hello world', $desc);
}
}