test: add comprehensive tests for Discovery module components
- Add tests for Results registries (AttributeRegistry, InterfaceRegistry, TemplateRegistry) - Add tests for Processing components (ProcessingContext) - Add tests for Memory components (MemoryGuard) - Add tests for Value Objects (DiscoveryOptions, DiscoveryContext) All new tests pass and cover core functionality including: - Registry operations (add, get, has, serialize/deserialize, optimize) - Processing context (reflection caching, file context management) - Memory guard (memory checks, statistics, emergency cleanup) - Value objects (factory methods, scan types, cache keys, metrics)
This commit is contained in:
89
tests/Framework/Discovery/Memory/MemoryGuardTest.php
Normal file
89
tests/Framework/Discovery/Memory/MemoryGuardTest.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\Memory;
|
||||
|
||||
use App\Framework\Core\ValueObjects\Byte;
|
||||
use App\Framework\Discovery\Memory\DiscoveryMemoryManager;
|
||||
use App\Framework\Discovery\Memory\GuardAction;
|
||||
use App\Framework\Discovery\Memory\MemoryGuard;
|
||||
use App\Framework\Discovery\Memory\MemoryStatus;
|
||||
use App\Framework\Discovery\ValueObjects\MemoryStrategy;
|
||||
|
||||
describe('MemoryGuard', function () {
|
||||
beforeEach(function () {
|
||||
$this->memoryManager = new DiscoveryMemoryManager(
|
||||
strategy: MemoryStrategy::BATCH,
|
||||
memoryLimit: Byte::fromMegabytes(128),
|
||||
memoryPressureThreshold: 0.8,
|
||||
memoryMonitor: null,
|
||||
logger: null,
|
||||
eventDispatcher: null,
|
||||
clock: null
|
||||
);
|
||||
|
||||
$this->guard = new MemoryGuard($this->memoryManager);
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->guard)->toBeInstanceOf(MemoryGuard::class);
|
||||
});
|
||||
|
||||
it('can check memory status', function () {
|
||||
$result = $this->guard->check();
|
||||
|
||||
expect($result)->toBeInstanceOf(\App\Framework\Discovery\Memory\GuardResult::class);
|
||||
expect($result->actions)->toBeArray();
|
||||
});
|
||||
|
||||
it('tracks check counter', function () {
|
||||
$result1 = $this->guard->check();
|
||||
$result2 = $this->guard->check();
|
||||
$result3 = $this->guard->check();
|
||||
|
||||
// All should succeed
|
||||
expect($result1)->toBeInstanceOf(\App\Framework\Discovery\Memory\GuardResult::class);
|
||||
expect($result2)->toBeInstanceOf(\App\Framework\Discovery\Memory\GuardResult::class);
|
||||
expect($result3)->toBeInstanceOf(\App\Framework\Discovery\Memory\GuardResult::class);
|
||||
});
|
||||
|
||||
it('can get statistics', function () {
|
||||
$this->guard->check();
|
||||
$this->guard->check();
|
||||
|
||||
$stats = $this->guard->getStatistics();
|
||||
|
||||
expect($stats)->toBeInstanceOf(\App\Framework\Discovery\Memory\GuardStatistics::class);
|
||||
expect($stats->totalChecks)->toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('handles emergency callback', function () {
|
||||
$callbackCalled = false;
|
||||
$callback = function () use (&$callbackCalled) {
|
||||
$callbackCalled = true;
|
||||
};
|
||||
|
||||
$guard = new MemoryGuard($this->memoryManager, $callback);
|
||||
|
||||
// With normal memory, callback shouldn't be called
|
||||
$guard->check();
|
||||
|
||||
// Callback might be called in critical situations
|
||||
expect($callbackCalled)->toBeBool();
|
||||
});
|
||||
|
||||
it('can reset guard state', function () {
|
||||
$this->guard->check();
|
||||
$this->guard->check();
|
||||
|
||||
$statsBefore = $this->guard->getStatistics();
|
||||
expect($statsBefore->totalChecks)->toBeGreaterThanOrEqual(2);
|
||||
|
||||
$this->guard->reset();
|
||||
|
||||
$statsAfter = $this->guard->getStatistics();
|
||||
expect($statsAfter->totalChecks)->toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
108
tests/Framework/Discovery/Processing/ProcessingContextTest.php
Normal file
108
tests/Framework/Discovery/Processing/ProcessingContextTest.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\Processing;
|
||||
|
||||
use App\Framework\Core\ValueObjects\ClassName;
|
||||
use App\Framework\Discovery\Processing\ProcessingContext;
|
||||
use App\Framework\Discovery\ValueObjects\FileContext;
|
||||
use App\Framework\Filesystem\File;
|
||||
use App\Framework\Filesystem\ValueObjects\FilePath;
|
||||
use App\Framework\ReflectionLegacy\CachedReflectionProvider;
|
||||
use App\Framework\ReflectionLegacy\ReflectionProvider;
|
||||
|
||||
describe('ProcessingContext', function () {
|
||||
beforeEach(function () {
|
||||
$this->reflectionProvider = new CachedReflectionProvider();
|
||||
$this->context = new ProcessingContext($this->reflectionProvider);
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->context)->toBeInstanceOf(ProcessingContext::class);
|
||||
});
|
||||
|
||||
it('can set current file context', function () {
|
||||
$file = File::fromPath(FilePath::create('/test/file.php'));
|
||||
$fileContext = FileContext::fromFile($file);
|
||||
|
||||
$this->context->setCurrentFile($fileContext);
|
||||
|
||||
$current = $this->context->getCurrentFileContext();
|
||||
expect($current)->toBeInstanceOf(FileContext::class);
|
||||
expect($current)->toBe($fileContext);
|
||||
});
|
||||
|
||||
it('can get reflection for a class', function () {
|
||||
$className = ClassName::create('stdClass');
|
||||
|
||||
$reflection = $this->context->getReflection($className);
|
||||
|
||||
// stdClass should be reflectable
|
||||
expect($reflection)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for non-existent class', function () {
|
||||
$className = ClassName::create('NonExistent\\Class\\That\\Does\\Not\\Exist');
|
||||
|
||||
$reflection = $this->context->getReflection($className);
|
||||
|
||||
expect($reflection)->toBeNull();
|
||||
});
|
||||
|
||||
it('caches reflection for the same class', function () {
|
||||
$className = ClassName::create('stdClass');
|
||||
|
||||
$reflection1 = $this->context->getReflection($className);
|
||||
$reflection2 = $this->context->getReflection($className);
|
||||
|
||||
// Should return the same instance (cached)
|
||||
expect($reflection1)->toBe($reflection2);
|
||||
});
|
||||
|
||||
it('clears reflection cache when switching files', function () {
|
||||
$file1 = File::fromPath(FilePath::create('/test/file1.php'));
|
||||
$fileContext1 = FileContext::fromFile($file1);
|
||||
$this->context->setCurrentFile($fileContext1);
|
||||
|
||||
$className = ClassName::create('stdClass');
|
||||
$reflection1 = $this->context->getReflection($className);
|
||||
|
||||
// Switch to different file
|
||||
$file2 = File::fromPath(FilePath::create('/test/file2.php'));
|
||||
$fileContext2 = FileContext::fromFile($file2);
|
||||
$this->context->setCurrentFile($fileContext2);
|
||||
|
||||
// Reflection should be cleared
|
||||
$reflection2 = $this->context->getReflection($className);
|
||||
|
||||
// Should still work, but might be a new instance
|
||||
expect($reflection2)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('can cleanup resources', function () {
|
||||
$file = File::fromPath(FilePath::create('/test/file.php'));
|
||||
$fileContext = FileContext::fromFile($file);
|
||||
$this->context->setCurrentFile($fileContext);
|
||||
|
||||
$className = ClassName::create('stdClass');
|
||||
$this->context->getReflection($className);
|
||||
|
||||
$this->context->cleanup();
|
||||
|
||||
// After cleanup, current file context should be null
|
||||
$current = $this->context->getCurrentFileContext();
|
||||
expect($current)->toBeNull();
|
||||
});
|
||||
|
||||
it('handles reflection errors gracefully', function () {
|
||||
// Use a class that might cause reflection errors
|
||||
$className = ClassName::create('NonExistent\\Class\\With\\Parse\\Error');
|
||||
|
||||
$reflection = $this->context->getReflection($className);
|
||||
|
||||
// Should return null instead of throwing
|
||||
expect($reflection)->toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
189
tests/Framework/Discovery/Results/AttributeRegistryTest.php
Normal file
189
tests/Framework/Discovery/Results/AttributeRegistryTest.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\Results;
|
||||
|
||||
use App\Framework\Core\ValueObjects\ClassName;
|
||||
use App\Framework\Core\ValueObjects\MethodName;
|
||||
use App\Framework\Discovery\Results\AttributeRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\AttributeTarget;
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveredAttribute;
|
||||
|
||||
describe('AttributeRegistry', function () {
|
||||
beforeEach(function () {
|
||||
$this->registry = new AttributeRegistry();
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->registry)->toBeInstanceOf(AttributeRegistry::class);
|
||||
});
|
||||
|
||||
it('starts empty', function () {
|
||||
expect(count($this->registry))->toBe(0);
|
||||
});
|
||||
|
||||
it('can add attributes', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute);
|
||||
|
||||
expect(count($this->registry))->toBe(1);
|
||||
});
|
||||
|
||||
it('can retrieve attributes by class', function () {
|
||||
$attribute1 = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass1'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$attribute2 = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass2'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute1);
|
||||
$this->registry->add('Test\\Attribute', $attribute2);
|
||||
|
||||
$attributes = $this->registry->get('Test\\Attribute');
|
||||
|
||||
expect($attributes)->toBeArray();
|
||||
expect(count($attributes))->toBe(2);
|
||||
expect($attributes[0])->toBeInstanceOf(DiscoveredAttribute::class);
|
||||
expect($attributes[1])->toBeInstanceOf(DiscoveredAttribute::class);
|
||||
});
|
||||
|
||||
it('returns empty array for non-existent attribute class', function () {
|
||||
$attributes = $this->registry->get('NonExistent\\Attribute');
|
||||
|
||||
expect($attributes)->toBeArray();
|
||||
expect(count($attributes))->toBe(0);
|
||||
});
|
||||
|
||||
it('can check if attribute class exists', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
expect($this->registry->has('Test\\Attribute'))->toBeFalse();
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute);
|
||||
|
||||
expect($this->registry->has('Test\\Attribute'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can get all attribute classes', function () {
|
||||
$attribute1 = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass1'),
|
||||
attributeClass: 'Test\\Attribute1',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$attribute2 = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass2'),
|
||||
attributeClass: 'Test\\Attribute2',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute1', $attribute1);
|
||||
$this->registry->add('Test\\Attribute2', $attribute2);
|
||||
|
||||
$all = $this->registry->getAllTypes();
|
||||
|
||||
expect($all)->toBeArray();
|
||||
expect(count($all))->toBe(2);
|
||||
expect($all)->toContain('Test\\Attribute1');
|
||||
expect($all)->toContain('Test\\Attribute2');
|
||||
});
|
||||
|
||||
it('can serialize and deserialize', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute);
|
||||
|
||||
$array = $this->registry->toArray();
|
||||
expect($array)->toBeArray();
|
||||
expect($array)->toHaveKey('mappings');
|
||||
|
||||
$restored = AttributeRegistry::fromArray($array);
|
||||
expect($restored)->toBeInstanceOf(AttributeRegistry::class);
|
||||
expect(count($restored))->toBe(1);
|
||||
expect($restored->has('Test\\Attribute'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can optimize for memory', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute);
|
||||
|
||||
$this->registry->optimize();
|
||||
|
||||
// Should still contain the data after optimization
|
||||
expect($this->registry->has('Test\\Attribute'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can clear cache', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\Attribute',
|
||||
target: AttributeTarget::TARGET_CLASS
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\Attribute', $attribute);
|
||||
expect($this->registry->has('Test\\Attribute'))->toBeTrue();
|
||||
|
||||
$this->registry->clearCache();
|
||||
|
||||
// Cache clearing shouldn't remove the data
|
||||
expect($this->registry->has('Test\\Attribute'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('handles method attributes', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\MethodAttribute',
|
||||
target: AttributeTarget::METHOD,
|
||||
methodName: MethodName::create('myMethod')
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\MethodAttribute', $attribute);
|
||||
|
||||
$attributes = $this->registry->get('Test\\MethodAttribute');
|
||||
expect(count($attributes))->toBe(1);
|
||||
expect($attributes[0]->target)->toBe(AttributeTarget::METHOD);
|
||||
expect($attributes[0]->methodName)->not->toBeNull();
|
||||
});
|
||||
|
||||
it('handles property attributes', function () {
|
||||
$attribute = new DiscoveredAttribute(
|
||||
className: ClassName::create('Test\\MyClass'),
|
||||
attributeClass: 'Test\\PropertyAttribute',
|
||||
target: AttributeTarget::PROPERTY,
|
||||
propertyName: 'myProperty'
|
||||
);
|
||||
|
||||
$this->registry->add('Test\\PropertyAttribute', $attribute);
|
||||
|
||||
$attributes = $this->registry->get('Test\\PropertyAttribute');
|
||||
expect(count($attributes))->toBe(1);
|
||||
expect($attributes[0]->target)->toBe(AttributeTarget::PROPERTY);
|
||||
expect($attributes[0]->propertyName)->toBe('myProperty');
|
||||
});
|
||||
});
|
||||
|
||||
159
tests/Framework/Discovery/Results/InterfaceRegistryTest.php
Normal file
159
tests/Framework/Discovery/Results/InterfaceRegistryTest.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\Results;
|
||||
|
||||
use App\Framework\Core\ValueObjects\ClassName;
|
||||
use App\Framework\Discovery\Results\InterfaceRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\InterfaceMapping;
|
||||
|
||||
describe('InterfaceRegistry', function () {
|
||||
beforeEach(function () {
|
||||
$this->registry = new InterfaceRegistry();
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->registry)->toBeInstanceOf(InterfaceRegistry::class);
|
||||
});
|
||||
|
||||
it('starts empty', function () {
|
||||
expect(count($this->registry))->toBe(0);
|
||||
});
|
||||
|
||||
it('can add interface mappings', function () {
|
||||
$mapping = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass',
|
||||
file: '/path/to/MyClass.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
expect(count($this->registry))->toBe(1);
|
||||
});
|
||||
|
||||
it('can retrieve implementations for an interface', function () {
|
||||
$interface = ClassName::create('Test\\MyInterface');
|
||||
|
||||
$mapping1 = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass1',
|
||||
file: '/path/to/MyClass1.php'
|
||||
);
|
||||
|
||||
$mapping2 = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass2',
|
||||
file: '/path/to/MyClass2.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping1);
|
||||
$this->registry->add($mapping2);
|
||||
|
||||
$implementations = $this->registry->get($interface->getFullyQualified());
|
||||
|
||||
expect($implementations)->toBeArray();
|
||||
expect(count($implementations))->toBe(2);
|
||||
expect($implementations[0])->toBeInstanceOf(ClassName::class);
|
||||
expect($implementations[1])->toBeInstanceOf(ClassName::class);
|
||||
});
|
||||
|
||||
it('returns empty array for non-existent interface', function () {
|
||||
$interface = ClassName::create('Test\\NonExistentInterface');
|
||||
$implementations = $this->registry->get($interface->getFullyQualified());
|
||||
|
||||
expect($implementations)->toBeArray();
|
||||
expect(count($implementations))->toBe(0);
|
||||
});
|
||||
|
||||
it('can check if interface has implementations', function () {
|
||||
$interface = ClassName::create('Test\\MyInterface');
|
||||
|
||||
expect($this->registry->has($interface->getFullyQualified()))->toBeFalse();
|
||||
|
||||
$mapping = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass',
|
||||
file: '/path/to/MyClass.php'
|
||||
);
|
||||
$this->registry->add($mapping);
|
||||
|
||||
expect($this->registry->has($interface->getFullyQualified()))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can get all mappings', function () {
|
||||
$mapping1 = InterfaceMapping::create(
|
||||
interface: 'Test\\Interface1',
|
||||
implementation: 'Test\\Class1',
|
||||
file: '/path/to/Class1.php'
|
||||
);
|
||||
|
||||
$mapping2 = InterfaceMapping::create(
|
||||
interface: 'Test\\Interface2',
|
||||
implementation: 'Test\\Class2',
|
||||
file: '/path/to/Class2.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping1);
|
||||
$this->registry->add($mapping2);
|
||||
|
||||
$all = $this->registry->getAllMappings();
|
||||
|
||||
expect($all)->toBeArray();
|
||||
expect(count($all))->toBe(2);
|
||||
});
|
||||
|
||||
it('can serialize and deserialize', function () {
|
||||
$interface = ClassName::create('Test\\MyInterface');
|
||||
$mapping = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass',
|
||||
file: '/path/to/MyClass.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
$array = $this->registry->toArray();
|
||||
expect($array)->toBeArray();
|
||||
|
||||
$restored = InterfaceRegistry::fromArray($array);
|
||||
expect($restored)->toBeInstanceOf(InterfaceRegistry::class);
|
||||
expect(count($restored))->toBe(1);
|
||||
expect($restored->has($interface->getFullyQualified()))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can optimize for memory', function () {
|
||||
$interface = ClassName::create('Test\\MyInterface');
|
||||
$mapping = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass',
|
||||
file: '/path/to/MyClass.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
$this->registry->optimize();
|
||||
|
||||
// Should still contain the data after optimization
|
||||
expect($this->registry->has($interface->getFullyQualified()))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can clear cache', function () {
|
||||
$interface = ClassName::create('Test\\MyInterface');
|
||||
$mapping = InterfaceMapping::create(
|
||||
interface: 'Test\\MyInterface',
|
||||
implementation: 'Test\\MyClass',
|
||||
file: '/path/to/MyClass.php'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
expect($this->registry->has($interface->getFullyQualified()))->toBeTrue();
|
||||
|
||||
$this->registry->clearCache();
|
||||
|
||||
// Cache clearing shouldn't remove the data
|
||||
expect($this->registry->has($interface->getFullyQualified()))->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
143
tests/Framework/Discovery/Results/TemplateRegistryTest.php
Normal file
143
tests/Framework/Discovery/Results/TemplateRegistryTest.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\Results;
|
||||
|
||||
use App\Framework\Discovery\Results\TemplateRegistry;
|
||||
use App\Framework\Discovery\ValueObjects\TemplateMapping;
|
||||
|
||||
describe('TemplateRegistry', function () {
|
||||
beforeEach(function () {
|
||||
$this->registry = new TemplateRegistry();
|
||||
});
|
||||
|
||||
it('can be instantiated', function () {
|
||||
expect($this->registry)->toBeInstanceOf(TemplateRegistry::class);
|
||||
});
|
||||
|
||||
it('starts empty', function () {
|
||||
expect(count($this->registry))->toBe(0);
|
||||
});
|
||||
|
||||
it('can add template mappings', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
expect(count($this->registry))->toBe(1);
|
||||
});
|
||||
|
||||
it('can retrieve template by name', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
$found = $this->registry->get('template');
|
||||
|
||||
expect($found)->not->toBeNull();
|
||||
expect($found)->toBeInstanceOf(TemplateMapping::class);
|
||||
expect($found->name)->toBe('template');
|
||||
expect($found->path->toString())->toBe('test/template.html');
|
||||
});
|
||||
|
||||
it('returns null for non-existent template name', function () {
|
||||
$found = $this->registry->get('non-existent');
|
||||
|
||||
expect($found)->toBeNull();
|
||||
});
|
||||
|
||||
it('can check if template name exists', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
expect($this->registry->has('template'))->toBeFalse();
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
expect($this->registry->has('template'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can get all templates', function () {
|
||||
$mapping1 = TemplateMapping::create(
|
||||
name: 'template1',
|
||||
path: 'test/template1.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$mapping2 = TemplateMapping::create(
|
||||
name: 'template2',
|
||||
path: 'test/template2.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping1);
|
||||
$this->registry->add($mapping2);
|
||||
|
||||
$all = $this->registry->getAll();
|
||||
|
||||
expect($all)->toBeArray();
|
||||
expect(count($all))->toBe(2);
|
||||
});
|
||||
|
||||
it('can serialize and deserialize', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
$array = $this->registry->toArray();
|
||||
expect($array)->toBeArray();
|
||||
|
||||
$restored = TemplateRegistry::fromArray($array);
|
||||
expect($restored)->toBeInstanceOf(TemplateRegistry::class);
|
||||
expect(count($restored))->toBe(1);
|
||||
expect($restored->has('template'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can optimize for memory', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
|
||||
$this->registry->optimize();
|
||||
|
||||
// Should still contain the data after optimization
|
||||
expect($this->registry->has('template'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('can clear cache', function () {
|
||||
$mapping = TemplateMapping::create(
|
||||
name: 'template',
|
||||
path: 'test/template.html',
|
||||
type: 'view'
|
||||
);
|
||||
|
||||
$this->registry->add($mapping);
|
||||
expect($this->registry->has('template'))->toBeTrue();
|
||||
|
||||
$this->registry->clearCache();
|
||||
|
||||
// Cache clearing shouldn't remove the data
|
||||
expect($this->registry->has('template'))->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
135
tests/Framework/Discovery/ValueObjects/DiscoveryContextTest.php
Normal file
135
tests/Framework/Discovery/ValueObjects/DiscoveryContextTest.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\ValueObjects;
|
||||
|
||||
use App\Framework\Context\ExecutionContext;
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveryContext;
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveryOptions;
|
||||
use App\Framework\Discovery\ValueObjects\ScanType;
|
||||
|
||||
describe('DiscoveryContext', function () {
|
||||
it('can be instantiated', function () {
|
||||
$context = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($context)->toBeInstanceOf(DiscoveryContext::class);
|
||||
});
|
||||
|
||||
it('can track processed files', function () {
|
||||
$context = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($context->getProcessedFiles())->toBe(0);
|
||||
|
||||
$context->incrementProcessedFiles();
|
||||
$context->incrementProcessedFiles();
|
||||
|
||||
expect($context->getProcessedFiles())->toBe(2);
|
||||
});
|
||||
|
||||
it('can add and retrieve metrics', function () {
|
||||
$context = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
$context->addMetric('files_scanned', 10);
|
||||
$context->addMetric('errors', 2);
|
||||
|
||||
$metrics = $context->getMetrics();
|
||||
|
||||
expect($metrics)->toBeArray();
|
||||
expect($metrics)->toHaveKey('files_scanned');
|
||||
expect($metrics)->toHaveKey('errors');
|
||||
expect($metrics['files_scanned'])->toBe(10);
|
||||
expect($metrics['errors'])->toBe(2);
|
||||
});
|
||||
|
||||
it('can check if incremental', function () {
|
||||
$incrementalContext = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::INCREMENTAL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($incrementalContext->isIncremental())->toBeTrue();
|
||||
|
||||
$fullContext = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($fullContext->isIncremental())->toBeFalse();
|
||||
});
|
||||
|
||||
it('can check if should use cache', function () {
|
||||
$cachedOptions = new DiscoveryOptions(useCache: true);
|
||||
$context = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: $cachedOptions,
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($context->shouldUseCache())->toBeTrue();
|
||||
|
||||
$noCacheOptions = new DiscoveryOptions(useCache: false);
|
||||
$context2 = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: $noCacheOptions,
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
expect($context2->shouldUseCache())->toBeFalse();
|
||||
});
|
||||
|
||||
it('can generate cache key', function () {
|
||||
$context = new DiscoveryContext(
|
||||
paths: ['/test/path'],
|
||||
scanType: ScanType::FULL,
|
||||
options: new DiscoveryOptions(),
|
||||
startTime: new \DateTimeImmutable()
|
||||
);
|
||||
|
||||
$cacheKey = $context->getCacheKey();
|
||||
|
||||
expect($cacheKey)->toBeInstanceOf(\App\Framework\Cache\CacheKey::class);
|
||||
});
|
||||
|
||||
it('can use default factory method', function () {
|
||||
$context = DiscoveryContext::default();
|
||||
|
||||
expect($context)->toBeInstanceOf(DiscoveryContext::class);
|
||||
expect($context->paths)->toBeArray();
|
||||
});
|
||||
|
||||
it('can use comprehensive factory method', function () {
|
||||
$context = DiscoveryContext::comprehensive();
|
||||
|
||||
expect($context)->toBeInstanceOf(DiscoveryContext::class);
|
||||
});
|
||||
|
||||
it('can use minimal factory method', function () {
|
||||
$context = DiscoveryContext::minimal();
|
||||
|
||||
expect($context)->toBeInstanceOf(DiscoveryContext::class);
|
||||
expect($context->isIncremental())->toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Framework\Discovery\ValueObjects;
|
||||
|
||||
use App\Framework\Discovery\ValueObjects\DiscoveryOptions;
|
||||
use App\Framework\Discovery\ValueObjects\ScanType;
|
||||
|
||||
describe('DiscoveryOptions', function () {
|
||||
it('can be instantiated with default values', function () {
|
||||
$options = new DiscoveryOptions();
|
||||
|
||||
expect($options)->toBeInstanceOf(DiscoveryOptions::class);
|
||||
expect($options->scanType)->toBeInstanceOf(ScanType::class);
|
||||
expect($options->paths)->toBeArray();
|
||||
expect($options->useCache)->toBeBool();
|
||||
});
|
||||
|
||||
it('can be created with custom values', function () {
|
||||
$options = new DiscoveryOptions(
|
||||
scanType: ScanType::FULL,
|
||||
paths: ['/test/path1', '/test/path2'],
|
||||
useCache: true
|
||||
);
|
||||
|
||||
expect($options->scanType)->toBe(ScanType::FULL);
|
||||
expect($options->paths)->toBe(['/test/path1', '/test/path2']);
|
||||
expect($options->useCache)->toBeTrue();
|
||||
});
|
||||
|
||||
it('can use default factory method', function () {
|
||||
$options = DiscoveryOptions::default();
|
||||
|
||||
expect($options)->toBeInstanceOf(DiscoveryOptions::class);
|
||||
});
|
||||
|
||||
it('can use comprehensive factory method', function () {
|
||||
$options = DiscoveryOptions::comprehensive();
|
||||
|
||||
expect($options)->toBeInstanceOf(DiscoveryOptions::class);
|
||||
});
|
||||
|
||||
it('can use minimal factory method', function () {
|
||||
$options = DiscoveryOptions::minimal();
|
||||
|
||||
expect($options)->toBeInstanceOf(DiscoveryOptions::class);
|
||||
});
|
||||
|
||||
it('supports incremental scan type', function () {
|
||||
$options = new DiscoveryOptions(
|
||||
scanType: ScanType::INCREMENTAL,
|
||||
paths: ['/test/path'],
|
||||
useCache: false
|
||||
);
|
||||
|
||||
expect($options->scanType)->toBe(ScanType::INCREMENTAL);
|
||||
});
|
||||
|
||||
it('supports full scan type', function () {
|
||||
$options = new DiscoveryOptions(
|
||||
scanType: ScanType::FULL,
|
||||
paths: ['/test/path'],
|
||||
useCache: true
|
||||
);
|
||||
|
||||
expect($options->scanType)->toBe(ScanType::FULL);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user