Skip to content

Commit

Permalink
Core/Dependencies: start working on resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
klees committed Nov 13, 2023
1 parent d4edc81 commit 3a31c8d
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 0 deletions.
11 changes: 11 additions & 0 deletions components/ILIAS/Core/src/Dependencies/In.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,19 @@ public function __toString(): string
return $this->type->value . ": " . $this->name;
}

public function getName(): Name
{
return $this->name;
}

public function getType(): InType
{
return $this->type;
}

public function addDependant(Out $out)
{
$this->dependant[(string) $out] = $out;
$out->addDependency($this);
}
}
14 changes: 14 additions & 0 deletions components/ILIAS/Core/src/Dependencies/OfComponent.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ public function getComponent(): Component
return $this->component;
}

public function getComponentName(): string
{
return get_class($this->getComponent());
}

public function getInDependencies(): \Iterator
{
foreach ($this->dependencies as $d) {
if ($d instanceof In) {
yield $d;
}
}
}

// ArrayAccess

public function offsetExists($dependency_description): bool
Expand Down
5 changes: 5 additions & 0 deletions components/ILIAS/Core/src/Dependencies/Out.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,9 @@ public function __toString(): string
{
return $this->type->value . ": " . $this->name;
}

public function addDependency(In $in)
{
$this->dependencies[(string) $in] = $in;
}
}
79 changes: 79 additions & 0 deletions components/ILIAS/Core/src/Dependencies/Resolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Core\Dependencies;

class Resolver
{
/**
* @param OfComponent[]
* @return OfComponent[]
*/
public function resolveDependencies(OfComponent ...$components): array
{
foreach ($components as $component) {
foreach ($component->getInDependencies() as $d) {
switch ($d->getType()) {
case InType::PULL:
$this->resolvePull($d, $components);
break;
case InType::SEEK:
$this->resolveSeek($d, $components);
break;
}
}
}

return $components;
}

protected function resolvePull(In $in, array &$others): void
{
$candidate = null;

foreach ($others as $other) {
if ($other->offsetExists("PROVIDE: " . $in->getName())) {
if (!is_null($candidate)) {
throw new \LogicException(
"Dependency {$in->getName()} is provided (at least) twice. " .
"Once by {$candidate->getComponentName()} " .
"and by {$other->getComponentName()} "
);
}
$candidate = $other;
}
}

if (is_null($candidate)) {
throw new \LogicException("Could not resolve dependency for: " . (string) $in);
}

$in->addDependant($candidate["PROVIDE: " . $in->getName()]);
}

protected function resolveSeek(In $in, array &$others): void
{
foreach ($others as $other) {
if ($other->offsetExists("CONTRIBUTE: " . $in->getName())) {
$in->addDependant($other["CONTRIBUTE: " . $in->getName()]);
}
}
}
}
61 changes: 61 additions & 0 deletions components/ILIAS/Core/tests/Dependencies/OfComponentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Core\Tests\Dependencies;

use PHPUnit\Framework\TestCase;
use ILIAS\Core\Component;
use ILIAS\Core\Dependencies as D;

class OfComponentTest extends TestCase
{
protected Component $component;

public function setUp(): void
{
$this->component = $this->createMock(Component::class);
$this->of_component = new D\OfComponent(
$this->component
);
}

public function testGetComponent(): void
{
$this->assertEquals($this->component, $this->of_component->getComponent());
}

public function testInDependencies(): void
{
$name = TestInterface::class;

$out = new D\Out(D\OutType::PROVIDE, $name, []);
$in = new D\In(D\InType::PULL, $name);

$of_component = new D\OfComponent(
$this->component,
$in,
$out
);

$result = iterator_to_array($of_component->getInDependencies());

$this->assertEquals([$in], $result);
}
}
143 changes: 143 additions & 0 deletions components/ILIAS/Core/tests/Dependencies/ResolverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Core\Tests\Dependencies;

use PHPUnit\Framework\TestCase;
use ILIAS\Core\Dependencies\Resolver;
use ILIAS\Core\Dependencies as D;
use ILIAS\Core\Component;

class ResolverTest extends TestCase
{
protected Resolver $resolver;

public function setUp(): void
{
$this->resolver = new Resolver();
}

public function testEmptyComponentSet(): void
{
$result = $this->resolver->resolveDependencies();

$this->assertEquals([], $result);
}

public function testResolvePull(): void
{
$component = $this->createMock(Component::class);

$name = TestInterface::class;

$pull = new D\In(D\InType::PULL, $name);
$provide = new D\Out(D\OutType::PROVIDE, $name, []);

$c1 = new D\OfComponent($component, $pull);
$c2 = new D\OfComponent($component, $provide);

$result = $this->resolver->resolveDependencies($c1, $c2);

$pull = new D\In(D\InType::PULL, $name);
$provide = new D\Out(D\OutType::PROVIDE, $name, [$pull]);

$c1 = new D\OfComponent($component, $pull);
$c2 = new D\OfComponent($component, $provide);

$this->assertEquals([$c1, $c2], $result);
}

public function testPullFailsNotExistent(): void
{
$this->expectException(\LogicException::class);

$component = $this->createMock(Component::class);

$name = TestInterface::class;

$pull = new D\In(D\InType::PULL, $name);

$c1 = new D\OfComponent($component, $pull);

$this->resolver->resolveDependencies($c1);
}

public function testPullFailsDuplicate(): void
{
$this->expectException(\LogicException::class);

$component = $this->createMock(Component::class);

$name = TestInterface::class;

$pull = new D\In(D\InType::PULL, $name);
$provide1 = new D\Out(D\OutType::PROVIDE, $name, []);
$provide2 = new D\Out(D\OutType::PROVIDE, $name, []);

$c1 = new D\OfComponent($component, $pull);
$c2 = new D\OfComponent($component, $provide1);
$c3 = new D\OfComponent($component, $provide2);

$this->resolver->resolveDependencies($c1, $c2, $c3);
}

public function testEmptySeek(): void
{
$component = $this->createMock(Component::class);

$name = TestInterface::class;

$seek = new D\In(D\InType::SEEK, $name);

$c1 = new D\OfComponent($component, $seek);

$result = $this->resolver->resolveDependencies($c1);

$this->assertEquals([$c1], $result);
}

public function testResolveSeek(): void
{
$component = $this->createMock(Component::class);

$name = TestInterface::class;

$seek = new D\In(D\InType::SEEK, $name);
$contribute1 = new D\Out(D\OutType::CONTRIBUTE, $name, []);
$contribute2 = new D\Out(D\OutType::CONTRIBUTE, $name, []);

$c1 = new D\OfComponent($component, $seek);
$c2 = new D\OfComponent($component, $contribute1);
$c3 = new D\OfComponent($component, $contribute2);

$result = $this->resolver->resolveDependencies($c1, $c2, $c3);


$seek = new D\In(D\InType::SEEK, $name);
$contribute1 = new D\Out(D\OutType::CONTRIBUTE, $name, [$seek]);
$contribute2 = new D\Out(D\OutType::CONTRIBUTE, $name, [$seek]);

$c1 = new D\OfComponent($component, $seek);
$c2 = new D\OfComponent($component, $contribute1);
$c3 = new D\OfComponent($component, $contribute2);

$this->assertEquals([$c1, $c2, $c3], $result);
}
}

0 comments on commit 3a31c8d

Please sign in to comment.