Completed
Push — master ( cd8b67...6a06e1 )
by
unknown
13s
created

RepositoryTest::testStashClear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
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()
35
    {
36
        $this->initRepository();
37
    }
38
39
    /**
40
     * @covers \GitElephant\Repository::__construct
41
     * @covers \GitElephant\Repository::getPath
42
     */
43
    public function testConstruct()
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()
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()
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()
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()
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()
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()
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->assertStringEndsWith('file2', $output[4]);
161
    }
162
163
    /**
164
     * @covers \GitElephant\Repository::createBranch
165
     */
166
    public function testCreateBranch()
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()
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()
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()
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()
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()
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
        }
301
        catch (\RuntimeException $e) {
302
            return;
303
        }
304
        $this->fail("Merge should have produced a runtime exception.");
305
    }
306
307
    /**
308
     * @covers \GitElephant\Repository::getTags
309
     * @covers \GitElephant\Repository::getTag
310
     * @covers \GitElephant\Repository::createTag
311
     * @covers \GitElephant\Repository::deleteTag
312
     */
313
    public function testTags()
314
    {
315
        $this->getRepository()->init();
316
        $this->addFile('test-file');
317
        $this->getRepository()->commit('test', true);
318
        $this->assertEquals(0, count($this->getRepository()->getTags()));
319
        $this->getRepository()->createTag('test-tag');
320
        $this->assertEquals(1, count($this->getRepository()->getTags()));
321
        $this->assertInstanceOf('GitElephant\Objects\Tag', $this->getRepository()->getTag('test-tag'));
322
        $this->getRepository()->deleteTag('test-tag');
323
        $this->assertEquals(0, count($this->getRepository()->getTags()));
324
        $this->assertNull($this->getRepository()->getTag('a-tag-that-do-not-exists'));
325
    }
326
327
    /**
328
     * test getLastTag
329
     */
330
    public function testGetLastTag()
331
    {
332
        $this->getRepository()->init();
333
        $this->addFile('test-file');
334
        $this->getRepository()->commit('test', true);
335
        $this->getRepository()->createTag('0.0.2');
336
        sleep(1);
337
        $this->getRepository()->createTag('0.0.4');
338
        sleep(1);
339
        $this->getRepository()->createTag('0.0.3');
340
        sleep(1);
341
        $this->getRepository()->createTag('0.0.1');
342
        sleep(1);
343
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.1'), $this->getRepository()->getLastTag());
344
345
        $this->getRepository()->createTag('0.0.05');
346
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.05'), $this->getRepository()->getLastTag());
347
348
        $this->getRepository()->deleteTag(Tag::pick($this->getRepository(), '0.0.05'));
349
        $this->assertEquals(Tag::pick($this->getRepository(), '0.0.1'), $this->getRepository()->getLastTag());
350
    }
351
352
    /**
353
     * @covers \GitElephant\Repository::getCommit
354
     */
355
    public function testGetCommit()
356
    {
357
        $this->getRepository()->init();
358
        $this->addFile('test-file');
359
        $this->getRepository()->commit('test', true);
360
        $this->assertInstanceOf('GitElephant\Objects\Commit', $this->getRepository()->getCommit());
361
    }
362
363
    public function testGetBranchOrTag()
364
    {
365
        $this->getRepository()->init();
366
        $this->addFile('test-file');
367
        $this->getRepository()->commit('test', true);
368
        $this->getRepository()->createBranch('branch2');
369
        $this->getRepository()->createTag('tag1');
370
        $this->assertInstanceOf('\GitElephant\Objects\Branch', $this->getRepository()->getBranchOrTag('branch2'));
371
        $this->assertInstanceOf('\GitElephant\Objects\Tag', $this->getRepository()->getBranchOrTag('tag1'));
372
        $this->assertNull($this->getRepository()->getBranchOrTag('not-exists'));
373
    }
374
375
    /**
376
     * @covers \GitElephant\Repository::getObjectLog
377
     */
378
    public function testGetObjectLog()
379
    {
380
        $repo = $this->getRepository();
381
        $repo->init();
382
383
        $this->addFolder('test');
384
385
        $this->addFile('A.txt', 'test');
386
        $repo->commit('added A.txt', true);
387
388
        $this->addFile('B.txt', 'test');
389
        $repo->commit('added B.txt', true);
390
391
        $this->addFile('C.txt', 'test');
392
        $repo->commit('added C.txt', true);
393
394
        $this->addFile('D.txt', 'test');
395
        $repo->commit('added D.txt', true);
396
397
        $this->addFile('E.txt', 'test');
398
        $repo->commit('added E.txt', true);
399
400
        $tree = $repo->getTree();
401
        $obj = $tree[0];
402
403
        $log = $this->getRepository()->getObjectLog($obj);
404
        $this->assertInstanceOf(Log::class, $log);
405
        $this->assertEquals(1, $log->count());
406
407
        $log = $this->getRepository()->getObjectLog($obj, null, 10);
408
        $this->assertEquals(5, $log->count());
409
410
        $this->assertEquals('added E.txt', $log->first()->getMessage()->toString());
411
        $this->assertEquals('added A.txt', $log->last()->getMessage()->toString());
412
    }
413
414
    /**
415
     * Test logs on different tree objects
416
     *
417
     * @covers \GitElephant\Repository::getObjectLog
418
     */
419
    public function testGetObjectLogFolders()
420
    {
421
        $repo = $this->getRepository();
422
        $repo->init();
423
424
        $this->addFolder('A');
425
        $this->addFile('A1.txt', 'A');
426
        $repo->commit('A/A1', true);
427
428
        $this->addFile('A2.txt', 'A');
429
        $repo->commit('A/A2', true);
430
431
        $this->addFolder('B');
432
        $this->addFile('B1.txt', 'B');
433
        $repo->commit('B/B1', true);
434
435
        $this->addFile('B2.txt', 'B');
436
        $repo->commit('B/B2', true);
437
438
        $tree = $repo->getTree();
439
440
        /* @var $treeObj NodeObject */
441
        foreach ($tree as $treeObj) {
442
            $name = $treeObj->getName();
443
            $log = $repo->getObjectLog($treeObj, null, 10);
444
445
            $this->assertEquals(2, $log->count());
446
447
            $i = 2;
448
            foreach ($log as $commit) {
449
                $this->assertEquals($name . '/' . $name . $i, $commit->getMessage()->toString());
450
                --$i;
451
            }
452
        }
453
    }
454
455
    /**
456
     * Test logs on different branches
457
     *
458
     * @covers \GitElephant\Repository::getObjectLog
459
     */
460
    public function testGetObjectLogBranches()
461
    {
462
        $repo = $this->getRepository();
463
        $repo->init();
464
465
        $this->addFolder('A');
466
        $this->addFile('A1.txt', 'A');
467
        $repo->commit('A/A1', true);
468
469
        $this->addFile('A2.txt', 'A');
470
        $repo->commit('A/A2', true);
471
472
        $repo->createBranch('test-branch');
473
        $repo->checkout('test-branch');
474
475
        $this->addFile('A3.txt', 'A');
476
        $repo->commit('A/A3', true);
477
478
        // master branch
479
        $repo->checkout('master');
480
        $tree = $repo->getTree();
481
        $dir = $tree[0];
482
        $log = $repo->getObjectLog($dir, null, 10);
483
484
        $this->assertEquals(2, $log->count());
485
        $this->assertEquals('A/A2', $log->first()->getMessage()->toString());
486
487
        // test branch
488
        $repo->checkout('test-branch');
489
        $tree = $repo->getTree();
490
        $dir = $tree[0];
491
        $log = $repo->getObjectLog($dir, null, 10);
492
493
        $this->assertEquals(3, $log->count());
494
        $this->assertEquals('A/A3', $log->first()->getMessage()->toString());
495
    }
496
497
    /**
498
     * @covers \GitElephant\Repository::getLog
499
     */
500
    public function testGetLog()
501
    {
502
        $this->getRepository()->init();
503
504
        for ($i = 0; $i < 50; $i++) {
505
            $this->addFile('test file ' . $i);
506
            $this->getRepository()->commit('test commit ' . $i, true);
507
        }
508
509
        $log = $this->getRepository()->getLog();
510
        $this->assertInstanceOf('GitElephant\Objects\Log', $this->getRepository()->getLog());
511
        $this->assertGreaterThan(0, $log->count());
512
    }
513
514
    /**
515
     * @covers \GitElephant\Repository::getLog
516
     */
517
    public function testGetLog_for_a_branch()
518
    {
519
        $this->getRepository()->init();
520
        $this->addFile('test file 0');
521
        $this->getRepository()->commit('first commit', true);
522
        $this->getRepository()->checkout('test-branch', true);
523
524
        for ($i = 1; $i <= 2; $i++) {
525
            $this->addFile('test file ' . $i);
526
            $this->getRepository()->commit('test commit ' . $i, true);
527
        }
528
529
        $log = $this->getRepository()->getLog(['test-branch', '^master']);
530
        $this->assertInstanceOf('GitElephant\Objects\Log', $this->getRepository()->getLog());
531
        $this->assertEquals(2, $log->count());
532
    }
533
534
    /**
535
     * @covers \GitElephant\Repository::checkout
536
     */
537
    public function testCheckout()
538
    {
539
        $this->getRepository()->init();
540
        $this->addFile('test-file');
541
        $this->getRepository()->commit('test', true);
542
        $this->assertEquals('master', $this->getRepository()->getMainBranch()->getName());
543
        $this->getRepository()->createBranch('branch2');
544
        $this->getRepository()->checkout('branch2');
545
        $this->assertEquals('branch2', $this->getRepository()->getMainBranch()->getName());
546
    }
547
548
    /**
549
     * @covers \GitElephant\Repository::checkout
550
     */
551
    public function testCheckoutTag()
552
    {
553
        $this->getRepository()->init();
554
        $this->addFile('test-file');
555
        $this->getRepository()->commit('test', true);
556
        $this->getRepository()->createTag('v0.0.1');
557
        $this->addFile('test-file2');
558
        $this->getRepository()->commit('test2', true);
559
        $tag = $this->getRepository()->getTag('v0.0.1');
560
        $this->assertInstanceOf('GitElephant\Objects\Tag', $tag);
561
        $lastCommit = $this->getRepository()->getCommit();
562
        $this->assertNotContains('detached', implode(' ', $this->getRepository()->getStatusOutput()));
563
        $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 559 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...
564
        $newCommit = $this->getRepository()->getCommit();
565
        $this->assertNotEquals($newCommit->getSha(), $lastCommit->getSha());
566
        $this->assertContains('detached', implode(' ', $this->getRepository()->getStatusOutput()));
567
    }
568
569
    /**
570
     * @covers \GitElephant\Repository::getTree
571
     * @covers \GitElephant\Objects\Tree
572
     */
573
    public function testGetTree()
574
    {
575
        $this->getRepository()->init();
576
        $this->addFile('test');
577
        $this->addFolder('test-folder');
578
        $this->addFile('test2', 'test-folder');
579
580
        $this->getRepository()->stage();
581
        $this->getRepository()->commit('initial import');
582
583
        $tree = $this->getRepository()->getTree();
584
        $this->assertFalse($tree->isBlob());
585
        $this->assertTrue($this->getRepository()->getTree($this->getRepository()->getCommit(), 'test')->isBlob());
586
        $this->assertCount(2, $tree, 'One file in the repository');
587
        $firstNode = $tree[0];
588
        $this->assertInstanceOf(
589
            'GitElephant\Objects\NodeObject',
590
            $firstNode,
591
            'array access on tree should give always a node type'
592
        );
593
        $this->assertEquals(
594
            'test-folder',
595
            $firstNode->getName(),
596
            'First repository file should be named "test"'
597
        );
598
        $secondNode = $tree[1];
599
        $this->assertInstanceOf(
600
            'GitElephant\Objects\NodeObject',
601
            $secondNode,
602
            'array access on tree should give always a node type'
603
        );
604
        $this->assertEquals(
605
            NodeObject::TYPE_BLOB,
606
            $secondNode->getType(),
607
            'second node should be of type tree'
608
        );
609
        $subtree = $this->getRepository()->getTree('master', 'test-folder');
610
        $subnode = $subtree[0];
611
        $this->assertInstanceOf(
612
            'GitElephant\Objects\NodeObject',
613
            $subnode,
614
            'array access on tree should give always a node type'
615
        );
616
        $this->assertEquals(
617
            NodeObject::TYPE_BLOB,
618
            $subnode->getType(),
619
            'subnode should be of type blob'
620
        );
621
        $this->assertEquals(
622
            'test2',
623
            $subnode->getName(),
624
            'subnode should be named "test2"'
625
        );
626
    }
627
628
    /**
629
     * @covers \GitElephant\Repository::getDiff
630
     */
631
    public function testGetDiff()
632
    {
633
        $this->getRepository()->init();
634
        $this->addFile('test-file');
635
        $this->getRepository()->commit('commit 1', true);
636
        $commit1 = $this->getRepository()->getCommit();
637
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit1));
638
        $this->addFile('test-file2');
639
        $this->getRepository()->commit('commit 2', true);
640
        $commit2 = $this->getRepository()->getCommit();
641
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit2));
642
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $this->getRepository()->getDiff($commit2, $commit1));
643
        $shaHead = $this->getRepository()->getCommit();
644
        $this->assertInstanceOf('GitElephant\Objects\Diff\Diff', $diff = $this->getRepository()->getDiff($shaHead));
645
    }
646
647
    /**
648
     * testCloneFrom
649
     */
650
    public function testCloneFrom()
651
    {
652
        $this->initRepository(null, 0);
653
        $this->initRepository(null, 1);
654
        $remote = $this->getRepository(0);
655
        $remote->init();
656
        $this->addFile('test', null, null, $remote);
657
        $remote->commit('test', true);
658
        $local = $this->getRepository(1);
659
        $local->cloneFrom($remote->getPath(), '.');
660
        $commit = $local->getCommit();
661
        $this->assertEquals($remote->getCommit()->getSha(), $commit->getSha());
662
        $this->assertEquals($remote->getCommit()->getMessage(), $commit->getMessage());
663
    }
664
665
    /**
666
     * testOutputContent
667
     */
668
    public function testOutputContent()
669
    {
670
        $this->initRepository();
671
        $this->getRepository()->init();
672
        $this->addFile('file1', null, 'file content');
673
        $this->getRepository()->commit('first commit', true);
674
        $branch = $this->getRepository()->getBranch('master');
675
        $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 674 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...
676
        $treeObject = $tree->getBlob();
677
        $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 674 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...
678
    }
679
680
    /**
681
     * testMove
682
     */
683
    public function testMove()
684
    {
685
        $this->getRepository()->init();
686
        $this->addFile('foo');
687
        $this->getRepository()->commit('commit 1', true);
688
        $this->getRepository()->move('foo', 'bar');
689
        $status = $this->getRepository()->getStatusOutput();
690
691
        $this->assertRegExp('/(.*):    foo -> bar/', $status[4]);
692
    }
693
694
    /**
695
     * testRemove
696
     */
697
    public function testRemove()
698
    {
699
        $this->getRepository()->init();
700
        $this->addFile('foo');
701
        $this->getRepository()->commit('commit 1', true);
702
        $this->getRepository()->remove('foo');
703
        $status = $this->getRepository()->getStatusOutput();
704
705
        $this->assertRegExp('/(.*):    foo/', $status[4]);
706
    }
707
708
    /**
709
     * testCountCommits
710
     */
711
    public function testCountCommits()
712
    {
713
        $this->getRepository()->init();
714
        $this->addFile('foo');
715
        $this->getRepository()->commit('commit 1', true);
716
        $this->assertEquals(1, $this->getRepository()->countCommits());
717
        $this->addFile('foo2');
718
        $this->getRepository()->commit('commit 2', true);
719
        $this->assertEquals(2, $this->getRepository()->countCommits());
720
        $this->getRepository()->createBranch('new-branch');
721
        $this->getRepository()->checkout('new-branch');
722
        $this->assertEquals(2, $this->getRepository()->countCommits());
723
        $this->addFile('bar');
724
        $this->getRepository()->commit('commit 3', true);
725
        $this->assertEquals(3, $this->getRepository()->countCommits());
726
        $this->getRepository()->checkout('master');
727
        $this->assertEquals(2, $this->getRepository()->countCommits());
728
    }
729
730
    /**
731
     * testHumanishName
732
     */
733
    public function testHumanishName()
734
    {
735
        $this->initRepository('test-dir');
736
        $this->assertEquals('test-dir', $this->getRepository()->getHumanishName());
737
    }
738
739
    /**
740
     * testCreateFromRemote
741
     *
742
     */
743
    public function testCreateFromRemote()
744
    {
745
        $this->initRepository(null, 0);
746
        $remote = $this->getRepository(0);
747
        $remote->init();
748
        $this->addFile('test', null, null, $remote);
749
        $remote->commit('test', true);
750
        $remote->createBranch('develop');
751
752
        $repo = Repository::createFromRemote($remote->getPath());
753
        $this->assertInstanceOf('GitElephant\Repository', $repo);
754
        $this->assertGreaterThanOrEqual(2, $repo->getBranches());
755
        $branches = $repo->getBranches();
756
        $branchesName = array_map(
757
            function (Branch $b) {
758
                return $b->getName();
759
            },
760
            $branches
761
        );
762
        $this->assertContains('master', $branchesName);
763
        $this->assertContains('develop', $branchesName);
764
    }
765
766
    /**
767
     * testAddRemote
768
     */
769
    public function testRemote()
770
    {
771
        $this->initRepository(null, 0);
772
        $remote = $this->getRepository(0);
773
        $remote->init(true);
774
        $this->initRepository();
775
        $this->repository->init();
776
        $this->repository->addRemote('github', $remote->getPath());
777
        $this->assertInstanceOf('GitElephant\Objects\Remote', $this->repository->getRemote('github'));
778
        $this->repository->addRemote('github2', $remote->getPath());
779
        $this->assertCount(2, $this->repository->getRemotes());
780
    }
781
782
    /**
783
     * testFetch, git branch -a should find the branch
784
     */
785
    public function testFetch()
786
    {
787
        $this->initRepository(null, 0);
788
        $this->initRepository(null, 1);
789
        $r1 = $this->getRepository(0);
790
        $r1->init();
791
        $this->addFile('test1', null, null, $r1);
792
        $r1->commit('test commit', true);
793
        $r1->createBranch('tag-test');
794
        $this->addFile('test2', null, null, $r1);
795
        $r1->commit('another test commit', true);
796
        $r1->createTag('test-tag');
797
        $r2 = $this->getRepository(1);
798
        $r2->init();
799
        $r2->addRemote('origin', $r1->getPath());
800
        $this->assertEmpty($r2->getBranches(true, true));
801
        $r2->fetch();
802
        $this->assertNotEmpty($r2->getBranches(true, true));
803
        $r2->fetch(null, null, true);
804
        $this->assertNotNull($r2->getTag('test-tag'));
805
    }
806
807
    /**
808
     * test pull
809
     */
810
    public function testPull()
811
    {
812
        $this->initRepository(null, 0);
813
        $this->initRepository(null, 1);
814
        $r1 = $this->getRepository(0);
815
        $r1->init();
816
        $this->addFile('test1', null, null, $r1);
817
        $r1->commit('test commit', true);
818
        $r2 = $this->getRepository(1);
819
        $r2->init();
820
        $r2->addRemote('origin', $r1->getPath());
821
        $r2->pull('origin', 'master');
822
        $this->assertEquals('test commit', $r2->getLog()->last()->getMessage());
823
        $this->assertEquals($r1->getMainBranch()->getSha(), $r2->getLog()->last()->getSha());
824
    }
825
826
    /**
827
     * test pull
828
     */
829
    public function testPush()
830
    {
831
        $this->initRepository(null, 0);
832
        $this->initRepository(null, 1);
833
        $this->initRepository(null, 2);
834
        // commit on r1
835
        $r1 = $this->getRepository(0);
836
        $r1->init();
837
        $this->addFile('test1', null, null, $r1);
838
        $r1->commit('test commit', true);
839
        // push from r1 to r2
840
        $r2 = $this->getRepository(1);
841
        $r2->init(true);
842
        $r1->addRemote('origin', $r2->getPath());
843
        $r1->push('origin', 'master');
844
        // pull from r2 to r3 should get the same result
845
        $r3 = $this->getRepository(2);
846
        $r3->init();
847
        $r3->addRemote('origin', $r2->getPath());
848
        $r3->pull('origin', 'master');
849
850
        $this->assertEquals('test commit', $r3->getLog()->last()->getMessage());
851
        $this->assertEquals($r1->getMainBranch()->getSha(), $r3->getLog()->last()->getSha());
852
    }
853
854
    public function testRevParse()
855
    {
856
        $this->initRepository(null, 0);
857
        $r = $this->getRepository(0);
858
        $r->init();
859
        $this->addFile('test1', null, null, $r);
860
        $r->commit('test commit', true);
861
        $master = $r->getBranch('master');
862
        $revParse = $r->revParse($master, []);
0 ignored issues
show
Bug introduced by
It seems like $master defined by $r->getBranch('master') on line 861 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...
863
        $this->assertEquals($master->getSha(), $revParse[0]);
864
    }
865
866
    public function testIsBare()
867
    {
868
        $this->initRepository(null, 0);
869
        $r = $this->getRepository(0);
870
        $r->init();
871
872
        $this->assertEquals(false, $r->isBare());
873
874
        $this->initRepository(null, 1);
875
        $r = $this->getRepository(1);
876
        $r->init(true);
877
878
        $this->assertEquals(true, $r->isBare());
879
880
    }
881
882
    /**
883
     * test add, remove and get global configs
884
     *
885
     * @covers \GitElephant\Repository::addGlobalConfig
886
     * @covers \GitElephant\Repository::getGlobalConfigs
887
     * @covers \GitElephant\Repository::removeGlobalConfig
888
     */
889
    public function testGlobalConfigs()
890
    {
891
        $repo = $this->getRepository();
892
893
        $configs = [
894
            'test1' => true,
895
            'test2' => 1,
896
            'test3' => 'value',
897
        ];
898
        $this->assertEmpty($repo->getGlobalConfigs());
899
900
        foreach ($configs as $configName => $configValue) {
901
            $repo->addGlobalConfig($configName, $configValue);
902
        }
903
        $this->assertSame($configs, $repo->getGlobalConfigs());
904
905
        foreach ($configs as $configName => $configValue) {
906
            $repo->removeGlobalConfig($configName);
907
        }
908
        $this->assertEmpty($repo->getGlobalConfigs());
909
    }
910
911
    /**
912
     * test reset
913
     */
914
    public function testResetHard()
915
    {
916
        $this->initRepository();
917
        $repo = $this->getRepository();
918
        $repo->init();
919
        $this->addFile('file1');
920
        $repo->stage();
921
        $repo->commit('message1');
922
        $headCommit = $repo->getCommit();
923
        $this->addFile('file2');
924
        $repo->stage();
925
        $repo->commit('message2');
926
927
        $this->assertEquals(2, $repo->countCommits());
928
        $repo->reset($headCommit, [ResetCommand::OPTION_HARD]);
929
        $this->assertEquals(1, $repo->countCommits());
930
        $this->assertEmpty($repo->getIndexStatus()->added());
931
    }
932
933
    /**
934
     * test reset
935
     */
936
    public function testResetSoft()
937
    {
938
        $this->initRepository();
939
        $repo = $this->getRepository();
940
        $repo->init();
941
        $this->addFile('file1');
942
        $repo->stage();
943
        $repo->commit('message1');
944
        $headCommit = $repo->getCommit();
945
        $this->addFile('file2');
946
        $repo->stage();
947
        $repo->commit('message2');
948
949
        $this->assertEquals(2, $repo->countCommits());
950
        $repo->reset($headCommit, [ResetCommand::OPTION_SOFT]);
951
        $this->assertEquals(1, $repo->countCommits());
952
        $this->assertNotEmpty($repo->getIndexStatus()->added());
953
    }
954
955
    /**
956
     * test add, remove and get global options
957
     *
958
     * @covers \GitElephant\Repository::addGlobalOption
959
     * @covers \GitElephant\Repository::getGlobalOptions
960
     * @covers \GitElephant\Repository::removeGlobalOption
961
     */
962
    public function testGlobalOptions()
963
    {
964
        $repo = $this->getRepository();
965
966
        $options = [
967
            'test1' => true,
968
            'test2' => 1,
969
            'test3' => 'value',
970
        ];
971
        $this->assertEmpty($repo->getGlobalOptions());
972
973
        foreach ($options as $configName => $configValue) {
974
            $repo->addGlobalOption($configName, $configValue);
975
        }
976
        $this->assertSame($options, $repo->getGlobalOptions());
977
978
        foreach ($options as $configName => $configValue) {
979
            $repo->removeGlobalOption($configName);
980
        }
981
        $this->assertEmpty($repo->getGlobalOptions());
982
    }
983
984
    /**
985
     * test add, remove and get global command arguments
986
     *
987
     * @covers \GitElephant\Repository::addGlobalCommandArgument
988
     * @covers \GitElephant\Repository::getGlobalCommandArguments
989
     * @covers \GitElephant\Repository::removeGlobalCommandArgument
990
     */
991
    public function testGlobalCommandArguments()
992
    {
993
        $repo = $this->getRepository();
994
995
        $args = [
996
            true,
997
            1,
998
            'value',
999
        ];
1000
        $this->assertEmpty($repo->getGlobalCommandArguments());
1001
1002
        foreach ($args as $configValue) {
1003
            $repo->addGlobalCommandArgument($configValue);
1004
        }
1005
        $this->assertSame($args, $repo->getGlobalCommandArguments());
1006
1007
        foreach ($args as $configValue) {
1008
            $repo->removeGlobalCommandArgument($configValue);
1009
        }
1010
        $this->assertEmpty($repo->getGlobalCommandArguments());
1011
    }
1012
1013
    /**
1014
     * @covers \GitElephant\Repository::stash
1015
     */
1016
    public function testStashThrowsExceptionIfNoCommits()
1017
    {
1018
        $this->getRepository()->init();
1019
        $this->addFile('test');
1020
1021
        $this->expectException('RuntimeException');
1022
        $this->getRepository()->stash('My stash', true);
1023
    }
1024
1025
    /**
1026
     * @covers \GitElephant\Repository::stash
1027
     */
1028
    public function testStash()
1029
    {
1030
        $this->getRepository()->init();
1031
        $this->addFile('test');
1032
        $this->getRepository()->commit('Test commit', true);
1033
        $this->addFile('test2');
1034
        $this->getRepository()->stash('My stash', true);
1035
        $this->assertTrue($this->getRepository()->isClean());
1036
        $stashList = $this->getRepository()->stashList();
1037
        $this->assertEquals(1, preg_match('%My stash%', $stashList[0]));
1038
    }
1039
1040
    /**
1041
     * @covers \GitElephant\Repository::stashList
1042
     */
1043
    public function testStashList()
1044
    {
1045
        $this->getRepository()->init();
1046
        $this->addFile('test');
1047
        $this->getRepository()->commit('Test commit', true);
1048
        $this->addFile('test2');
1049
        $this->getRepository()->stash('My stash', true);
1050
        $this->assertCount(1, $this->getRepository()->stashList());
1051
    }
1052
1053
    /**
1054
     * @covers \GitElephant\Repository::stashShow
1055
     */
1056
    public function testStashShow()
1057
    {
1058
        $this->getRepository()->init();
1059
        $this->addFile('test');
1060
        $this->getRepository()->commit('Test commit', true);
1061
        $this->addFile('test2');
1062
        $this->getRepository()->stash('My stash', true);
1063
        $this->assertInternalType('string', $this->getRepository()->stashShow(0));
1064
    }
1065
1066
    /**
1067
     * @covers \GitElephant\Repository::stashDrop
1068
     */
1069
    public function testStashDrop()
1070
    {
1071
        $this->getRepository()->init();
1072
        $this->addFile('test');
1073
        $this->getRepository()->commit('Test commit', true);
1074
        $this->addFile('test2');
1075
        $this->getRepository()->stash('My stash', true);
1076
        $this->getRepository()->stashDrop(0);
1077
        $this->assertCount(0, $this->getRepository()->stashList());
1078
    }
1079
1080
    /**
1081
     * @covers \GitElephant\Repository::stashPop
1082
     */
1083
    public function testStashPop()
1084
    {
1085
        $this->getRepository()->init();
1086
        $this->addFile('test');
1087
        $this->getRepository()->commit('Test commit', true);
1088
        $this->addFile('test2');
1089
        $this->getRepository()->stash('My stash', true);
1090
        $this->getRepository()->stashPop(0);
1091
        $this->assertTrue($this->getRepository()->isDirty());
1092
        $this->assertCount(0, $this->getRepository()->stashList());
1093
    }
1094
1095
    /**
1096
     * @covers \GitElephant\Repository::stashApply
1097
     */
1098
    public function testStashApply()
1099
    {
1100
        $this->getRepository()->init();
1101
        $this->addFile('test');
1102
        $this->getRepository()->commit('Test commit', true);
1103
        $this->addFile('test2');
1104
        $this->getRepository()->stash('My stash', true);
1105
        $this->getRepository()->stashApply(0);
1106
        $this->assertTrue($this->getRepository()->isDirty());
1107
        $this->assertCount(1, $this->getRepository()->stashList());
1108
    }
1109
1110
    /**
1111
     * @covers \GitElephant\Repository::stashBranch
1112
     */
1113
    public function testStashBranch()
1114
    {
1115
        $this->getRepository()->init();
1116
        $this->addFile('test');
1117
        $this->getRepository()->commit('Test commit', true);
1118
        $this->addFile('test2');
1119
        $this->getRepository()->stash('My stash', true);
1120
        $this->getRepository()->stashBranch('testbranch', 0);
1121
        $this->assertEquals('testbranch', $this->getRepository()->getMainBranch()->getName());
1122
    }
1123
1124
    /**
1125
     * @covers \GitElephant\Repository::stashCreate
1126
     */
1127
    public function testStashCreate()
1128
    {
1129
        $this->getRepository()->init();
1130
        $this->addFile('test');
1131
        $this->getRepository()->commit('Test commit', true);
1132
        $objectName = $this->getRepository()->stashCreate();
1133
        $this->assertInternalType('string', $objectName);
1134
    }
1135
1136
    /**
1137
     * @covers \GitElephant\Repository::stashCreate
1138
     */
1139
    public function testStashClear()
1140
    {
1141
        $this->getRepository()->init();
1142
        $this->addFile('test');
1143
        $this->getRepository()->commit('Test commit', true);
1144
        $this->addFile('test2');
1145
        $this->getRepository()->stash('My stash', true);
1146
        $this->addFile('test3');
1147
        $this->getRepository()->stash('My stash 2', true);
1148
        $this->getRepository()->stashClear();
1149
        $this->assertCount(0, $this->getRepository()->stashList());
1150
    }
1151
1152
}
1153