diff --git a/src/Facades/Quantum.php b/src/Facades/Quantum.php index 7451739..8ab92eb 100644 --- a/src/Facades/Quantum.php +++ b/src/Facades/Quantum.php @@ -4,6 +4,7 @@ namespace Aether\Facades; +use Aether\Circuit\BatchBuilder; use Aether\Circuit\CircuitBuilder; use Aether\Contracts\QuantumDevice; use Aether\Entropy\EntropyGenerator; @@ -17,8 +18,10 @@ /** * Facade for the QuantumManager. * - * @method static QuantumDevice driver(?string $name = null) + * @method static string getDefaultDriver() + * @method static QuantumDevice driver(string|\UnitEnum|null $driver = null) * @method static CircuitBuilder circuit(?string $driver = null) + * @method static BatchBuilder batch(array $circuits, ?string $driver = null) * @method static EntropyGenerator entropy(?string $driver = null) * @method static \Aether\Bridge\PythonBridge bridge() * @method static void extend(string $name, Closure $callback) diff --git a/tests/Unit/Facades/QuantumFacadeTest.php b/tests/Unit/Facades/QuantumFacadeTest.php new file mode 100644 index 0000000..48cd494 --- /dev/null +++ b/tests/Unit/Facades/QuantumFacadeTest.php @@ -0,0 +1,74 @@ + method name => annotated return type */ +function facadeMethodAnnotations(): array +{ + $docblock = (string) (new ReflectionClass(Quantum::class))->getDocComment(); + + preg_match_all('/@method\s+static\s+(?:(.+?)\s+)?([A-Za-z_]\w*)\(/', $docblock, $matches, PREG_SET_ORDER); + + $annotations = []; + + foreach ($matches as $match) { + $annotations[$match[2]] = $match[1] !== '' ? $match[1] : null; + } + + return $annotations; +} + +/** @return array method name => reflection, every public method callable through the facade */ +function managerPublicMethods(): array +{ + $methods = []; + + foreach ((new ReflectionClass(QuantumManager::class))->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if (! $method->isStatic() && ! $method->isConstructor() && ! str_starts_with($method->getName(), '__')) { + $methods[$method->getName()] = $method; + } + } + + return $methods; +} + +it('annotates every public method QuantumManager declares itself', function () { + $declared = array_filter( + managerPublicMethods(), + fn (ReflectionMethod $method): bool => $method->getDeclaringClass()->getName() === QuantumManager::class, + ); + + expect(array_values(array_diff(array_keys($declared), array_keys(facadeMethodAnnotations()))))->toBe([]); +}); + +it('does not annotate methods the manager no longer has', function () { + $stale = array_diff(array_keys(facadeMethodAnnotations()), array_keys(managerPublicMethods())); + + expect(array_values($stale))->toBe([]); +}); + +it('annotates each method with the return type the manager declares', function () { + $methods = managerPublicMethods(); + + foreach (facadeMethodAnnotations() as $name => $annotated) { + $declared = $methods[$name]->getReturnType(); + + if (! $declared instanceof ReflectionNamedType || $annotated === null) { + continue; + } + + $expected = $declared->isBuiltin() ? $declared->getName() : basename(str_replace('\\', '/', $declared->getName())); + $actual = basename(str_replace('\\', '/', $annotated)); + + expect($actual)->toBe($expected, "@method {$name}() is annotated as returning {$annotated}, the manager returns {$declared->getName()}"); + } +});