Steuerkram/tests/70_SettingsLogoUploadTest.php

117 lines
5.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
use Steuerkram\Config;
use Steuerkram\Models\Setting;
/**
* Test 70: Logo-Upload – Formular-Struktur, warnungsfreies Speichern und
* Ablage in data/logo außerhalb des Web-Roots.
*/
class SettingsLogoUploadTest extends TestCase
{
protected string $testName = 'Test 70: Logo-Upload – keine Warnings, Formulare nicht verschachtelt, Ablage in data/logo';
public function run(): void
{
// 1) Setting::update() darf mit einem Datensatz ohne die optionalen Keys
// (z.B. mail_subject_template, seit "E-Mail-Texte pro Kunde" nicht mehr im
// Einstellungsformular) keine Warning erzeugen – sonst geht Output raus,
// bevor View::redirect() den Location-Header setzen kann.
$warnings = [];
set_error_handler(function (int $no, string $msg) use (&$warnings): bool {
$warnings[] = $msg;
return true;
}, E_ALL);
try {
Setting::update([
'firma' => 'Testfirma',
'strasse' => 'Teststr. 1',
'plz' => '12345',
'ort' => 'Testort',
]);
} finally {
restore_error_handler();
}
$this->assert(
$warnings === [],
'Setting::update() ohne optionale Keys erzeugt keine Warnings (erhalten: ' . implode(' | ', $warnings) . ')'
);
$stored = Setting::get();
$this->assertEquals('Rechnung %RNR%', $stored['mail_subject_template'], 'Fehlender Betreff fällt auf den Default zurück');
$this->assertEquals('Testfirma', $stored['firma'], 'Firma wurde gespeichert');
// 2) Logo liegt in data/logo, die DB speichert nur den Dateinamen.
// Bewusst ein eigener Testdateiname – deleteLogo() löscht die Datei
// physisch, ein echtes logo.png darf davon nie getroffen werden.
$testFile = 'logo-test-' . getmypid() . '.png';
$testPath = $this->registerTempPath(Config::get('logo_dir') . '/' . $testFile);
Setting::setLogo($testFile);
$this->assertEquals($testFile, Setting::get()['logo_path'], 'setLogo() speichert nur den Dateinamen');
$abs = Setting::logoAbsolutePath();
$this->assertEquals($testPath, $abs, 'logoAbsolutePath() zeigt in das Logo-Datenverzeichnis');
$this->assert(
!str_contains((string)$abs, '/public/'),
'Logo liegt außerhalb des Web-Roots'
);
// Altbestände mit webroot-relativem Präfix bleiben auffindbar, falls
// Migration 089 noch nicht gelaufen ist
Setting::setLogo('static/uploads/logo/' . $testFile);
$this->assertEquals(
$testPath,
Setting::logoAbsolutePath(),
'Legacy-Pfad wird auf das Logo-Verzeichnis abgebildet'
);
// deleteLogo() entfernt Datei und DB-Eintrag
if (!is_dir((string)Config::get('logo_dir'))) {
mkdir((string)Config::get('logo_dir'), 0755, true);
}
file_put_contents($testPath, 'dummy');
Setting::setLogo($testFile);
Setting::deleteLogo();
$this->assert(!file_exists($testPath), 'deleteLogo() entfernt die Datei aus data/logo');
$this->assert(empty(Setting::get()['logo_path']), 'deleteLogo() entfernt den Pfad');
$this->assert(Setting::logoAbsolutePath() === null, 'Ohne Logo liefert logoAbsolutePath() null');
// 3) Belege und Logo liegen getrennt und beide außerhalb von public/
$uploadDir = (string)Config::get('upload_dir');
$logoDir = (string)Config::get('logo_dir');
$this->assert(!str_contains($uploadDir, '/public/'), 'Belegverzeichnis liegt außerhalb des Web-Roots');
$this->assert($uploadDir !== $logoDir, 'Belege und Logo haben getrennte Verzeichnisse');
$this->assert(str_ends_with($uploadDir, '/data/belege'), 'Belege liegen in data/belege');
$this->assert(str_ends_with($logoDir, '/data/logo'), 'Logo liegt in data/logo');
// 3) Das Logo-Upload-Formular darf nicht in #settings-form verschachtelt sein –
// sonst verwirft der Browser das innere <form> und der Hochladen-Button
// postet an /settings statt an /settings/logo.
$view = file_get_contents(dirname(__DIR__) . '/src/Views/settings/form.php');
$this->assertNotEmpty($view, 'settings/form.php ist lesbar');
$settingsFormStart = strpos($view, '<form id="settings-form"');
$settingsFormEnd = strpos($view, '</form>', (int)$settingsFormStart);
$this->assert($settingsFormStart !== false && $settingsFormEnd !== false, '#settings-form ist im View vorhanden');
$inner = substr($view, (int)$settingsFormStart + 1, (int)$settingsFormEnd - (int)$settingsFormStart);
$this->assert(
!str_contains($inner, '<form '),
'Innerhalb von #settings-form steht kein weiteres <form>-Element'
);
$this->assert(
str_contains($view, '<form id="logo-upload-form"') && str_contains($view, 'action="/settings/logo"'),
'Eigenständiges #logo-upload-form mit action="/settings/logo" vorhanden'
);
$this->assert(
str_contains($view, 'name="logo" accept=".png,.jpg,.jpeg" form="logo-upload-form"'),
'Datei-Input ist per form-Attribut an #logo-upload-form gebunden'
);
}
}