Completed
Pull Request — master (#166)
by
unknown
112:06 queued 110:39
created

RepositoryTest::testGetLogForBranch()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * This file is part of the GitElephant package.
5
 *
6
 * (c) Matteo Giachino <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * Just for fun...
12
 */
13
14
namespace GitElephant;
15
16
use GitElephant\Command\ResetCommand;
17
use GitElephant\Objects\Branch;
18
use GitElephant\Objects\Log;
19
use GitElephant\Objects\NodeObject;
20
use GitElephant\Objects\Tag;
21
22
/**
23
 * RepositoryTest
24
 *
25
 * Repository Test Class
26
 *
27
 * @author Matteo Giachino <[email protected]>
28
 */
29
class RepositoryTest extends TestCase
30
{
31
    /**
32
     * setUp
33
     */
34
    public function setUp(): void
35
    {
36
        $this->initRepository();
37
    }
38
39
    /**
40
     * @covers \GitElephant\Repository::__construct
41
     * @covers \GitElephant\Repository::getPath
42
     */
43
    public function testConstruct(): void
44
    {
45
        $this->assertEquals($this->getRepository()->getPath(), $this->path);
46
47
        $this->expectException('GitElephant\Exception\InvalidRepositoryPathException');
48
        $repo = new Repository('non-existent-path');
0 ignored issues
show
Unused Code introduced by
$repo is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
49
50
        $repo = Repository::open($this->path);
51
        $this->assertInstanceOf('GitElephant\Repository', $repo);
52
    }
53
54
    /**
55
     * @covers \GitElephant\Repository::init
56
     */
57
    public function testInit(): void
58
    {
59
        $this->getRepository()->init();
60
        $match = false;
61
62
        // Force US/EN locale
63
        putenv('LANG=en_US.UTF-8');
64
65
        foreach ($this->getRepository()->getStatusOutput() as $line) {
66
            if (preg_match('/nothing to commit?(.*)/', $line)) {
67
                $match = true;
68
            }
69
        }
70
        $this->assertTrue($match, 'init problem, git status on an empty repo should give nothing to commit');
71
    }
72
73
    /**
74
     * testName
75
     */
76
    public function testName(): void
77
    {
78
        $this->getRepository()->setName('test-repo');
79
        $this->assertEquals('test-repo', $this->getRepository()->getName());
80
    }
81
82
    /**
83
     * @covers \GitElephant\Repository::stage
84
     */
85
    public function testStage(): void
86
    {
87
        $this->getRepository()->init();
88
        $this->addFile('test');
89
        $this->getRepository()->stage();
90
        $match = false;
91
        foreach ($this->getRepository()->getStatusOutput() as $line) {
92
            if (preg_match('/(.*)Changes to be committed(.*)/', $line)) {
93
                $match = true;
94
            }
95
        }
96
        $this->assertTrue($match, 'stageAll error, git status should give Changes to be committed');
97
    }
98
99
    /**
100
     * @covers \GitElephant\Repository::unstage
101
     */
102
    public function testUnstage(): void
103
    {
104
        $this->getRepository()->init();
105
        $this->addFile('test');
106
        $this->getRepository()->commit('first commit', true);
107
        $this->addFile('test2');
108
        $this->assertCount(1, $this->getRepository()->getStatus()->untracked());
109
        $this->assertCount(0, $this->getRepository()->getStatus()->added());
110
        $this->getRepository()->stage('test2');
111
        $this->assertCount(0, $this->getRepository()->getStatus()->untracked());
112
        $this->assertCount(1, $this->getRepository()->getStatus()->added());
113
        $this->getRepository()->unstage('test2');
114
        $this->assertCount(1, $this->getRepository()->getStatus()->untracked());
115
        $this->assertCount(0, $this->getRepository()->getStatus()->added());
116
    }
117
118
    /**
119
     * @covers \GitElephant\Repository::commit
120
     * @covers \GitElephant\Repository::getStatusOutput
121
     */
122
    public function testCommit(): void
123
    {
124
        $this->getRepository()->init();
125
        $this->addFile('test');
126
        $this->getRepository()->stage();
127
        $this->getRepository()->commit('initial import');
128
        $match = false;
129
        foreach ($this->getRepository()->getStatusOutput() as $line) {
130
            if (preg_match('/nothing to commit?(.*)/', $line)) {
131
                $match = true;
132
            }
133
        }
134
        $this->assertTrue($match, 'commit error, git status should give nothing to commit');
135
136
        $this->getRepository()->createBranch('develop', $this->getRepository()->getCommit());
137
        $this->addFile('test2');
138
        $this->getRepository()->commit('commit 2', true, 'develop');
139
        $match = false;
140
        foreach ($this->getRepository()->getStatusOutput() as $line) {
141
            if (preg_match('/nothing to commit?(.*)/', $line)) {
142
                $match = true;
143
            }
144
        }
145
        $this->assertTrue($match, 'commit error, git status should give nothing to commit');
146
    }
147
148
    /**
149
     * @covers \GitElephant\Repository::getStatusOutput
150
     */
151
    public function testGetStatus(): void
152
    {
153
        $this->getRepository()->init();
154
        $this->addFile('test');
155
        $this->getRepository()->commit('test commit', true);
156
        $output = $this->getRepository()->getStatusOutput();
157
        $this->assertStringEndsWith('master', $output[0]);
158
        $this->addFile('file2');
159
        $output = $this->getRepository()->getStatusOutput();
160
        $this->assertContains('file2', $output);
161
    }
162
163
    /**
164
     * @covers \GitElephant\Repository::createBranch
165
     */
166
    public function testCreateBranch(): void
167
    {
168
        $this->getRepository()->init();
169
        $this->addFile('test');
170
        $this->getRepository()->commit('foo', true);
171
        $this->getRepository()->createBranch('test-branch');
172
        $this->assertEquals(2, count($this->getRepository()->getBranches()));
173
    }
174
175
    /**
176
     * @covers \GitElephant\Repository::deleteBranch
177
     */
178
    public function testDeleteBranch(): void
179
    {
180
        $this->getRepository()->init();
181
        $this->addFile('test-file');
182
        $this->getRepository()->commit('test', true);
183
        $this->getRepository()->createBranch('branch2');
184
        $this->assertEquals(2, count($this->getRepository()->getBranches(true)));
185
        $this->getRepository()->deleteBranch('branch2');
186
        $this->assertEquals(1, count($this->getRepository()->getBranches(true)));
187
        $this->addFile('test-file2');
188
        $this->getRepository()->commit('test2', true);
189
        $this->getRepository()->createBranch('branch3');
190
        $this->assertEquals(2, count($this->getRepository()->getBranches(true)));
191
        $this->getRepository()->deleteBranch('branch3', true);
192
        $this->assertEquals(1, count($this->getRepository()->getBranches(true)));
193
    }
194
195
    /**
196
     * @covers \GitElephant\Repository::getBranches
197
     */
198
    public function testGetBranches(): void
199
    {
200
        $this->getRepository()->init();
201
        $this->addFile('test');
202
        $this->getRepository()->stage();
203
        $this->getRepository()->commit('initial import', true);
204
        $this->assertCount(
205
            1,
206
            $this->getRepository()->getBranches(),
207
            'an initialized repository should have only one branch'
208
        );
209
        $this->getRepository()->createBranch('test-branch');
210
        $this->assertCount(2, $this->getRepository()->getBranches(), 'two branches expected');
211
        $branches = $this->getRepository()->getBranches();
212
        /** @var Branch $branch */
213
        $branch = $branches[0];
214
        $this->assertEquals('master', $branch->getName());
215
        $this->getRepository()->deleteBranch('test-branch');
216
        $this->assertCount(1, $this->getRepository()->getBranches(), 'one branch expected');
217
        $this->assertInstanceOf(
218
            'GitElephant\Objects\Branch',
219
            $this->getRepository()->getMainBranch(),
220
            'main branch should be an instance of Branch'
221
        );
222
        $this->assertTrue(
223
            $this->getRepository()->getMainBranch()->getCurrent(),
224
            'getCurrent on main branch should be true'
225
        );
226
        $this->assertEquals(
227
            'master',
228
            $this->getRepository()->getMainBranch()->getName(),
229
            'main branch should be named "master"'
230
        );
231
        $this->assertEquals(['master'], $this->getRepository()->getBranches(true));
232
        $this->getRepository()->createBranch('develop');
233
        $this->assertContains('master', $this->getRepository()->getBranches(true));
234
        $this->assertContains('develop', $this->getRepository()->getBranches(true));
235
    }
236
237
    /**
238
     * @covers \GitElephant\Repository::getMainBranch
239
     */
240
    public function testGetMainBranch(): void
241
    {
242
        $this->getRepository()->init();
243
        $this->addFile('test-file');
244
        $this->getRepository()->commit('test', true);
245
        $this->assertEquals('master', $this->getRepository()->getMainBranch()->getName());
246
    }
247
248
    /**
249
     * @covers \GitElephant\Repository::getBranch
250
     */
251
    public function testGetBranch(): void
252
    {
253
        $this->getRepository()->init();
254
        $this->addFile('test-file');
255
        $this->getRepository()->commit('test', true);
256
        $this->assertInstanceOf('GitElephant\Objects\Branch', $this->getRepository()->getBranch('master'));
257
        $this->assertNull($this->getRepository()->getBranch('a-branch-that-do-not-exists'));
258
    }
259
260
    /**
261
     * @covers \GitElephant\Repository::merge
262
     */
263
    public function testMerge(): void
264
    {
265
        $this->getRepository()->init();
266
        $this->addFile('test-file');
267
        $this->getRepository()->commit('test', true);
268
        $this->assertEquals(1, count($this->getRepository()->getTree()));
269
        $this->getRepository()->createBranch('branch2');
270
        $this->getRepository()->checkout('branch2');
271
        $this->addFile('file2');
272
        $this->getRepository()->commit('test2', true);
273
        $this->assertEquals(2, count($this->getRepository()->getTree()));
274
        $this->getRepository()->checkout('master');
275
        $this->assertEquals(1, count($this->getRepository()->getTree()));
276
        $this->getRepository()->merge($this->getRepository()->getBranch('branch2'));
0 ignored issues
show
Bug introduced by
It seems like $this->getRepository()->getBranch('branch2') can be null; however, merge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
277
        $this->assertEquals(2, count($this->getRepository()->getTree()));
278
279
        // attempt to merge a different branch by forcing a 3-way merge and verify the merge commit message
280
        $this->getRepository()->createBranch('branch3');
281
        $this->getRepository()->checkout('branch3');
282
        $this->addFile('file3');
283
        $this->getRepository()->commit('test3', true);
284
        $this->assertEquals(3, count($this->getRepository()->getTree()));
285
        $this->getRepository()->checkout('master');
286
        $this->assertEquals(2, count($this->getRepository()->getTree()));
287
        $this->getRepository()->merge($this->getRepository()->getBranch('branch3'), 'test msg', 'no-ff');
0 ignored issues
show
Bug introduced by
It seems like $this->getRepository()->getBranch('branch3') can be null; however, merge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
288
        $this->assertEquals(3, count($this->getRepository()->getTree()));
289
        $this->assertEquals('test msg', $this->getRepository()->getCommit()->getMessage()->getFullMessage());
290
291
        // attempt a fast forward merge where a 3-way is necessary and trap the resulting exception
292
        $this->getRepository()->checkout('branch2');
293
        $this->addFile('file4');
294
        $this->getRepository()->commit('test4', true);
295
        $this->assertEquals(3, count($this->getRepository()->getTree()));
296
        $this->getRepository()->checkout('master');
297
        $this->assertEquals(3, count($this->getRepository()->getTree()));
298
        try {
299
            $this->getRepository()->merge($this->getRepository()->getBranch('branch2'), '', 'ff-only');
0 ignored issues
show
Bug introduced by
It seems like $this->getRepository()->getBranch('branch2') can be null; however, merge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
300
        } catch (\RuntimeException $e) {
301
            return;
302
        }
303
        $this->fail("Merge should have produced a runtime exception.");
304
    }
305
306
    /**
307
     * @covers \GitElephant\Repository::getTags
308
     * @covers \GitElephant\Repository::getTag
309
     * @covers \GitElephant\Repository::createTag
310
     * @covers \GitElephant\Repository::deleteTag
311
     */
312
    public function testTags(): void
313
    {
314
        $this->getRepository()->init();
315
        $this->addFile('test-file');
316
        $this->getRepository()->commit('test', true);
317
        $this->assertEquals(0, count($this->getRepository()->getTags()));
318
        $this->getRepository()->createTag('test-tag');
319
        $this->assertEquals(1, count($this->getRepository()->getTags()));
320
        $this->assertInstanceOf('GitElephant\Objects\Tag', $this->getRepository()->getTag('test-tag'));
321
        $this->getRepository()->deleteTag('test-tag');
322
        $this->assertEquals(0, count($this->getRepository()->getTags()));
323
        $this->assertNull($this->getRepository()->getTag('a-tag-that-do-not-exists'));
324
    }
325
326
    /**
327
     * test getLastTag
328
     */
329
    public function testGetLastTag(): void
330
    {
331
        $this->getRepository()->init();
332
        $this->addFile('test-file');
333
        $this->getRepository()->commit('test', true);
334
        $this->getRepository()->createTag('0.0.2');
335
        sleep(1);
336
        $this->getRepository()->createTag('0.0.4');
337
        sleep(1);
338
        $this->getRepository()->createTag('0.0.3');
339
        sleep(1);
340
        $this->getRepository()->createTag('0.0.1');
341
        sleep(1);
342
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.1'), $this->getRepository()->getLastTag());
343
344
        $this->getRepository()->createTag('0.0.05');
345
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.05'), $this->getRepository()->getLastTag());
346
347
        $this->getRepository()->deleteTag(Tag::pick($this->getRepository(), '0.0.05'));
348
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.1'), $this->getRepository()->getLastTag());
349
    }
350
351
    /**
352
     * @covers \GitElephant\Repository::getCommit
353
     */
354
    public function testGetCommit(): void
355
    {
356
        $this->getRepository()->init();
357
        $this->addFile('test-file');
358
        $this->getRepository()->commit('test', true);
359
        $this->assertInstanceOf('GitElephant\Objects\Commit', $this->getRepository()->getCommit());
360
    }
361
362
    public function testGetBranchOrTag(): void
363
    {
364
        $this->getRepository()->init();
365
        $this->addFile('test-file');
366
        $this->getRepository()->commit('test', true);
367
        $this->getRepository()->createBranch('branch2');
368
        $this->getRepository()->createTag('tag1');
369
        $this->assertInstanceOf('\GitElephant\Objects\Branch', $this->getRepository()->getBranchOrTag('branch2'));
370
        $this->assertInstanceOf('\GitElephant\Objects\Tag', $this->getRepository()->getBranchOrTag('tag1'));
371
        $this->assertNull($this->getRepository()->getBranchOrTag('not-exists'));
372
    }
373
374
    /**
375
     * @covers \GitElephant\Repository::getObjectLog
376
     */
377
    public function testGetObjectLog(): void
378
    {
379
        $repo = $this->getRepository();
380
        $repo->init();
381
382
        $this->addFolder('test');
383
384
        $this->addFile('A.txt', 'test');
385
        $repo->commit('added A.txt', true);
386
387
        $this->addFile('B.txt', 'test');
388
        $repo->commit('added B.txt', true);
389
390
        $this->addFile('C.txt', 'test');
391
        $repo->commit('added C.txt', true);
392
393
        $this->addFile('D.txt', 'test');
394
        $repo->commit('added D.txt', true);
395
396
        $this->addFile('E.txt', 'test');
397
        $repo->commit('added E.txt', true);
398
399
        $tree = $repo->getTree();
400
        $obj = $tree[0];
401
402
        $log = $this->getRepository()->getObjectLog($obj);
403
        $this->assertInstanceOf(Log::class, $log);
404
        $this->assertEquals(1, $log->count());
405
406
        $log = $this->getRepository()->getObjectLog($obj, null, 10);
407
        $this->assertEquals(5, $log->count());
408
409
        $this->assertEquals('added E.txt', $log->first()->getMessage()->toString());
410
        $this->assertEquals('added A.txt', $log->last()->getMessage()->toString());
411
    }
412
413
    /**
414
     * Test logs on different tree objects
415
     *
416
     * @covers \GitElephant\Repository::getObjectLog
417
     */
418
    public function testGetObjectLogFolders(): void
419
    {
420
        $repo = $this->getRepository();
421
        $repo->init();
422
423
        $this->addFolder('A');
424
        $this->addFile('A1.txt', 'A');
425
        $repo->commit('A/A1', true);
426
427
        $this->addFile('A2.txt', 'A');
428
        $repo->commit('A/A2', true);
429
430
        $this->addFolder('B');
431
        $this->addFile('B1.txt', 'B');
432
        $repo->commit('B/B1', true);
433
434
        $this->addFile('B2.txt', 'B');
435
        $repo->commit('B/B2', true);
436
437
        $tree = $repo->getTree();
438
439
        /** @var NodeObject $treeObj */
440
        foreach ($tree as $treeObj) {
441
            $name = $treeObj->getName();
442
            $log = $repo->getObjectLog($treeObj, null, 10);
443
444
            $this->assertEquals(2, $log->count());
445
446
            $i = 2;
447
            foreach ($log as $commit) {
448
                $this->assertEquals($name . '/' . $name . $i, $commit->getMessage()->toString());
449
                --$i;
450
            }
451
        }
452
    }
453
454
    /**
455
     * Test logs on different branches
456
     *
457
     * @covers \GitElephant\Repository::getObjectLog
458
     */
459
    public function testGetObjectLogBranches(): void
460
    {
461
        $repo = $this->getRepository();
462
        $repo->init();
463
464
        $this->addFolder('A');
465
        $this->addFile('A1.txt', 'A');
466
        $repo->commit('A/A1', true);
467
468
        $this->addFile('A2.txt', 'A');
469
        $repo->commit('A/A2', true);
470
471
        $repo->createBranch('test-branch');
472
        $repo->checkout('test-branch');
473
474
        $this->addFile('A3.txt', 'A');
475
        $repo->commit('A/A3', true);
476
477
        // master branch
478
        $repo->checkout('master');
479
        $tree = $repo->getTree();
480
        $dir = $tree[0];
481
        $log = $repo->getObjectLog($dir, null, 10);
482
483
        $this->assertEquals(2, $log->count());
484
        $this->assertEquals('A/A2', $log->first()->getMessage()->toString());
485
486
        // test branch
487
        $repo->checkout('test-branch');
488
        $tree = $repo->getTree();
489
        $dir = $tree[0];
490
        $log = $repo->getObjectLog($dir, null, 10);
491
492
        $this->assertEquals(3, $log->count());
493
        $this->assertEquals('A/A3', $log->first()->getMessage()->toString());
494
    }
495
496
    /**
497
     * @covers \GitElephant\Repository::getLog
498
     */
499
    public function testGetLog(): void
500
    {
501
        $this->getRepository()->init();
502
503
        for ($i = 0; $i < 50; $i++) {
504
            $this->addFile('test file ' . $i);
505
            $this->getRepository()->commit('test commit ' . $i, true);
506
        }
507
508
        $log = $this->getRepository()->getLog();
509
        $this->assertInstanceOf('GitElephant\Objects\Log', $this->getRepository()->getLog());
510
        $this->assertGreaterThan(0, $log->count());
511
    }
512
513
    /**
514
     * @covers \GitElephant\Repository::getLog
515
     */
516
    public function testGetLogForBranch(): void
517
    {
518
        $this->getRepository()->init();
519
        $this->addFile('test file 0');
520
        $this->getRepository()->commit('first commit', true);
521
        $this->getRepository()->checkout('test-branch', true);
522
523
        for ($i = 1; $i <= 2; $i++) {
524
            $this->addFile('test file ' . $i);
525
            $this->getRepository()->commit('test commit ' . $i, true);
526
        }
527
528
        $log = $this->getRepository()->getLog(['test-branch', '^master']);
529
        $this->assertInstanceOf('GitElephant\Objects\Log', $this->getRepository()->getLog());
530
        $this->assertEquals(2, $log->count());
531
    }
532
533
    /**
534
     * @covers \GitElephant\Repository::checkout
535
     */
536
    public function testCheckout(): void
537
    {
538
        $this->getRepository()->init();
539
        $this->addFile('test-file');
540
        $this->getRepository()->commit('test', true);
541
        $this->assertEquals('master', $this->getRepository()->getMainBranch()->getName());
542
        $this->getRepository()->createBranch('branch2');
543
        $this->getRepository()->checkout('branch2');
544
        $this->assertEquals('branch2', $this->getRepository()->getMainBranch()->getName());
545
    }
546
547
    /**
548
     * @covers \GitElephant\Repository::checkout
549
     */
550
    public function testCheckoutTag(): void
551
    {
552
        $this->getRepository()->init();
553
        $this->addFile('test-file');
554
        $this->getRepository()->commit('test', true);
555
        $this->getRepository()->createTag('v0.0.1');
556
        $this->addFile('test-file2');
557
        $this->getRepository()->commit('test2', true);
558
        $tag = $this->getRepository()->getTag('v0.0.1');
559
        $this->assertInstanceOf('GitElephant\Objects\Tag', $tag);
560
        $lastCommit = $this->getRepository()->getCommit();
561
        $this->assertStringNotContainsString('detached', implode(' ', $this->getRepository()->getStatusOutput()));
562
        $this->getRepository()->checkout($tag);
0 ignored issues
show
Bug introduced by
It seems like $tag defined by $this->getRepository()->getTag('v0.0.1') on line 558 can be null; however, GitElephant\Repository::checkout() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
563
        $newCommit = $this->getRepository()->getCommit();
564
        $this->assertNotEquals($newCommit->getSha(), $lastCommit->getSha());
565
        $this->assertStringContainsString('detached', implode(' ', $this->getRepository()->getStatusOutput()));
566
    }
567
568
    /**
569
     * @covers \GitElephant\Repository::getTree
570
     * @covers \GitElephant\Objects\Tree
571
     */
572
    public function testGetTree(): void
573
    {
574
        $this->getRepository()->init();
575
        $this->addFile('test');
576
        $this->addFolder('test-folder');
577
        $this->addFile('test2', 'test-folder');
578
579
        $this->getRepository()->stage();
580
        $this->getRepository()->commit('initial import');
581
582
        $tree = $this->getRepository()->getTree();
583
        $this->assertFalse($tree->isBlob());
584
        $this->assertTrue($this->getRepository()->getTree($this->getRepository()->getCommit(), 'test')->isBlob());
585
        $this->assertCount(2, $tree, 'One file in the repository');
586
        $firstNode = $tree[0];
587
        $this->assertInstanceOf(
588
            'GitElephant\Objects\NodeObject',
589
            $firstNode,
590
            'array access on tree should give always a node type'
591
        );
592
        $this->assertEquals(
593
            'test-folder',
594
            $firstNode->getName(),
595
            'First repository file should be named "test"'
596
        );
597
        $secondNode = $tree[1];
598
        $this->assertInstanceOf(
599
            'GitElephant\Objects\NodeObject',
600
            $secondNode,
601
            'array access on tree should give always a node type'
602
        );
603
        $this->assertEquals(
604
            NodeObject::TYPE_BLOB,
605
            $secondNode->getType(),
606
            'second node should be of type tree'
607
        );
608
        $subtree = $this->getRepository()->getTree('master', 'test-folder');
609
        $subnode = $subtree[0];
610
        $this->assertInstanceOf(
611
            'GitElephant\Objects\NodeObject',
612
            $subnode,
613
            'array access on tree should give always a node type'
614
        );
615
        $this->assertEquals(
616
            NodeObject::TYPE_BLOB,
617
            $subnode->getType(),
618
            'subnode should be of type blob'
619
        );
620
        $this->assertEquals(
621
            'test2',
622
            $subnode->getName(),
623
            'subnode should be named "test2"'
624
        );
625
    }
626
627
    /**
628
     * @covers \GitElephant\Repository::getDiff
629
     */
630
    public function testGetDiff(): void
631
    {
632
        $this->getRepository()->init();
633
        $this->addFile('test-file');
634
        $this->getRepository()->commit('commit 1', true);
635
        $commit1 = $this->getRepository()->getCommit();
636
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit1));
637
        $this->addFile('test-file2');
638
        $this->getRepository()->commit('commit 2', true);
639
        $commit2 = $this->getRepository()->getCommit();
640
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit2));
641
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit2, $commit1));
642
        $shaHead = $this->getRepository()->getCommit();
643
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $diff = $this->getRepository()->getDiff($shaHead));
644
    }
645
646
    /**
647
     * testCloneFrom
648
     */
649
    public function testCloneFrom(): void
650
    {
651
        $this->initRepository(null, 0);
652
        $this->initRepository(null, 1);
653
        $remote = $this->getRepository(0);
654
        $remote->init();
655
        $this->addFile('test', null, null, $remote);
656
        $remote->commit('test', true);
657
        $local = $this->getRepository(1);
658
        $local->cloneFrom($remote->getPath(), '.', 'master', 1, false);
659
        $commit = $local->getCommit();
660
        $this->assertEquals($remote->getCommit()->getSha(), $commit->getSha());
661
        $this->assertEquals($remote->getCommit()->getMessage(), $commit->getMessage());
662
    }
663
664
    /**
665
     * testOutputContent
666
     */
667
    public function testOutputContent(): void
668
    {
669
        $this->initRepository();
670
        $this->getRepository()->init();
671
        $this->addFile('file1', null, 'file content');
672
        $this->getRepository()->commit('first commit', true);
673
        $branch = $this->getRepository()->getBranch('master');
674
        $tree = $this->getRepository()->getTree($branch, 'file1');
0 ignored issues
show
Bug introduced by
It seems like $branch defined by $this->getRepository()->getBranch('master') on line 673 can be null; however, GitElephant\Repository::getTree() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
675
        $treeObject = $tree->getBlob();
676
        $this->assertEquals(['file content'], $this->getRepository()->outputContent($treeObject, $branch));
0 ignored issues
show
Bug introduced by
It seems like $branch defined by $this->getRepository()->getBranch('master') on line 673 can be null; however, GitElephant\Repository::outputContent() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
677
    }
678
679
    /**
680
     * testMove
681
     */
682
    public function testMove(): void
683
    {
684
        $this->getRepository()->init();
685
        $this->addFile('foo');
686
        $this->getRepository()->commit('commit 1', true);
687
        $this->getRepository()->move('foo', 'bar');
688
        $status = $this->getRepository()->getStatusOutput();
689
        $this->assertRegExp('/(.*):    foo -> bar/', implode("\n", $status));
690
    }
691
692
    /**
693
     * testRemove
694
     */
695
    public function testRemove(): void
696
    {
697
        $this->getRepository()->init();
698
        $this->addFile('foo');
699
        $this->getRepository()->commit('commit 1', true);
700
        $this->getRepository()->remove('foo');
701
        $status = $this->getRepository()->getStatusOutput();
702
703
        $this->assertRegExp('/(.*):    foo/', implode("\n", $status));
704
    }
705
706
    /**
707
     * testCountCommits
708
     */
709
    public function testCountCommits(): void
710
    {
711
        $this->getRepository()->init();
712
        $this->addFile('foo');
713
        $this->getRepository()->commit('commit 1', true);
714
        $this->assertEquals(1, $this->getRepository()->countCommits());
715
        $this->addFile('foo2');
716
        $this->getRepository()->commit('commit 2', true);
717
        $this->assertEquals(2, $this->getRepository()->countCommits());
718
        $this->getRepository()->createBranch('new-branch');
719
        $this->getRepository()->checkout('new-branch');
720
        $this->assertEquals(2, $this->getRepository()->countCommits());
721
        $this->addFile('bar');
722
        $this->getRepository()->commit('commit 3', true);
723
        $this->assertEquals(3, $this->getRepository()->countCommits());
724
        $this->getRepository()->checkout('master');
725
        $this->assertEquals(2, $this->getRepository()->countCommits());
726
    }
727
728
    /**
729
     * testHumanishName
730
     */
731
    public function testHumanishName(): void
732
    {
733
        $this->initRepository('test-dir');
734
        $this->assertEquals('test-dir', $this->getRepository()->getHumanishName());
735
    }
736
737
    /**
738
     * testCreateFromRemote
739
     */
740
    public function testCreateFromRemote(): void
741
    {
742
        $this->initRepository(null, 0);
743
        $remote = $this->getRepository(0);
744
        $remote->init();
745
        $this->addFile('test', null, null, $remote);
746
        $remote->commit('test', true);
747
        $remote->createBranch('develop');
748
749
        $repo = Repository::createFromRemote($remote->getPath());
750
        $this->assertInstanceOf('GitElephant\Repository', $repo);
751
        $this->assertGreaterThanOrEqual(2, $repo->getBranches());
752
        $branches = $repo->getBranches();
753
        $branchesName = array_map(
754
            function (Branch $b) {
755
                return $b->getName();
756
            },
757
            $branches
758
        );
759
        $this->assertContains('master', $branchesName);
760
        $this->assertContains('develop', $branchesName);
761
    }
762
763
    /**
764
     * testAddRemote
765
     */
766
    public function testRemote(): void
767
    {
768
        $this->initRepository(null, 0);
769
        $remote = $this->getRepository(0);
770
        $remote->init(true);
771
        $this->initRepository();
772
        $this->repository->init();
773
        $this->repository->addRemote('github', $remote->getPath());
774
        $this->assertInstanceOf('GitElephant\Objects\Remote', $this->repository->getRemote('github'));
775
        $this->repository->addRemote('github2', $remote->getPath());
776
        $this->assertCount(2, $this->repository->getRemotes());
777
    }
778
779
    /**
780
     * testFetch, git branch -a should find the branch
781
     */
782
    public function testFetch(): void
783
    {
784
        $this->initRepository(null, 0);
785
        $this->initRepository(null, 1);
786
        $r1 = $this->getRepository(0);
787
        $r1->init();
788
        $this->addFile('test1', null, null, $r1);
789
        $r1->commit('test commit', true);
790
        $r1->createBranch('tag-test');
791
        $this->addFile('test2', null, null, $r1);
792
        $r1->commit('another test commit', true);
793
        $r1->createTag('test-tag');
794
        $r2 = $this->getRepository(1);
795
        $r2->init();
796
        $r2->addRemote('origin', $r1->getPath());
797
        $this->assertEmpty($r2->getBranches(true, true));
798
        $r2->fetch();
799
        $this->assertNotEmpty($r2->getBranches(true, true));
800
        $r2->fetch(null, null, true);
801
        $this->assertNotNull($r2->getTag('test-tag'));
802
    }
803
804
    /**
805
     * test pull
806
     */
807
    public function testPull(): void
808
    {
809
        $this->initRepository(null, 0);
810
        $this->initRepository(null, 1);
811
        $r1 = $this->getRepository(0);
812
        $r1->init();
813
        $this->addFile('test1', null, null, $r1);
814
        $r1->commit('test commit', true);
815
        $r2 = $this->getRepository(1);
816
        $r2->init();
817
        $r2->addRemote('origin', $r1->getPath());
818
        $r2->pull('origin', 'master');
819
        $this->assertEquals('test commit', $r2->getLog()->last()->getMessage());
820
        $this->assertEquals($r1->getMainBranch()->getSha(), $r2->getLog()->last()->getSha());
821
    }
822
823
    /**
824
     * test pull
825
     */
826
    public function testPush(): void
827
    {
828
        $this->initRepository(null, 0);
829
        $this->initRepository(null, 1);
830
        $this->initRepository(null, 2);
831
        // commit on r1
832
        $r1 = $this->getRepository(0);
833
        $r1->init();
834
        $this->addFile('test1', null, null, $r1);
835
        $r1->commit('test commit', true);
836
        // push from r1 to r2
837
        $r2 = $this->getRepository(1);
838
        $r2->init(true);
839
        $r1->addRemote('origin', $r2->getPath());
840
        $r1->push('origin', 'master');
841
        // pull from r2 to r3 should get the same result
842
        $r3 = $this->getRepository(2);
843
        $r3->init();
844
        $r3->addRemote('origin', $r2->getPath());
845
        $r3->pull('origin', 'master');
846
847
        $this->assertEquals('test commit', $r3->getLog()->last()->getMessage());
848
        $this->assertEquals($r1->getMainBranch()->getSha(), $r3->getLog()->last()->getSha());
849
    }
850
851
    public function testRevParse(): void
852
    {
853
        $this->initRepository(null, 0);
854
        $r = $this->getRepository(0);
855
        $r->init();
856
        $this->addFile('test1', null, null, $r);
857
        $r->commit('test commit', true);
858
        $master = $r->getBranch('master');
859
        $revParse = $r->revParse($master, []);
0 ignored issues
show
Bug introduced by
It seems like $master defined by $r->getBranch('master') on line 858 can also be of type object<GitElephant\Objects\Branch>; however, GitElephant\Repository::revParse() does only seem to accept null|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
860
        $this->assertEquals($master->getSha(), $revParse[0]);
861
    }
862
863
    public function testIsBare(): void
864
    {
865
        $this->initRepository(null, 0);
866
        $r = $this->getRepository(0);
867
        $r->init();
868
869
        $this->assertEquals(false, $r->isBare());
870
871
        $this->initRepository(null, 1);
872
        $r = $this->getRepository(1);
873
        $r->init(true);
874
875
        $this->assertEquals(true, $r->isBare());
876
    }
877
878
    /**
879
     * test add, remove and get global configs
880
     *
881
     * @covers \GitElephant\Repository::addGlobalConfig
882
     * @covers \GitElephant\Repository::getGlobalConfigs
883
     * @covers \GitElephant\Repository::removeGlobalConfig
884
     */
885
    public function testGlobalConfigs(): void
886
    {
887
        $repo = $this->getRepository();
888
889
        $configs = [
890
            'test1' => true,
891
            'test2' => 1,
892
            'test3' => 'value',
893
        ];
894
        $this->assertEmpty($repo->getGlobalConfigs());
895
896
        foreach ($configs as $configName => $configValue) {
897
            $repo->addGlobalConfig($configName, $configValue);
898
        }
899
        $this->assertSame($configs, $repo->getGlobalConfigs());
900
901
        foreach (array_keys($configs) as $configName) {
902
            $repo->removeGlobalConfig($configName);
903
        }
904
        $this->assertEmpty($repo->getGlobalConfigs());
905
    }
906
907
    /**
908
     * test reset
909
     */
910
    public function testResetHard(): void
911
    {
912
        $this->initRepository();
913
        $repo = $this->getRepository();
914
        $repo->init();
915
        $this->addFile('file1');
916
        $repo->stage();
917
        $repo->commit('message1');
918
        $headCommit = $repo->getCommit();
919
        $this->addFile('file2');
920
        $repo->stage();
921
        $repo->commit('message2');
922
923
        $this->assertEquals(2, $repo->countCommits());
924
        $repo->reset($headCommit, [ResetCommand::OPTION_HARD]);
925
        $this->assertEquals(1, $repo->countCommits());
926
        $this->assertEmpty($repo->getIndexStatus()->added());
927
    }
928
929
    /**
930
     * test reset
931
     */
932
    public function testResetSoft(): void
933
    {
934
        $this->initRepository();
935
        $repo = $this->getRepository();
936
        $repo->init();
937
        $this->addFile('file1');
938
        $repo->stage();
939
        $repo->commit('message1');
940
        $headCommit = $repo->getCommit();
941
        $this->addFile('file2');
942
        $repo->stage();
943
        $repo->commit('message2');
944
945
        $this->assertEquals(2, $repo->countCommits());
946
        $repo->reset($headCommit, [ResetCommand::OPTION_SOFT]);
947
        $this->assertEquals(1, $repo->countCommits());
948
        $this->assertNotEmpty($repo->getIndexStatus()->added());
949
    }
950
951
    /**
952
     * test add, remove and get global options
953
     *
954
     * @covers \GitElephant\Repository::addGlobalOption
955
     * @covers \GitElephant\Repository::getGlobalOptions
956
     * @covers \GitElephant\Repository::removeGlobalOption
957
     */
958
    public function testGlobalOptions(): void
959
    {
960
        $repo = $this->getRepository();
961
962
        $options = [
963
            'test1' => true,
964
            'test2' => 1,
965
            'test3' => 'value',
966
        ];
967
        $this->assertEmpty($repo->getGlobalOptions());
968
969
        foreach ($options as $configName => $configValue) {
970
            $repo->addGlobalOption($configName, $configValue);
971
        }
972
        $this->assertSame($options, $repo->getGlobalOptions());
973
974
        foreach (array_keys($options) as $configName) {
975
            $repo->removeGlobalOption($configName);
976
        }
977
        $this->assertEmpty($repo->getGlobalOptions());
978
    }
979
980
    /**
981
     * test add, remove and get global command arguments
982
     *
983
     * @covers \GitElephant\Repository::addGlobalCommandArgument
984
     * @covers \GitElephant\Repository::getGlobalCommandArguments
985
     * @covers \GitElephant\Repository::removeGlobalCommandArgument
986
     */
987
    public function testGlobalCommandArguments(): void
988
    {
989
        $repo = $this->getRepository();
990
991
        $args = [
992
            true,
993
            1,
994
            'value',
995
        ];
996
        $this->assertEmpty($repo->getGlobalCommandArguments());
997
998
        foreach ($args as $configValue) {
999
            $repo->addGlobalCommandArgument($configValue);
1000
        }
1001
        $this->assertSame($args, $repo->getGlobalCommandArguments());
1002
1003
        foreach ($args as $configValue) {
1004
            $repo->removeGlobalCommandArgument($configValue);
1005
        }
1006
        $this->assertEmpty($repo->getGlobalCommandArguments());
1007
    }
1008
1009
    /**
1010
     * @covers \GitElephant\Repository::stash
1011
     */
1012
    public function testStashThrowsExceptionIfNoCommits(): void
1013
    {
1014
        $this->getRepository()->init();
1015
        $this->addFile('test');
1016
1017
        $this->expectException('RuntimeException');
1018
        $this->getRepository()->stash('My stash', true);
1019
    }
1020
1021
    /**
1022
     * @covers \GitElephant\Repository::stash
1023
     */
1024
    public function testStash(): void
1025
    {
1026
        $this->getRepository()->init();
1027
        $this->addFile('test');
1028
        $this->getRepository()->commit('Test commit', true);
1029
        $this->addFile('test2');
1030
        $this->getRepository()->stash('My stash', true);
1031
        $this->assertTrue($this->getRepository()->isClean());
1032
        $stashList = $this->getRepository()->stashList();
1033
        $this->assertEquals(1, preg_match('%My stash%', $stashList[0]));
1034
    }
1035
1036
    /**
1037
     * @covers \GitElephant\Repository::stashList
1038
     */
1039
    public function testStashList(): void
1040
    {
1041
        $this->getRepository()->init();
1042
        $this->addFile('test');
1043
        $this->getRepository()->commit('Test commit', true);
1044
        $this->addFile('test2');
1045
        $this->getRepository()->stash('My stash', true);
1046
        $this->assertCount(1, $this->getRepository()->stashList());
1047
    }
1048
1049
    /**
1050
     * @covers \GitElephant\Repository::stashShow
1051
     */
1052
    public function testStashShow(): void
1053
    {
1054
        $this->getRepository()->init();
1055
        $this->addFile('test');
1056
        $this->getRepository()->commit('Test commit', true);
1057
        $this->addFile('test2');
1058
        $this->getRepository()->stash('My stash', true);
1059
        $this->assertIsString($this->getRepository()->stashShow(0));
1060
    }
1061
1062
    /**
1063
     * @covers \GitElephant\Repository::stashDrop
1064
     */
1065
    public function testStashDrop(): void
1066
    {
1067
        $this->getRepository()->init();
1068
        $this->addFile('test');
1069
        $this->getRepository()->commit('Test commit', true);
1070
        $this->addFile('test2');
1071
        $this->getRepository()->stash('My stash', true);
1072
        $this->getRepository()->stashDrop(0);
1073
        $this->assertCount(0, $this->getRepository()->stashList());
1074
    }
1075
1076
    /**
1077
     * @covers \GitElephant\Repository::stashPop
1078
     */
1079
    public function testStashPop(): void
1080
    {
1081
        $this->getRepository()->init();
1082
        $this->addFile('test');
1083
        $this->getRepository()->commit('Test commit', true);
1084
        $this->addFile('test2');
1085
        $this->getRepository()->stash('My stash', true);
1086
        $this->getRepository()->stashPop(0);
1087
        $this->assertTrue($this->getRepository()->isDirty());
1088
        $this->assertCount(0, $this->getRepository()->stashList());
1089
    }
1090
1091
    /**
1092
     * @covers \GitElephant\Repository::stashApply
1093
     */
1094
    public function testStashApply(): void
1095
    {
1096
        $this->getRepository()->init();
1097
        $this->addFile('test');
1098
        $this->getRepository()->commit('Test commit', true);
1099
        $this->addFile('test2');
1100
        $this->getRepository()->stash('My stash', true);
1101
        $this->getRepository()->stashApply(0);
1102
        $this->assertTrue($this->getRepository()->isDirty());
1103
        $this->assertCount(1, $this->getRepository()->stashList());
1104
    }
1105
1106
    /**
1107
     * @covers \GitElephant\Repository::stashBranch
1108
     */
1109
    public function testStashBranch(): void
1110
    {
1111
        $this->getRepository()->init();
1112
        $this->addFile('test');
1113
        $this->getRepository()->commit('Test commit', true);
1114
        $this->addFile('test2');
1115
        $this->getRepository()->stash('My stash', true);
1116
        $this->getRepository()->stashBranch('testbranch', 0);
1117
        $this->assertEquals('testbranch', $this->getRepository()->getMainBranch()->getName());
1118
    }
1119
1120
    /**
1121
     * @covers \GitElephant\Repository::stashCreate
1122
     */
1123
    public function testStashCreate(): void
1124
    {
1125
        $this->getRepository()->init();
1126
        $this->addFile('test');
1127
        $this->getRepository()->commit('Test commit', true);
1128
        $objectName = $this->getRepository()->stashCreate();
1129
        $this->assertIsString($objectName);
1130
    }
1131
1132
    /**
1133
     * @covers \GitElephant\Repository::stashCreate
1134
     */
1135
    public function testStashClear(): void
1136
    {
1137
        $this->getRepository()->init();
1138
        $this->addFile('test');
1139
        $this->getRepository()->commit('Test commit', true);
1140
        $this->addFile('test2');
1141
        $this->getRepository()->stash('My stash', true);
1142
        $this->addFile('test3');
1143
        $this->getRepository()->stash('My stash 2', true);
1144
        $this->getRepository()->stashClear();
1145
        $this->assertCount(0, $this->getRepository()->stashList());
1146
    }
1147
}
1148