clock = new FrozenClock(); $this->randomGenerator = new TestableRandomGenerator(); $this->csrfTokenGenerator = new CsrfTokenGenerator($this->randomGenerator); $this->sessionId = SessionId::fromString('testlazyinitsessionid1234567890ab'); }); describe('Session Component Lazy Initialization', function () { test('only used component keys appear in session data', function () { // 1. Session erstellen $session = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session->fromArray([]); // 2. Nur einige Komponenten verwenden $session->flash->add('info', 'Test message'); $session->csrf->generateToken('test_form'); // Bewusst NICHT verwenden: validation und form // 3. Session-Daten prüfen $sessionData = $session->all(); // 4. Nur verwendete Keys sollten existieren expect($sessionData)->toHaveKey(SessionKey::FLASH->value); expect($sessionData)->toHaveKey(SessionKey::CSRF->value); // 5. Nicht verwendete Keys sollten NICHT existieren expect($sessionData)->not->toHaveKey(SessionKey::VALIDATION_ERRORS->value); expect($sessionData)->not->toHaveKey(SessionKey::FORM_DATA->value); // 6. Inhalt der verwendeten Keys prüfen expect($sessionData[SessionKey::FLASH->value])->toHaveKey('info'); expect($sessionData[SessionKey::CSRF->value])->toHaveKey('test_form'); }); test('accessing component creates its key even if empty', function () { // 1. Session erstellen $session = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session->fromArray([]); // 2. Komponente zugreifen ohne Daten hinzuzufügen $errors = $session->validation->get('nonexistent_form'); // Sollte [] zurückgeben expect($errors)->toBe([]); // 3. Jetzt sollte der Key existieren (da Komponente initialisiert wurde) $sessionData = $session->all(); expect($sessionData)->toHaveKey(SessionKey::VALIDATION_ERRORS->value); expect($sessionData[SessionKey::VALIDATION_ERRORS->value])->toBe([]); }); test('component keys persist after session reload', function () { $storage = new InMemorySessionStorage(); // 1. Session mit gemischter Nutzung erstellen $session1 = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session1->fromArray([]); $session1->flash->add('success', 'Saved!'); $session1->csrf->generateToken('edit_form'); // validation und form werden NICHT verwendet // 2. Session speichern $storage->write($this->sessionId, $session1->all()); // 3. Session neu laden $loadedData = $storage->read($this->sessionId); $session2 = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session2->fromArray($loadedData); // 4. Nur die Keys die vorher verwendet wurden sollten existieren $reloadedData = $session2->all(); expect($reloadedData)->toHaveKey(SessionKey::FLASH->value); expect($reloadedData)->toHaveKey(SessionKey::CSRF->value); expect($reloadedData)->not->toHaveKey(SessionKey::VALIDATION_ERRORS->value); expect($reloadedData)->not->toHaveKey(SessionKey::FORM_DATA->value); // 5. Daten sollten korrekt geladen werden expect($session2->flash->get('success'))->toBe(['Saved!']); }); test('unused components can be accessed after session reload', function () { $storage = new InMemorySessionStorage(); // 1. Session mit teilweiser Nutzung $session1 = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session1->fromArray([]); $session1->flash->add('info', 'Test'); $storage->write($this->sessionId, $session1->all()); // 2. Session neu laden $loadedData = $storage->read($this->sessionId); $session2 = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session2->fromArray($loadedData); // 3. Bisher unverwendete Komponenten sollten funktionieren $session2->validation->add('new_form', ['field' => ['New error']]); $session2->form->store('new_form', ['data' => 'New data']); // 4. Nach Verwendung sollten die Keys existieren $finalData = $session2->all(); expect($finalData)->toHaveKey(SessionKey::VALIDATION_ERRORS->value); expect($finalData)->toHaveKey(SessionKey::FORM_DATA->value); // 5. Ursprüngliche Daten sollten erhalten bleiben expect($finalData)->toHaveKey(SessionKey::FLASH->value); }); test('simulates live system behavior from your example', function () { // 1. Simuliere eine typische Web-App Session $session = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session->fromArray([]); // 2. Simuliere Security Tracking (automatisch durch Framework) $session->security->updateActivity(); // 3. Simuliere CSRF Token Generierung für verschiedene Formulare $session->csrf->generateToken('form_bf9d2e47868b'); $session->csrf->generateToken('form_386bb8ff6647'); // 4. Flash wird initialisiert aber ist leer (typisch nach Redirect) // Simuliere: Flash wurde bereits abgerufen und ist jetzt leer $session->flash->get('any_type'); // Initialisiert das Array // 5. validation und form werden NICHT verwendet (kein Fehler, kein Form-Data) // 6. Prüfe Session-Daten (sollte dem Live-System ähneln) $sessionData = $session->all(); expect($sessionData)->toHaveKey('__security'); expect($sessionData)->toHaveKey('__csrf'); expect($sessionData)->toHaveKey('__flash'); expect($sessionData['__flash'])->toBe([]); // Leer, wie im Live-System // Diese Keys fehlen - das ist korrekt! expect($sessionData)->not->toHaveKey('__validation_errors'); expect($sessionData)->not->toHaveKey('__form_data'); // 7. CSRF sollte Tokens für verschiedene Formulare enthalten expect($sessionData['__csrf'])->toHaveKey('form_bf9d2e47868b'); expect($sessionData['__csrf'])->toHaveKey('form_386bb8ff6647'); }); test('components become available when first needed', function () { $storage = new InMemorySessionStorage(); // 1. Session wie im Live-System $existingData = [ '__security' => [ 'user_agent' => 'Mozilla/5.0 (Test Browser)', 'ip_address' => '127.0.0.1', 'last_activity' => time(), ], '__csrf' => [ 'test_form' => [ ['token' => 'abc123', 'created_at' => time(), 'used_at' => null], ], ], '__flash' => [], ]; $session = new Session($this->sessionId, $this->clock, $this->csrfTokenGenerator); $session->fromArray($existingData); // 2. Bisher fehlende Komponenten sind trotzdem verfügbar expect($session->validation->has('any_form'))->toBeFalse(); expect($session->form->has('any_form'))->toBeFalse(); // 3. Wenn sie verwendet werden, funktionieren sie $session->validation->add('contact_form', ['email' => ['Required']]); $session->form->store('contact_form', ['name' => 'John']); // 4. Jetzt sollten die Keys existieren $finalData = $session->all(); expect($finalData)->toHaveKey('__validation_errors'); expect($finalData)->toHaveKey('__form_data'); // 5. Bestehende Daten bleiben erhalten expect($finalData['__security']['user_agent'])->toBe('Mozilla/5.0 (Test Browser)'); expect($finalData['__csrf'])->toHaveKey('test_form'); expect($finalData['__flash'])->toBe([]); }); });