Files
duckbrain-toolbox/tests/group2_manifest_test.php
T

182 lines
6.4 KiB
PHP

<?php
use Toolbox\Catalog;
use Toolbox\Manifest;
use Toolbox\Resolver;
use Toolbox\Semver;
use Toolbox\ToolboxException;
Harness::suite('group2');
Harness::it('semver compara y satisface rangos', function () {
ok(Semver::satisfies('1.2.0', '>=1.0'));
ok(!Semver::satisfies('0.9.0', '>=1.0'));
ok(Semver::satisfies('1.2.3', '^1.2'));
ok(!Semver::satisfies('2.0.0', '^1.2'));
ok(Semver::satisfies('1.2.9', '~1.2.3'));
ok(!Semver::satisfies('1.3.0', '~1.2.3'));
ok(Semver::satisfies('1.0.0', '*'));
eq(0, Semver::compare('1.0.0', '1.0.0'));
ok(Semver::compare('1.0.1', '1.0.0') > 0);
ok(Semver::compare('1.0.0-beta', '1.0.0') < 0);
});
Harness::it('manifiesto válido parsea identidad, componentes y default', function () {
$m = Manifest::fromArray([
'name' => 'http',
'version' => '1.2.0',
'description' => 'Utilidades HTTP',
'components' => [
'curlRequest' => ['files' => ['src/Libs/CurlRequest.php']],
'aria2' => ['files' => ['src/Libs/Aria2.php']],
],
'default' => ['curlRequest', 'aria2'],
]);
eq('http', $m->name);
eq('1.2.0', $m->version);
eq(['curlRequest', 'aria2'], $m->expand(null));
eq(['aria2'], $m->expand('aria2'));
});
Harness::it('manifiesto sin name es inválido', function () {
throws(fn () => Manifest::fromArray(['version' => '1.0.0', 'components' => ['a' => ['files' => ['x']]]]));
});
Harness::it('manifiesto sin components es inválido', function () {
throws(fn () => Manifest::fromArray(['name' => 'x', 'version' => '1.0.0']));
});
Harness::it('default que referencia componente inexistente es inválido', function () {
throws(fn () => Manifest::fromArray([
'name' => 'x', 'version' => '1.0.0',
'components' => ['a' => ['files' => ['x']]],
'default' => ['nope'],
]));
});
Harness::it('paquete sin default y sin componente explícito falla', function () {
$m = Manifest::fromArray([
'name' => 'x', 'version' => '1.0.0',
'components' => ['a' => ['files' => ['x']]],
]);
throws(fn () => $m->expand(null));
});
Harness::it('resuelve dependencias en orden (dependencias primero)', function () {
$dir = tmpdir();
write_file($dir . '/http/duckbrain.json', json_encode([
'name' => 'http', 'version' => '1.0.0',
'components' => [
'curlRequest' => ['files' => ['src/Libs/CurlRequest.php']],
'compreFace' => [
'files' => ['src/Libs/CompreFace.php'],
'require' => ['http:curlRequest' => '>=1.0'],
],
],
], JSON_PRETTY_PRINT));
$resolver = new Resolver(new Catalog($dir));
$result = $resolver->resolve(['http:compreFace']);
eq([
['package' => 'http', 'component' => 'curlRequest'],
['package' => 'http', 'component' => 'compreFace'],
], $result);
rrmdir($dir);
});
Harness::it('require no satisfecho detiene con error', function () {
$dir = tmpdir();
write_file($dir . '/a/duckbrain.json', json_encode([
'name' => 'a', 'version' => '1.0.0',
'components' => [
'main' => ['files' => ['src/Libs/A.php'], 'require' => ['b:lib' => '>=2.0']],
],
]));
write_file($dir . '/b/duckbrain.json', json_encode([
'name' => 'b', 'version' => '1.0.0',
'components' => ['lib' => ['files' => ['src/Libs/B.php']]],
]));
$resolver = new Resolver(new Catalog($dir));
throws(fn () => $resolver->resolve(['a:main']));
rrmdir($dir);
});
Harness::it('ciclo de dependencias se detecta', function () {
$dir = tmpdir();
write_file($dir . '/a/duckbrain.json', json_encode([
'name' => 'a', 'version' => '1.0.0',
'components' => [
'x' => ['files' => ['src/Libs/A.php'], 'require' => ['a:y' => '*']],
'y' => ['files' => ['src/Libs/B.php'], 'require' => ['a:x' => '*']],
],
]));
$resolver = new Resolver(new Catalog($dir));
throws(fn () => $resolver->resolve(['a:x']));
rrmdir($dir);
});
Harness::it('la descripcion del componente prevalece y hereda del paquete', function () {
$m = Manifest::fromArray([
'name' => 'pkg',
'version' => '1.0.0',
'description' => 'Resumen del paquete',
'components' => [
'a' => ['files' => ['src/A.php'], 'description' => 'Componente A'],
'b' => ['files' => ['src/B.php']],
],
]);
eq('Componente A', $m->descriptionOf('a'), 'descripción propia gana');
eq('Resumen del paquete', $m->descriptionOf('b'), 'sin descripción propia hereda del paquete');
eq('Resumen del paquete', $m->descriptionOf(), 'sin componente: la del paquete');
$m2 = Manifest::fromArray(['name' => 'x', 'version' => '1.0.0', 'components' => ['c' => ['files' => ['c.php']]]]);
eq('', $m2->descriptionOf('c'), 'paquete sin texto produce cadena vacía (no null)');
throws(fn () => Manifest::fromArray([
'name' => 'y',
'version' => '1.0.0',
'components' => ['c' => ['files' => ['c.php'], 'description' => 7]],
]), 'description no-string es inválida');
});
Harness::it('core admite "none" como bloque con herencia completa', function () {
$m = Manifest::fromArray([
'name' => 'pkg',
'version' => '1.0.0',
'core' => 'none',
'components' => [
'a' => ['files' => ['src/A.php']],
'b' => ['files' => ['src/B.php'], 'core' => ['requires' => '>=0.2', 'tested' => '0.2']],
],
]);
ok($m->coreIndependent('a'), 'a hereda la independencia del paquete');
ok(!$m->coreIndependent('b'), 'b sobreescribe el bloque con su rango');
eq('>=0.2', $m->coreRequirement('b'));
eq('0.2', $m->testedCore('b'));
eq(null, $m->coreRequirement('a'), 'independiente no arrastra rangos');
$m2 = Manifest::fromArray([
'name' => 'pkg2',
'version' => '1.0.0',
'core' => ['requires' => '>=0.1'],
'components' => ['c' => ['files' => ['src/C.php'], 'core' => 'none']],
]);
ok($m2->coreIndependent('c'), 'componente declara none sobre rango de paquete');
eq(null, $m2->coreRequirement('c'), 'el rango del paquete no se filtra al bloque declarado none');
eq('>=0.1', $m2->coreRequirement());
throws(fn () => Manifest::fromArray([
'name' => 'bad', 'version' => '1.0.0', 'core' => 'otro',
'components' => ['x' => ['files' => ['x.php']]],
]), 'core string distinto de none es inválido');
});