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:
2025-11-10 01:39:57 +01:00
parent 9289344379
commit 43dd602509
7 changed files with 893 additions and 0 deletions

View 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');
});
});

View 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();
});
});

View 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();
});
});