* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD * @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE) * @link https://github.com/tecnickcom/tc-lib-pdf * * This file is part of tc-lib-pdf software library. */ namespace Test; use Com\Tecnick\Pdf\CSS\CascadeContext; class CascadeContextTest extends TestUtil { public function testInitialStateHasZeroSourceOrder(): void { $ctx = new CascadeContext(); $this->assertSame(0, $ctx->getTotalRulesProcessed()); } public function testGetNextNormalSourceOrderIncrementsCounter(): void { $ctx = new CascadeContext(); $order1 = $ctx->getNextNormalSourceOrder(); $order2 = $ctx->getNextNormalSourceOrder(); $order3 = $ctx->getNextNormalSourceOrder(); $this->assertSame(1, $order1); $this->assertSame(2, $order2); $this->assertSame(3, $order3); $this->assertSame(3, $ctx->getTotalRulesProcessed()); } public function testGetNextImportantSourceOrderStartsAboveNormalRange(): void { $ctx = new CascadeContext(); // Normal rules $ctx->getNextNormalSourceOrder(); $ctx->getNextNormalSourceOrder(); // First important rule should start at MIN_IMPORTANT_SOURCE_ORDER $importantOrder = $ctx->getNextImportantSourceOrder(); $this->assertSame(CascadeContext::MIN_IMPORTANT_SOURCE_ORDER + 1, $importantOrder); $this->assertGreaterThan(CascadeContext::INLINE_STYLE_SOURCE_ORDER, $importantOrder); } public function testImportantAndNormalCountersAreIndependent(): void { $ctx = new CascadeContext(); $normal1 = $ctx->getNextNormalSourceOrder(); $important1 = $ctx->getNextImportantSourceOrder(); $normal2 = $ctx->getNextNormalSourceOrder(); $important2 = $ctx->getNextImportantSourceOrder(); $this->assertSame(1, $normal1); $this->assertSame(CascadeContext::MIN_IMPORTANT_SOURCE_ORDER + 1, $important1); $this->assertSame(2, $normal2); $this->assertSame(CascadeContext::MIN_IMPORTANT_SOURCE_ORDER + 2, $important2); } public function testInlineStyleSourceOrderIsMaximumNormalValue(): void { $inlineOrder = CascadeContext::getInlineStyleSourceOrder(); $this->assertSame(10000000, $inlineOrder); $this->assertGreaterThan(CascadeContext::MAX_NORMAL_SOURCE_ORDER, $inlineOrder); $this->assertLessThan(CascadeContext::MIN_IMPORTANT_SOURCE_ORDER, $inlineOrder); } public function testSetCurrentSourceTypeStoresAndRetrievesValue(): void { $ctx = new CascadeContext(); $this->assertSame('embedded', $ctx->getCurrentSourceType()); $ctx->setCurrentSourceType('external'); $this->assertSame('external', $ctx->getCurrentSourceType()); $ctx->setCurrentSourceType('inline'); $this->assertSame('inline', $ctx->getCurrentSourceType()); } public function testResetClearsAllCountersAndState(): void { $ctx = new CascadeContext(); // Add some rules $ctx->setCurrentSourceType('external'); $ctx->getNextNormalSourceOrder(); $ctx->getNextNormalSourceOrder(); $ctx->getNextImportantSourceOrder(); $this->assertGreaterThan(0, $ctx->getTotalRulesProcessed()); $this->assertSame('external', $ctx->getCurrentSourceType()); // Reset $ctx->reset(); $this->assertSame(0, $ctx->getTotalRulesProcessed()); $this->assertSame('embedded', $ctx->getCurrentSourceType()); } public function testMultipleSourcesCanBeProcessedSequentially(): void { $ctx = new CascadeContext(); // External stylesheet: 3 rules $ctx->setCurrentSourceType('external'); $ctx->getNextNormalSourceOrder(); $ctx->getNextNormalSourceOrder(); $ext3 = $ctx->getNextNormalSourceOrder(); // Embedded style: 2 rules $ctx->setCurrentSourceType('embedded'); $emb1 = $ctx->getNextNormalSourceOrder(); $emb2 = $ctx->getNextNormalSourceOrder(); // Inline style: 1 rule $ctx->setCurrentSourceType('inline'); $inl1 = $ctx->getNextNormalSourceOrder(); // Verify ordering: external < embedded < inline $this->assertLessThan($emb1, $ext3); $this->assertLessThan($inl1, $emb2); $this->assertSame(6, $ctx->getTotalRulesProcessed()); } public function testSourceOrderValuesRemainBelowImportantRange(): void { $ctx = new CascadeContext(); // Generate many normal rules for ($i = 0; $i < 100; ++$i) { $order = $ctx->getNextNormalSourceOrder(); $this->assertLessThanOrEqual( CascadeContext::MAX_NORMAL_SOURCE_ORDER, $order, "Normal source order exceeded max at iteration {$i}", ); } // Important rules should still be higher $importantOrder = $ctx->getNextImportantSourceOrder(); $this->assertGreaterThan(CascadeContext::MAX_NORMAL_SOURCE_ORDER, $importantOrder); } public function testCascadePrecedenceForDeterminism(): void { // This test verifies the precedence model: // normal rules < inline styles < !important rules $normalMax = CascadeContext::MAX_NORMAL_SOURCE_ORDER; $inlineOrder = CascadeContext::getInlineStyleSourceOrder(); $importantMin = CascadeContext::MIN_IMPORTANT_SOURCE_ORDER; // Verify cascade ordering: normal < inline < important $this->assertLessThan($inlineOrder, $normalMax); $this->assertLessThan($importantMin, $inlineOrder); } }