Completed
Pull Request — master (#34)
by Pol
08:23
created

GraphTest::testToString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * phpDocumentor.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * @see      http://phpdoc.org
12
 */
13
14
namespace phpDocumentor\GraphViz\Test;
15
16
use InvalidArgumentException;
17
use Mockery as m;
18
use const PHP_EOL;
19
use phpDocumentor\GraphViz\AttributeNotFound;
20
use phpDocumentor\GraphViz\Edge;
21
use phpDocumentor\GraphViz\Exception;
22
use phpDocumentor\GraphViz\Graph;
23
use phpDocumentor\GraphViz\Node;
24
use PHPUnit\Framework\TestCase;
25
use RuntimeException;
26
27
/**
28
 * Test for the the class representing a GraphViz graph.
29
 *
30
 * @internal
31
 * @coversNothing
32
 */
33
final class GraphTest extends TestCase
34
{
35
    /** @var Graph */
36
    protected $fixture;
37
38
    /**
39
     * Sets up the fixture, for example, opens a network connection.
40
     * This method is called before a test is executed.
41
     */
42
    protected function setUp(): void
43
    {
44
        $this->fixture = new Graph();
45
    }
46
47
    /**
48
     * Tears down the fixture, for example, closes a network connection.
49
     * This method is called after a test is executed.
50
     */
51
    protected function tearDown(): void
52
    {
53
        m::close();
54
    }
55
56
    /**
57
     * @covers \phpDocumentor\GraphViz\Graph::addGraph
58
     */
59
    public function testAddGraph(): void
60
    {
61
        $mock = m::mock(Graph::class);
62
        $mock->expects('setType');
63
        $mock->expects('getName');
64
65
        self::assertSame(
66
            $this->fixture,
67
            $this->fixture->addGraph($mock)
68
        );
69
    }
70
71
    /**
72
     * @covers \phpDocumentor\GraphViz\Graph::__call
73
     * @covers \phpDocumentor\GraphViz\Graph::getAttribute
74
     * @covers \phpDocumentor\GraphViz\Graph::setAttribute
75
     */
76
    public function testCall(): void
77
    {
78
        self::assertNull($this->fixture->MyMethod());
0 ignored issues
show
Documentation Bug introduced by
The method MyMethod does not exist on object<phpDocumentor\GraphViz\Graph>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
79
        self::assertSame($this->fixture, $this->fixture->setBgColor('black'));
0 ignored issues
show
Documentation Bug introduced by
The method setBgColor does not exist on object<phpDocumentor\GraphViz\Graph>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
80
        self::assertSame('black', $this->fixture->getBgColor()->getValue());
0 ignored issues
show
Documentation Bug introduced by
The method getBgColor does not exist on object<phpDocumentor\GraphViz\Graph>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
81
    }
82
83
    /**
84
     * @covers \phpDocumentor\GraphViz\Graph::create
85
     */
86
    public function testCreate(): void
87
    {
88
        $fixture = Graph::create();
89
        self::assertInstanceOf(
90
            Graph::class,
91
            $fixture
92
        );
93
        self::assertSame(
94
            'G',
95
            $fixture->getName()
96
        );
97
        self::assertSame(
98
            'digraph',
99
            $fixture->getType()
100
        );
101
102
        $fixture = Graph::create('MyName', false);
103
        self::assertSame(
104
            'MyName',
105
            $fixture->getName()
106
        );
107
        self::assertSame(
108
            'graph',
109
            $fixture->getType()
110
        );
111
    }
112
113
    /**
114
     * @covers \phpDocumentor\GraphViz\Graph::export
115
     */
116
    public function testExport(): void
117
    {
118
        $graph = Graph::create('My First Graph');
119
        $filename = \tempnam(\sys_get_temp_dir(), 'tst');
120
121
        if (false === $filename) {
122
            self::assertFalse('Failed to create destination file');
123
124
            return;
125
        }
126
127
        self::assertSame(
128
            $graph,
129
            $graph->export('pdf', $filename)
130
        );
131
        self::assertTrue(\is_readable($filename));
132
    }
133
134
    /**
135
     * @covers \phpDocumentor\GraphViz\Graph::export
136
     */
137
    public function testExportException(): void
138
    {
139
        $graph = Graph::create('My First Graph');
140
        $filename = \tempnam(\sys_get_temp_dir(), 'tst');
141
142
        if (false === $filename) {
143
            self::assertFalse('Failed to create destination file');
144
145
            return;
146
        }
147
148
        $this->expectException(Exception::class);
149
        $graph->export('fpd', $filename);
150
    }
151
152
    /**
153
     * @covers \phpDocumentor\GraphViz\Graph::findNode
154
     */
155
    public function testFindNode(): void
156
    {
157
        self::assertNull($this->fixture->findNode('MyNode'));
158
159
        $mock = m::mock(Node::class);
160
        $mock->expects('setGraphRoot');
161
        $mock->expects('getName')->andReturn('MyName');
162
163
        $this->fixture->setNode($mock);
164
        self::assertSame(
165
            $mock,
166
            $this->fixture->findNode('MyName')
167
        );
168
169
        $subGraph = Graph::create();
170
        $mock2 = m::mock(Node::class);
171
        $mock2->expects('setGraphRoot');
172
        $mock2->expects('getName')->andReturn('MyName2');
173
174
        $subGraph->setNode($mock2);
175
176
        $this->fixture->addGraph($subGraph);
177
        self::assertSame(
178
            $mock2,
179
            $this->fixture->findNode('MyName2')
180
        );
181
    }
182
183
    /**
184
     * @covers \phpDocumentor\GraphViz\Graph::__get
185
     */
186
    public function testGet(): void
187
    {
188
        $mock = m::mock(Node::class);
189
190
        $this->fixture->myNode = $mock;
0 ignored issues
show
Documentation introduced by
The property myNode does not exist on object<phpDocumentor\GraphViz\Graph>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
191
        self::assertSame(
192
            $mock,
193
            $this->fixture->myNode
0 ignored issues
show
Documentation introduced by
The property myNode does not exist on object<phpDocumentor\GraphViz\Graph>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
194
        );
195
    }
196
197
    /**
198
     * @covers \phpDocumentor\GraphViz\Graph::getGraph
199
     */
200
    public function testGetGraph(): void
201
    {
202
        $mock = m::mock(Graph::class);
203
        $mock->expects('setType');
204
        $mock->expects('getName')->andReturn('MyName');
205
206
        $this->fixture->addGraph($mock);
207
        self::assertSame(
208
            $mock,
209
            $this->fixture->getGraph('MyName')
210
        );
211
    }
212
213
    /**
214
     * @covers \phpDocumentor\GraphViz\Graph::getName
215
     */
216
    public function testGetName(): void
217
    {
218
        self::assertSame(
219
            $this->fixture->getName(),
220
            'G',
221
            'Expecting the name to match the initial state'
222
        );
223
        $this->fixture->setName('otherName');
224
        self::assertSame(
225
            $this->fixture->getName(),
226
            'otherName',
227
            'Expecting the name to contain the new value'
228
        );
229
    }
230
231
    /**
232
     * @covers \phpDocumentor\GraphViz\AttributeNotFound::__construct
233
     * @covers \phpDocumentor\GraphViz\Graph::getAttribute
234
     */
235
    public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
236
    {
237
        $this->expectException(AttributeNotFound::class);
238
        $this->expectExceptionMessage('Attribute with name "notexisting" was not found');
239
240
        $this->fixture->getNotExisting();
0 ignored issues
show
Documentation Bug introduced by
The method getNotExisting does not exist on object<phpDocumentor\GraphViz\Graph>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
241
    }
242
243
    /**
244
     * @covers \phpDocumentor\GraphViz\Graph::getType
245
     */
246
    public function testGetType(): void
247
    {
248
        self::assertSame(
249
            $this->fixture->getType(),
250
            'digraph'
251
        );
252
        $this->fixture->setType('graph');
253
        self::assertSame(
254
            $this->fixture->getType(),
255
            'graph'
256
        );
257
    }
258
259
    /**
260
     * @covers \phpDocumentor\GraphViz\Graph::hasGraph
261
     */
262
    public function testHasGraph(): void
263
    {
264
        $mock = m::mock(Graph::class);
265
        $mock->expects('getName')->andReturn('MyName');
266
        $mock->expects('setType');
267
268
        self::assertFalse($this->fixture->hasGraph('MyName'));
269
        $this->fixture->addGraph($mock);
270
        self::assertTrue($this->fixture->hasGraph('MyName'));
271
    }
272
273
    public function testIsStrict(): void
274
    {
275
        self::assertSame(
276
            $this->fixture->isStrict(),
277
            false
278
        );
279
        $this->fixture->setStrict(true);
280
        self::assertSame(
281
            $this->fixture->isStrict(),
282
            true
283
        );
284
    }
285
286
    /**
287
     * @covers \phpDocumentor\GraphViz\Graph::link
288
     */
289
    public function testLink(): void
290
    {
291
        $mock = m::mock(Edge::class);
292
        $mock->expects('setGraphRoot');
293
294
        self::assertSame(
295
            $this->fixture,
296
            $this->fixture->link($mock)
297
        );
298
    }
299
300
    /**
301
     * @covers \phpDocumentor\GraphViz\Graph::__set
302
     */
303
    public function testSet(): void
304
    {
305
        $mock = m::mock(Node::class);
306
307
        self::assertSame(
308
            $this->fixture,
309
            $this->fixture->__set('myNode', $mock)
310
        );
311
    }
312
313
    /**
314
     * @covers \phpDocumentor\GraphViz\Graph::setName
315
     */
316
    public function testSetName(): void
317
    {
318
        self::assertSame(
319
            $this->fixture,
320
            $this->fixture->setName('otherName'),
321
            'Expecting a fluent interface'
322
        );
323
    }
324
325
    /**
326
     * @covers \phpDocumentor\GraphViz\Graph::setNode
327
     */
328
    public function testSetNode(): void
329
    {
330
        $mock = m::mock(Node::class);
331
        $mock->expects('setGraphRoot');
332
        $mock->expects('getName')->andReturn('MyName');
333
334
        self::assertSame(
335
            $this->fixture,
336
            $this->fixture->setNode($mock)
337
        );
338
    }
339
340
    public function testSetPath(): void
341
    {
342
        self::assertSame(
343
            $this->fixture,
344
            $this->fixture->setPath(__DIR__),
345
            'Expecting a fluent interface'
346
        );
347
    }
348
349
    public function testSetStrict(): void
350
    {
351
        self::assertSame(
352
            $this->fixture,
353
            $this->fixture->setStrict(true),
354
            'Expecting a fluent interface'
355
        );
356
        self::assertSame(
357
            $this->fixture,
358
            $this->fixture->setStrict(false),
359
            'Expecting a fluent interface'
360
        );
361
    }
362
363
    /**
364
     * @covers \phpDocumentor\GraphViz\Graph::setType
365
     */
366
    public function testSetType(): void
367
    {
368
        self::assertSame(
369
            $this->fixture,
370
            $this->fixture->setType('digraph'),
371
            'Expecting a fluent interface'
372
        );
373
        self::assertSame(
374
            $this->fixture,
375
            $this->fixture->setType('graph'),
376
            'Expecting a fluent interface'
377
        );
378
        self::assertSame(
379
            $this->fixture,
380
            $this->fixture->setType('subgraph'),
381
            'Expecting a fluent interface'
382
        );
383
    }
384
385
    /**
386
     * @covers \phpDocumentor\GraphViz\Graph::setType
387
     */
388
    public function testSetTypeException(): void
389
    {
390
        $this->expectException(InvalidArgumentException::class);
391
        $this->fixture->setType('fakegraphg');
392
    }
393
394
    /**
395
     * @covers \phpDocumentor\GraphViz\Graph::__toString
396
     */
397
    public function testToString(): void
398
    {
399
        $graph = Graph::create('My First Graph');
400
        self::assertSame(
401
            $this->normalizeLineEndings((string) $graph),
402
            $this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . PHP_EOL . '}'))
403
        );
404
405
        $graph->setLabel('PigeonPost');
406
        self::assertSame(
407
            $this->normalizeLineEndings((string) $graph),
408
            $this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . 'label="PigeonPost"' . PHP_EOL . '}'))
409
        );
410
411
        $graph->setStrict(true);
412
        self::assertSame(
413
            $this->normalizeLineEndings((string) $graph),
414
            $this->normalizeLineEndings(
415
                ('strict digraph "My First Graph" {' . PHP_EOL . 'label="PigeonPost"' . PHP_EOL . '}')
416
            )
417
        );
418
    }
419
420
    /**
421
     * Help avoid issue of "#Warning: Strings contain different line endings!" on Windows.
422
     *
423
     * @param string $string
424
     */
425
    private function normalizeLineEndings(string $string): string
426
    {
427
        $result = \preg_replace('~\R~u', "\r\n", $string);
428
429
        if (null === $result) {
430
            throw new RuntimeException('Normalize line endings failed');
431
        }
432
433
        return $result;
434
    }
435
}
436