assertSame('234567abcdefghijklmnopqrstuvwxyz', Tid::ALPHABET); $this->assertSame(32, strlen(Tid::ALPHABET)); } public function testLengthIs13(): void { $this->assertSame(13, Tid::LENGTH); } public function testEncodeProduces13Characters(): void { $tid = Tid::encode(1_000_000_000, 0); $this->assertSame(13, strlen($tid)); } public function testEncodeUsesOnlyS32Alphabet(): void { $tid = Tid::encode(1_000_000_000, 512); $this->assertSame(13, strspn($tid, Tid::ALPHABET)); } public function testEncodeZeroIsAllFirstChar(): void { // timestamp=0, clockId=0 → all bits 0 → every 5-bit group is 0 → '2' (first char of s32) $tid = Tid::encode(0, 0); $this->assertSame(str_repeat('2', 13), $tid); } public function testEncodeKnownVector(): void { // timestamp = 0x1_0000_0000 µs (4 294 967 296), clockId = 0 // value = (0x1_0000_0000 & ((1<<53)-1)) << 10 = 0x400_0000_0400 // Split into 13 × 5-bit groups and map through s32. // We just verify the length and alphabet; exact value is tested via roundtrip. $tid = Tid::encode(4_294_967_296, 0); $this->assertSame(13, strlen($tid)); $this->assertSame(13, strspn($tid, Tid::ALPHABET)); } public function testIsValidReturnsTrueForWellFormedTid(): void { $tid = Tid::encode(1_000_000_000, 1); $this->assertTrue(Tid::isValid($tid)); } public function testIsValidReturnsFalseForWrongLength(): void { $this->assertFalse(Tid::isValid('short')); $this->assertFalse(Tid::isValid(str_repeat('a', 14))); } public function testIsValidReturnsFalseForInvalidAlphabetCharacter(): void { // Replace the first char with '0' which is not in the s32 alphabet. $tid = Tid::encode(1_000_000_000, 0); $invalid = '0' . substr($tid, 1); $this->assertFalse(Tid::isValid($invalid)); } public function testNextProducesValidTid(): void { $this->assertTrue(Tid::isValid(Tid::next())); } public function testNextIsMonotonicallyIncreasing(): void { $previous = Tid::next(); for ($i = 0; $i < 10; $i++) { $current = Tid::next(); $this->assertGreaterThan($previous, $current, 'TIDs must be lexicographically increasing'); $previous = $current; } } public function testNextTidsAreLexicographicallySortable(): void { $tids = []; for ($i = 0; $i < 20; $i++) { $tids[] = Tid::next(); } $sorted = $tids; sort($sorted); $this->assertSame($tids, $sorted, 'Consecutive TIDs must already be in sorted order'); } }