Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
211
tests/Unit/Framework/NanoId/NanoIdGeneratorTest.php
Normal file
211
tests/Unit/Framework/NanoId/NanoIdGeneratorTest.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\NanoId\NanoId;
|
||||
use App\Framework\NanoId\NanoIdGenerator;
|
||||
use App\Framework\Random\SecureRandomGenerator;
|
||||
|
||||
it('creates generator with default settings', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generate();
|
||||
|
||||
expect($nanoId)->toBeInstanceOf(NanoId::class);
|
||||
expect($nanoId->getLength())->toBe(NanoId::DEFAULT_SIZE);
|
||||
});
|
||||
|
||||
it('creates generator with custom settings', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator(), 10, 'ABC123');
|
||||
$nanoId = $generator->generate();
|
||||
|
||||
expect($nanoId->getLength())->toBe(10);
|
||||
expect($nanoId->matchesAlphabet('ABC123'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('generates NanoId with custom size', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateWithSize(15);
|
||||
|
||||
expect($nanoId->getLength())->toBe(15);
|
||||
});
|
||||
|
||||
it('generates NanoId with custom alphabet', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateWithAlphabet('XYZ789');
|
||||
|
||||
expect($nanoId->matchesAlphabet('XYZ789'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('generates custom NanoId with size and alphabet', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateCustom(8, 'ABCD');
|
||||
|
||||
expect($nanoId->getLength())->toBe(8);
|
||||
expect($nanoId->matchesAlphabet('ABCD'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('generates safe NanoId', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateSafe();
|
||||
|
||||
expect($nanoId->isSafe())->toBeTrue();
|
||||
});
|
||||
|
||||
it('generates numeric NanoId', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateNumeric();
|
||||
|
||||
expect($nanoId->isNumeric())->toBeTrue();
|
||||
});
|
||||
|
||||
it('generates lowercase alphanumeric NanoId', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateLowercase();
|
||||
|
||||
expect($nanoId->toString())->toMatch('/^[0-9a-z]+$/');
|
||||
});
|
||||
|
||||
it('generates uppercase alphanumeric NanoId', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateUppercase();
|
||||
|
||||
expect($nanoId->toString())->toMatch('/^[0-9A-Z]+$/');
|
||||
});
|
||||
|
||||
it('generates NanoId for entity types', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
|
||||
$userNanoId = $generator->generateForEntity('user');
|
||||
expect($userNanoId->toString())->toStartWith('usr_');
|
||||
|
||||
$orderNanoId = $generator->generateForEntity('order');
|
||||
expect($orderNanoId->toString())->toStartWith('ord_');
|
||||
|
||||
$customNanoId = $generator->generateForEntity('widget');
|
||||
expect($customNanoId->toString())->toStartWith('wid_');
|
||||
});
|
||||
|
||||
it('generates time-prefixed NanoId', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$nanoId = $generator->generateTimePrefixed();
|
||||
|
||||
expect($nanoId->toString())->toContain('_');
|
||||
|
||||
// Check that prefix is a valid base36 timestamp
|
||||
$parts = explode('_', $nanoId->toString());
|
||||
expect($parts)->toHaveCount(2);
|
||||
|
||||
$timestamp = base_convert($parts[0], 36, 10);
|
||||
expect($timestamp)->toBeNumeric();
|
||||
expect((int)$timestamp)->toBeLessThanOrEqual(time());
|
||||
expect((int)$timestamp)->toBeGreaterThan(time() - 10); // Within last 10 seconds
|
||||
});
|
||||
|
||||
it('generates batch of unique NanoIds', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$batch = $generator->generateBatch(100);
|
||||
|
||||
expect($batch)->toHaveCount(100);
|
||||
expect($batch[0])->toBeInstanceOf(NanoId::class);
|
||||
|
||||
// Check uniqueness
|
||||
$values = array_map(fn ($id) => $id->toString(), $batch);
|
||||
$uniqueValues = array_unique($values);
|
||||
expect($uniqueValues)->toHaveCount(100);
|
||||
});
|
||||
|
||||
it('validates NanoIds correctly', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
|
||||
$validId = $generator->generate()->toString();
|
||||
expect($generator->isValid($validId))->toBeTrue();
|
||||
|
||||
expect($generator->isValid(''))->toBeFalse();
|
||||
expect($generator->isValid(str_repeat('a', 256)))->toBeFalse();
|
||||
|
||||
// Test with custom alphabet generator
|
||||
$customGenerator = new NanoIdGenerator(new SecureRandomGenerator(), 10, 'ABC');
|
||||
expect($customGenerator->isValid('ABCABC'))->toBeTrue();
|
||||
expect($customGenerator->isValid('XYZ123'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('creates generator using factory methods', function () {
|
||||
$randomGen = new SecureRandomGenerator();
|
||||
|
||||
$defaultGenerator = NanoIdGenerator::create($randomGen);
|
||||
expect($defaultGenerator->generate())->toBeInstanceOf(NanoId::class);
|
||||
|
||||
$safeGenerator = NanoIdGenerator::createSafe($randomGen);
|
||||
expect($safeGenerator->generate()->isSafe())->toBeTrue();
|
||||
|
||||
$numericGenerator = NanoIdGenerator::createNumeric($randomGen);
|
||||
expect($numericGenerator->generate()->isNumeric())->toBeTrue();
|
||||
});
|
||||
|
||||
it('throws exception for invalid default size', function () {
|
||||
$randomGen = new SecureRandomGenerator();
|
||||
expect(fn () => new NanoIdGenerator($randomGen, 0))->toThrow(InvalidArgumentException::class, 'Default size must be between 1 and 255');
|
||||
expect(fn () => new NanoIdGenerator($randomGen, 256))->toThrow(InvalidArgumentException::class, 'Default size must be between 1 and 255');
|
||||
});
|
||||
|
||||
it('throws exception for empty default alphabet', function () {
|
||||
$randomGen = new SecureRandomGenerator();
|
||||
expect(fn () => new NanoIdGenerator($randomGen, 21, ''))->toThrow(InvalidArgumentException::class, 'Default alphabet cannot be empty');
|
||||
});
|
||||
|
||||
it('throws exception for invalid batch count', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
|
||||
expect(fn () => $generator->generateBatch(0))->toThrow(InvalidArgumentException::class, 'Count must be positive');
|
||||
expect(fn () => $generator->generateBatch(10001))->toThrow(InvalidArgumentException::class, 'Batch size cannot exceed 10000');
|
||||
});
|
||||
|
||||
it('throws exception for invalid generation parameters', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
|
||||
// Test invalid size
|
||||
expect(fn () => $generator->generateWithSize(0))->toThrow(InvalidArgumentException::class, 'Size must be between 1 and 255');
|
||||
expect(fn () => $generator->generateWithSize(256))->toThrow(InvalidArgumentException::class, 'Size must be between 1 and 255');
|
||||
|
||||
// Test empty alphabet
|
||||
expect(fn () => $generator->generateWithAlphabet(''))->toThrow(InvalidArgumentException::class, 'Alphabet cannot be empty');
|
||||
|
||||
// Test alphabet too long
|
||||
$longAlphabet = str_repeat('a', 256);
|
||||
expect(fn () => $generator->generateWithAlphabet($longAlphabet))->toThrow(InvalidArgumentException::class, 'Alphabet cannot exceed 255 characters');
|
||||
});
|
||||
|
||||
it('generates different entity type prefixes correctly', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
|
||||
$prefixes = [
|
||||
'user' => 'usr_',
|
||||
'order' => 'ord_',
|
||||
'product' => 'prd_',
|
||||
'session' => 'ses_',
|
||||
'token' => 'tok_',
|
||||
'transaction' => 'txn_',
|
||||
'invoice' => 'inv_',
|
||||
'customer' => 'cus_',
|
||||
'payment' => 'pay_',
|
||||
'subscription' => 'sub_',
|
||||
];
|
||||
|
||||
foreach ($prefixes as $entity => $expectedPrefix) {
|
||||
$nanoId = $generator->generateForEntity($entity);
|
||||
expect($nanoId->toString())->toStartWith($expectedPrefix);
|
||||
}
|
||||
});
|
||||
|
||||
it('generates unique IDs across multiple calls', function () {
|
||||
$generator = new NanoIdGenerator(new SecureRandomGenerator());
|
||||
$ids = [];
|
||||
$count = 1000;
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$ids[] = $generator->generate()->toString();
|
||||
}
|
||||
|
||||
$uniqueIds = array_unique($ids);
|
||||
expect(count($uniqueIds))->toBe($count);
|
||||
});
|
||||
136
tests/Unit/Framework/NanoId/NanoIdTest.php
Normal file
136
tests/Unit/Framework/NanoId/NanoIdTest.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\NanoId\NanoId;
|
||||
|
||||
it('creates NanoId from string', function () {
|
||||
$value = 'test123ABC';
|
||||
$nanoId = NanoId::fromString($value);
|
||||
|
||||
expect($nanoId->toString())->toBe($value);
|
||||
expect($nanoId->getValue())->toBe($value);
|
||||
});
|
||||
|
||||
it('validates NanoId alphabet matching', function () {
|
||||
$nanoId = NanoId::fromString('ABC123');
|
||||
|
||||
expect($nanoId->matchesAlphabet('ABC123'))->toBeTrue();
|
||||
expect($nanoId->matchesAlphabet('XYZ'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('checks if NanoId is default alphabet', function () {
|
||||
$defaultId = NanoId::fromString('abcDEF123_-');
|
||||
expect($defaultId->isDefault())->toBeTrue();
|
||||
|
||||
$nonDefaultId = NanoId::fromString('abc!@#');
|
||||
expect($nonDefaultId->isDefault())->toBeFalse();
|
||||
});
|
||||
|
||||
it('checks if NanoId is safe alphabet', function () {
|
||||
$safeId = NanoId::fromString('abcDEF23456789');
|
||||
expect($safeId->isSafe())->toBeTrue();
|
||||
|
||||
$unsafeId = NanoId::fromString('abc0O1I');
|
||||
expect($unsafeId->isSafe())->toBeFalse();
|
||||
});
|
||||
|
||||
it('checks if NanoId is numeric', function () {
|
||||
$numericId = NanoId::fromString('123456789');
|
||||
expect($numericId->isNumeric())->toBeTrue();
|
||||
|
||||
$alphaId = NanoId::fromString('abc123');
|
||||
expect($alphaId->isNumeric())->toBeFalse();
|
||||
});
|
||||
|
||||
it('gets NanoId length correctly', function () {
|
||||
$nanoId = NanoId::fromString('12345');
|
||||
expect($nanoId->getLength())->toBe(5);
|
||||
});
|
||||
|
||||
it('checks equality between NanoIds', function () {
|
||||
$value = 'sameId123';
|
||||
$nanoId1 = NanoId::fromString($value);
|
||||
$nanoId2 = NanoId::fromString($value);
|
||||
$nanoId3 = NanoId::fromString('differentId');
|
||||
|
||||
expect($nanoId1->equals($nanoId2))->toBeTrue();
|
||||
expect($nanoId1->equals($nanoId3))->toBeFalse();
|
||||
});
|
||||
|
||||
it('adds prefix to NanoId', function () {
|
||||
$nanoId = NanoId::fromString('abc123');
|
||||
$prefixed = $nanoId->withPrefix('user_');
|
||||
|
||||
expect($prefixed->toString())->toBe('user_abc123');
|
||||
});
|
||||
|
||||
it('adds suffix to NanoId', function () {
|
||||
$nanoId = NanoId::fromString('abc123');
|
||||
$suffixed = $nanoId->withSuffix('_v2');
|
||||
|
||||
expect($suffixed->toString())->toBe('abc123_v2');
|
||||
});
|
||||
|
||||
it('truncates NanoId', function () {
|
||||
$nanoId = NanoId::fromString('verylongnanoid123456');
|
||||
$truncated = $nanoId->truncate(10);
|
||||
|
||||
expect($truncated->toString())->toBe('verylongna');
|
||||
expect($truncated->getLength())->toBe(10);
|
||||
});
|
||||
|
||||
it('throws exception for empty NanoId', function () {
|
||||
expect(fn () => NanoId::fromString(''))->toThrow(InvalidArgumentException::class, 'NanoId cannot be empty');
|
||||
});
|
||||
|
||||
it('throws exception for NanoId exceeding 255 characters', function () {
|
||||
$longString = str_repeat('a', 256);
|
||||
expect(fn () => NanoId::fromString($longString))->toThrow(InvalidArgumentException::class, 'NanoId cannot exceed 255 characters');
|
||||
});
|
||||
|
||||
it('throws exception for empty prefix', function () {
|
||||
$nanoId = NanoId::fromString('test');
|
||||
expect(fn () => $nanoId->withPrefix(''))->toThrow(InvalidArgumentException::class, 'Prefix cannot be empty');
|
||||
});
|
||||
|
||||
it('throws exception for empty suffix', function () {
|
||||
$nanoId = NanoId::fromString('test');
|
||||
expect(fn () => $nanoId->withSuffix(''))->toThrow(InvalidArgumentException::class, 'Suffix cannot be empty');
|
||||
});
|
||||
|
||||
it('throws exception for invalid truncate length', function () {
|
||||
$nanoId = NanoId::fromString('test');
|
||||
expect(fn () => $nanoId->truncate(0))->toThrow(InvalidArgumentException::class, 'Length must be positive');
|
||||
});
|
||||
|
||||
it('converts NanoId to string using magic method', function () {
|
||||
$nanoId = NanoId::fromString('test123');
|
||||
|
||||
expect((string)$nanoId)->toBe('test123');
|
||||
});
|
||||
|
||||
it('does not truncate when length is greater than NanoId length', function () {
|
||||
$nanoId = NanoId::fromString('short');
|
||||
$truncated = $nanoId->truncate(10);
|
||||
|
||||
expect($truncated->toString())->toBe('short');
|
||||
expect($truncated->equals($nanoId))->toBeTrue();
|
||||
});
|
||||
|
||||
it('validates alphabet patterns correctly', function () {
|
||||
$defaultId = NanoId::fromString('abc123DEF_-');
|
||||
expect($defaultId->matchesAlphabet(NanoId::DEFAULT_ALPHABET))->toBeTrue();
|
||||
|
||||
$safeId = NanoId::fromString('abc23456789DEF');
|
||||
expect($safeId->matchesAlphabet(NanoId::SAFE_ALPHABET))->toBeTrue();
|
||||
|
||||
$numericId = NanoId::fromString('123456789');
|
||||
expect($numericId->matchesAlphabet(NanoId::NUMBERS))->toBeTrue();
|
||||
|
||||
$lowercaseId = NanoId::fromString('abc123def');
|
||||
expect($lowercaseId->matchesAlphabet(NanoId::LOWERCASE_ALPHANUMERIC))->toBeTrue();
|
||||
|
||||
$uppercaseId = NanoId::fromString('ABC123DEF');
|
||||
expect($uppercaseId->matchesAlphabet(NanoId::UPPERCASE_ALPHANUMERIC))->toBeTrue();
|
||||
});
|
||||
Reference in New Issue
Block a user