Skip to content

Commit d0cdc1d

Browse files
committed
Add tests with 100% coverage for Algorithm\ShortestPath
1 parent 82c3b61 commit d0cdc1d

File tree

4 files changed

+281
-58
lines changed

4 files changed

+281
-58
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
use Fhaculty\Graph\Graph;
4+
use Fhaculty\Graph\Vertex;
5+
use Fhaculty\Graph\Algorithm\ShortestPath\Base as ShortestPathAlg;
6+
7+
abstract class BaseShortestPathTest extends TestCase
8+
{
9+
/**
10+
*
11+
* @param Vertex $vertex
12+
* @return ShortestPathAlg
13+
*/
14+
abstract protected function createAlg(Vertex $vertex);
15+
16+
abstract public function testGraphParallelNegative();
17+
18+
public function testGraphTrivial()
19+
{
20+
// 1
21+
$graph = new Graph();
22+
$v1 = $graph->createVertex(1);
23+
24+
$alg = $this->createAlg($v1);
25+
26+
$this->assertFalse($alg->hasVertex($v1));
27+
//$this->assertEquals(0, $alg->getDistance($v1));
28+
$this->assertEquals(array(), $alg->getDistanceMap());
29+
$this->assertEquals(array(), $alg->getEdges());
30+
//$this->assertEquals(array(), $alg->getEdgesTo($v1));
31+
$this->assertEquals(array(), $alg->getVertices());
32+
$this->assertEquals(array(), $alg->getVerticesId());
33+
34+
$clone = $alg->createGraph();
35+
$this->assertGraphEquals($graph,$clone);
36+
}
37+
38+
public function testGraphSingleLoop()
39+
{
40+
// 1 -[4]> 1
41+
$graph = new Graph();
42+
$v1 = $graph->createVertex(1);
43+
$e1 = $v1->createEdgeTo($v1)->setWeight(4);
44+
45+
$alg = $this->createAlg($v1);
46+
47+
$this->assertEquals(array($e1), $alg->getEdges());
48+
49+
$expectedWeight = $this->getExpectedWeight(array($e1));
50+
$this->assertTrue($alg->hasVertex($v1));
51+
$this->assertEquals($expectedWeight, $alg->getDistance($v1));
52+
$this->assertEquals(array(1 => $expectedWeight), $alg->getDistanceMap());
53+
$this->assertEquals(array($e1), $alg->getEdgesTo($v1));
54+
$this->assertEquals(array(1 => $v1), $alg->getVertices());
55+
$this->assertEquals(array(1), $alg->getVerticesId());
56+
}
57+
58+
public function testGraphCycle()
59+
{
60+
// 1 -[4]-> 2 -[2]-> 1
61+
$graph = new Graph();
62+
$v1 = $graph->createVertex(1);
63+
$v2 = $graph->createVertex(2);
64+
$e1 = $v1->createEdgeTo($v2)->setWeight(4);
65+
$e2 = $v2->createEdgeTo($v1)->setWeight(2);
66+
67+
$alg = $this->createAlg($v1);
68+
69+
//$this->assertEquals(array($e2, $e1), $alg->getEdges());
70+
71+
$expectedWeight = $this->getExpectedWeight(array($e1));
72+
$this->assertTrue($alg->hasVertex($v2));
73+
$this->assertEquals(array($e1), $alg->getEdgesTo($v2));
74+
$this->assertEquals($expectedWeight, $alg->getDistance($v2));
75+
76+
$expectedWeight = $this->getExpectedWeight(array($e1, $e2));
77+
$this->assertTrue($alg->hasVertex($v1));
78+
$this->assertEquals(array($e1, $e2), $alg->getEdgesTo($v1));
79+
$this->assertEquals($expectedWeight, $alg->getDistance($v1));
80+
81+
$walk = $alg->getWalkTo($v1);
82+
$this->assertEquals(2, $walk->getNumberOfEdges());
83+
}
84+
85+
/**
86+
* @expectedException OutOfBoundsException
87+
*/
88+
public function testIsolatedVertexIsNotReachable()
89+
{
90+
// 1, 2
91+
$graph = new Graph();
92+
$v1 = $graph->createVertex(1);
93+
$v2 = $graph->createVertex(2);
94+
95+
$alg = $this->createAlg($v1);
96+
97+
$this->assertFalse($alg->hasVertex($v2));
98+
99+
$alg->getEdgesTo($v2);
100+
}
101+
102+
/**
103+
* @expectedException OutOfBoundsException
104+
*/
105+
public function testSeparateGraphsAreNotReachable()
106+
{
107+
// 1
108+
$graph1 = new Graph();
109+
$vg1 = $graph1->createVertex(1);
110+
111+
$graph2 = new Graph();
112+
$vg2 = $graph2->createVertex(1);
113+
114+
$alg = $this->createAlg($vg1);
115+
116+
$alg->getEdgesTo($vg2);
117+
}
118+
119+
public function testGraphTwoComponents()
120+
{
121+
// 1 -[10]-> 2
122+
// 3 -[20]-> 4
123+
$graph = new Graph();
124+
$v1 = $graph->createVertex(1);
125+
$v2 = $graph->createVertex(2);
126+
$v3 = $graph->createVertex(3);
127+
$v4 = $graph->createVertex(4);
128+
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
129+
$e2 = $v3->createEdgeTo($v4)->setWeight(20);
130+
131+
$alg = $this->createAlg($v1);
132+
133+
$expectedWeight = $this->getExpectedWeight(array($e1));
134+
$this->assertEquals($expectedWeight, $alg->getDistance($v2));
135+
$this->assertEquals(array(2 => $expectedWeight), $alg->getDistanceMap());
136+
$this->assertEquals(array($e1), $alg->getEdges());
137+
// $this->assertEquals(array(), $alg->getEdgesTo($v1));
138+
$this->assertEquals(array($e1), $alg->getEdgesTo($v2));
139+
$this->assertEquals(array(2 => $v2), $alg->getVertices());
140+
$this->assertEquals(array(2), $alg->getVerticesId());
141+
}
142+
143+
protected function getExpectedWeight($edges)
144+
{
145+
$sum = 0;
146+
foreach ($edges as $edge) {
147+
$sum += $edge->getWeight();
148+
}
149+
return $sum;
150+
}
151+
}
Lines changed: 27 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,38 @@
11
<?php
22

3+
use Fhaculty\Graph\Graph;
34
use Fhaculty\Graph\Vertex;
4-
5-
use Fhaculty\Graph\GraphViz;
6-
use Fhaculty\Graph\Edge\Base as Edge;
75
use Fhaculty\Graph\Algorithm\ShortestPath\BreadthFirst;
8-
use Fhaculty\Graph\Loader\CompleteGraph;
96

10-
class BreadthFirstTest extends PHPUnit_Framework_TestCase
7+
class BreadthFirstTest extends BaseShortestPathTest
118
{
12-
public function testOne()
9+
protected function createAlg(Vertex $vertex)
1310
{
14-
// TODO: this should NOT be part of the unit test
15-
// TODO: remove randomness
16-
$debug = false;
17-
18-
$loader = new CompleteGraph(10);
19-
$loader->setEnableDirectedEdges(true);
20-
$graph = $loader->createGraph();
21-
22-
// randomly remove 70% of the edges
23-
foreach (array_slice(Edge::getAll($graph->getEdges(), Edge::ORDER_RANDOM), 0, $graph->getNumberOfEdges()*0.8) as $edge) {
24-
$edge->destroy();
25-
}
26-
27-
$start = Vertex::getFirst($graph, Vertex::ORDER_RANDOM);
28-
$start->setLayoutAttribute('shape', 'doublecircle');
29-
30-
// actually start breadth search
31-
$alg = new BreadthFirst($start);
32-
33-
// visualize all resulting edges in blue
34-
foreach ($alg->getEdges() as $edge) {
35-
$edge->setLayoutAttribute('color', 'blue');
36-
}
37-
38-
// visualize all reachable vertices in blue
39-
foreach ($alg->getVertices() as $vertex) {
40-
$vertex->setLayoutAttribute('color', 'blue');
41-
}
42-
43-
if ($debug) {
44-
// visualize resulting graph
45-
$vis = new GraphViz($graph);
46-
$vis->display();
47-
}
48-
49-
$this->assertTrue(count($alg->getVertices()) >= count($start->getVerticesEdgeTo()));
50-
51-
// test all reachable vertices
52-
foreach ($alg->getDistanceMap() as $vid => $distance) {
53-
if($debug) echo 'vertex ' . $vid . ' in distance ' . $distance;
54-
$walk = $alg->getWalkTo($graph->getVertex($vid));
55-
56-
$this->assertEquals($distance, $walk->getNumberOfEdges());
57-
58-
if ($debug) {
59-
echo ' (vertex walk: ' . implode(', ', $walk->getVerticesSequenceId()) . ')';
60-
echo PHP_EOL;
11+
return new BreadthFirst($vertex);
12+
}
6113

62-
$vis = new GraphViz($walk->createGraph());
63-
$vis->display();
64-
}
65-
}
14+
public function testGraphParallelNegative()
15+
{
16+
// 1 -[10]-> 2
17+
// 1 -[-1]-> 2
18+
$graph = new Graph();
19+
$v1 = $graph->createVertex(1);
20+
$v2 = $graph->createVertex(2);
21+
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
22+
$e2 = $v1->createEdgeTo($v2)->setWeight(-1);
23+
24+
$alg = $this->createAlg($v1);
25+
26+
$this->assertEquals(1, $alg->getDistance($v2));
27+
$this->assertEquals(array(2 => 1), $alg->getDistanceMap());
28+
$this->assertEquals(array($e1), $alg->getEdges());
29+
$this->assertEquals(array($e1), $alg->getEdgesTo($v2));
30+
$this->assertEquals(array(2 => $v2), $alg->getVertices());
31+
$this->assertEquals(array(2), $alg->getVerticesId());
32+
}
6633

67-
// $alg = new BreadthFirst($startVertex);
34+
protected function getExpectedWeight($edges)
35+
{
36+
return count($edges);
6837
}
6938
}

tests/ShortestPath/DijkstraTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Fhaculty\Graph\Graph;
4+
use Fhaculty\Graph\Vertex;
5+
use Fhaculty\Graph\Algorithm\ShortestPath\Dijkstra;
6+
7+
class DijkstraTest extends BaseShortestPathTest
8+
{
9+
protected function createAlg(Vertex $vertex)
10+
{
11+
return new Dijkstra($vertex);
12+
}
13+
14+
/**
15+
* @expectedException UnexpectedValueException
16+
*/
17+
public function testGraphParallelNegative()
18+
{
19+
// 1 -[10]-> 2
20+
// 1 -[-1]-> 2
21+
$graph = new Graph();
22+
$v1 = $graph->createVertex(1);
23+
$v2 = $graph->createVertex(2);
24+
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
25+
$e2 = $v1->createEdgeTo($v2)->setWeight(-1);
26+
27+
$alg = $this->createAlg($v1);
28+
29+
$alg->getEdges();
30+
}
31+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
use Fhaculty\Graph\Graph;
4+
use Fhaculty\Graph\Vertex;
5+
use Fhaculty\Graph\Algorithm\ShortestPath\MooreBellmanFord;
6+
7+
class MooreBellmanFordTest extends BaseShortestPathTest
8+
{
9+
protected function createAlg(Vertex $vertex)
10+
{
11+
return new MooreBellmanFord($vertex);
12+
}
13+
14+
public function testGraphParallelNegative()
15+
{
16+
// 1 -[10]-> 2
17+
// 1 -[-1]-> 2
18+
$graph = new Graph();
19+
$v1 = $graph->createVertex(1);
20+
$v2 = $graph->createVertex(2);
21+
$e1 = $v1->createEdgeTo($v2)->setWeight(10);
22+
$e2 = $v1->createEdgeTo($v2)->setWeight(-1);
23+
24+
$alg = $this->createAlg($v1);
25+
26+
// $this->assertEquals(0, $alg->getDistance($v1));
27+
$this->assertEquals(-1, $alg->getDistance($v2));
28+
$this->assertEquals(array(2 => -1), $alg->getDistanceMap());
29+
$this->assertEquals(array($e2), $alg->getEdges());
30+
//$this->assertEquals(array(), $alg->getEdgesTo($v1));
31+
$this->assertEquals(array($e2), $alg->getEdgesTo($v2));
32+
$this->assertEquals(array(2 => $v2), $alg->getVertices());
33+
$this->assertEquals(array(2), $alg->getVerticesId());
34+
35+
return $alg;
36+
}
37+
38+
/**
39+
* @param MooreBellmanFord $alg
40+
* @depends testGraphParallelNegative
41+
* @expectedException UnderflowException
42+
*/
43+
public function testNoNegativeCycle(MooreBellmanFord $alg)
44+
{
45+
$alg->getCycleNegative();
46+
}
47+
48+
public function testUndirectedNegativeWeightIsCycle()
49+
{
50+
// 1 -[-10]- 2
51+
$graph = new Graph();
52+
$v1 = $graph->createVertex(1);
53+
$v2 = $graph->createVertex(2);
54+
$e1 = $v1->createEdge($v2)->setWeight(-10);
55+
56+
$alg = $this->createAlg($v1);
57+
58+
$cycle = $alg->getCycleNegative();
59+
}
60+
61+
public function testLoopNegativeWeightIsCycle()
62+
{
63+
// 1 -[-10]-> 1
64+
$graph = new Graph();
65+
$v1 = $graph->createVertex(1);
66+
$e1 = $v1->createEdge($v1)->setWeight(-10);
67+
68+
$alg = $this->createAlg($v1);
69+
70+
$cycle = $alg->getCycleNegative();
71+
}
72+
}

0 commit comments

Comments
 (0)