new ReleaseStatus(ReleaseState::Untested, '5.3.0')); } public function testTheTestCaseDefaultIsReleased(): void { self::assertTrue(ReleaseGate::status()->writable()); ReleaseGate::assertWritable(7); } public function testAssertWritableThrowsTheLockWithTheStatus(): void { $this->untested(); try { ReleaseGate::assertWritable(7); self::fail('an untested Divi must lock writes'); } catch (DiviLocked $locked) { self::assertSame('5.3.0', $locked->status->version); self::assertToolError($locked->toError(), 'divi_untested'); } } public function testProbingAllowsOnlyThatPostAndOnlyMeanwhile(): void { $this->untested(); $result = ReleaseGate::whileProbing(41, static function (): string { ReleaseGate::assertWritable(41); return 'written'; }); self::assertSame('written', $result); foreach ([static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertWritable(42)), static fn () => ReleaseGate::whileProbing(41, static fn () => ReleaseGate::assertWritable()), static fn () => ReleaseGate::assertWritable(41)] as $attempt) { try { $attempt(); self::fail('only post 41, only while probing'); } catch (DiviLocked) { self::addToAssertionCount(1); } } } public function testProbingEndsEvenWhenTheWriteThrows(): void { $this->untested(); try { ReleaseGate::whileProbing(41, static function (): never { throw new RuntimeException('boom'); }); } catch (RuntimeException) { } $this->expectException(DiviLocked::class); ReleaseGate::assertWritable(41); } public function testStatusIsComputedOncePerRequestUntilForgotten(): void { $calls = 0; ReleaseGate::useResolver(static function () use (&$calls): ReleaseStatus { ++$calls; return ReleaseStatus::released('5.2.1'); }); ReleaseGate::status(); ReleaseGate::status(); self::assertSame(1, $calls); ReleaseGate::forget(); ReleaseGate::status(); self::assertSame(2, $calls); } public function testAFailingResolverLocksWrites(): void { ReleaseGate::useResolver(static function (): never { throw new RuntimeException('theme API gone'); }); $log = (string) tempnam(sys_get_temp_dir(), 'lit-mcp-log'); $previous = ini_set('error_log', $log); try { $status = ReleaseGate::status(); } finally { ini_set('error_log', (string) $previous); } self::assertSame(ReleaseState::Incompatible, $status->state); self::assertStringContainsString('theme API gone', (string) file_get_contents($log)); unlink($log); $this->expectException(DiviLocked::class); ReleaseGate::assertWritable(); } public function testFindsTheLockInsideAWrappedFailure(): void { $locked = new DiviLocked(new ReleaseStatus(ReleaseState::Untested, '5.3.0')); $wrapped = WriteFailed::rolledBack('Nicht gespeichert.', new RuntimeException('draft', 0, $locked)); self::assertSame($locked, DiviLocked::in($wrapped)); self::assertNull(DiviLocked::in(new RuntimeException('other'))); } }