Completed
Push — master ( a20e35...2a3e96 )
by Greg
03:21
created

CollectionCest   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 447
Duplicated Lines 18.57 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
wmc 17
lcom 0
cbo 1
dl 83
loc 447
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A _before() 0 4 1
A toRunMultipleTasksViaACollectionBuilder() 35 35 1
A toUseAWorkingDirWithACollectionBuilder() 0 30 1
A toRollbackAfterFailureViaACollectionBuilder() 30 30 1
A toRollbackAWorkingDir() 0 27 1
A toBuildFilesViaAddIterable() 0 27 1
A toRollbackANestedCollection() 0 36 1
A toRollbackInCorrectOrder() 0 23 1
A toCreateDirViaCollection() 18 18 1
A toUseATmpDirAndConfirmItIsDeleted() 0 38 1
A toUseATmpDirAndChangeWorkingDirectory() 0 41 1
A toCreateATmpFileAndConfirmItIsDeleted() 0 29 1
A toUseATmpDirWithAlternateSyntax() 0 24 1
A toCreateATmpDirWithoutACollection() 0 17 1
A toCreateATmpDirUsingShortcut() 0 14 1
A toThrowAnExceptionAndConfirmItIsCaught() 0 13 1
A toChainData() 0 22 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
namespace Robo;
3
4
use \CliGuy;
5
6
use Robo\Collection\Temporary;
7
8
class CollectionCest
9
{
10
    public function _before(CliGuy $I)
11
    {
12
        $I->amInPath(codecept_data_dir().'sandbox');
13
    }
14
15 View Code Duplication
    public function toRunMultipleTasksViaACollectionBuilder(CliGuy $I)
0 ignored issues
show
Duplication introduced by Greg Anderson
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
16
    {
17
        // This tests creating multiple tasks in a single builder,
18
        // which implicitly adds them to a collection.  To keep things
19
        // simple, we are only going to use taskFilesystemStack.  It
20
        // would be possible, of course, to do these operations with
21
        // a single FilesystemStack, but our goal is to test creating
22
        // multiple tasks with a builder, and ensure that a propper
23
        // collection is built.
24
        $collection = $I->collectionBuilder();
25
        $result = $collection->taskFilesystemStack()
26
                ->mkdir('a')
27
                ->touch('a/a.txt')
28
            ->rollback(
29
                $I->taskDeleteDir('a')
30
            )
31
            ->taskFilesystemStack()
32
                ->mkdir('a/b')
33
                ->touch('a/b/b.txt')
34
            ->taskFilesystemStack()
35
                ->mkdir('a/c')
36
                ->touch('a/c/c.txt')
37
            ->run();
38
39
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
40
41
        // All of the tasks created by the builder should be added
42
        // to a collection, and `run()` should run them all.
43
        $I->seeDirFound('a');
44
        $I->seeFileFound('a/a.txt');
45
        $I->seeDirFound('a/b');
46
        $I->seeFileFound('a/b/b.txt');
47
        $I->seeDirFound('a/c');
48
        $I->seeFileFound('a/c/c.txt');
49
    }
50
51
    public function toUseAWorkingDirWithACollectionBuilder(CliGuy $I)
52
    {
53
        // Run the same test with a working directory.  The working
54
        // directory path will point to a temporary directory which
55
        // will be moved into place once the tasks complete.
56
        $collection = $I->collectionBuilder();
57
        $workDirPath = $collection->workDir("build");
58
        $I->assertNotEquals("build", basename($workDirPath));
59
        $result = $collection->taskFilesystemStack()
60
                ->mkdir("{$workDirPath}/a")
61
                ->touch("{$workDirPath}/a/a.txt")
62
            ->taskFilesystemStack()
63
                ->mkdir("{$workDirPath}/a/b")
64
                ->touch("{$workDirPath}/a/b/b.txt")
65
            ->taskFilesystemStack()
66
                ->mkdir("{$workDirPath}/a/c")
67
                ->touch("{$workDirPath}/a/c/c.txt")
68
            ->run();
69
70
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
71
72
        // All of the tasks created by the builder should be added
73
        // to a collection, and `run()` should run them all.
74
        $I->seeDirFound('build/a');
75
        $I->seeFileFound('build/a/a.txt');
76
        $I->seeDirFound('build/a/b');
77
        $I->seeFileFound('build/a/b/b.txt');
78
        $I->seeDirFound('build/a/c');
79
        $I->seeFileFound('build/a/c/c.txt');
80
    }
81
82 View Code Duplication
    public function toRollbackAfterFailureViaACollectionBuilder(CliGuy $I)
0 ignored issues
show
Duplication introduced by Greg Anderson
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
85
        // except we force an error at the end, and confirm that the
86
        // rollback function is called.
87
        $collection = $I->collectionBuilder();
88
        $result = $collection->taskFilesystemStack()
89
                ->mkdir('j')
90
                ->touch('j/j.txt')
91
            ->rollback(
92
                $I->taskDeleteDir('j')
93
            )
94
            ->taskFilesystemStack()
95
                ->mkdir('j/k')
96
                ->touch('j/k/k.txt')
97
            ->taskFilesystemStack()
98
                ->mkdir('j/k/m')
99
                ->touch('j/k/m/m.txt')
100
            ->taskCopyDir(['doesNotExist' => 'copied'])
101
            ->run();
102
103
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
104
105
        // All of the tasks created by the builder should be added
106
        // to a collection, and `run()` should run them all.
107
        $I->dontSeeFileFound('q/q.txt');
108
        $I->dontSeeFileFound('j/j.txt');
109
        $I->dontSeeFileFound('j/k/k.txt');
110
        $I->dontSeeFileFound('j/k/m/m.txt');
111
    }
112
113
    public function toRollbackAWorkingDir(CliGuy $I)
114
    {
115
        // Run the same test with a working directory.  The working
116
        // directory path will point to a temporary directory which
117
        // will be moved into place once the tasks complete.
118
        $collection = $I->collectionBuilder();
119
        $workDirPath = $collection->workDir("build");
120
        $I->assertNotEquals("build", basename($workDirPath));
121
        $result = $collection->taskFilesystemStack()
122
                ->mkdir("{$workDirPath}/a")
123
                ->touch("{$workDirPath}/a/a.txt")
124
            ->taskFilesystemStack()
125
                ->mkdir("{$workDirPath}/a/b")
126
                ->touch("{$workDirPath}/a/b/b.txt")
127
            ->taskFilesystemStack()
128
                ->mkdir("{$workDirPath}/a/c")
129
                ->touch("{$workDirPath}/a/c/c.txt")
130
            ->taskCopyDir(['doesNotExist' => 'copied'])
131
            ->run();
132
133
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
134
135
        // All of the tasks created by the builder should be added
136
        // to a collection, and `run()` should run them all.
137
        $I->dontSeeFileFound('build/a');
138
        $I->dontSeeFileFound($workDirPath);
139
    }
140
141
    public function toBuildFilesViaAddIterable(CliGuy $I)
142
    {
143
        $processList = ['cats', 'dogs', 'sheep', 'fish', 'horses', 'cows'];
144
145
        $collection = $I->collectionBuilder();
146
        $result = $collection
147
            ->taskFilesystemStack()
148
                ->mkdir('stuff')
149
            ->taskForEach($processList)
150
                ->withBuilder(
151
                    function ($builder, $key, $value) {
152
                        return $builder
153
                            ->taskFilesystemStack()
154
                                ->touch("stuff/{$value}.txt");
155
                    }
156
                )
157
            ->run();
158
159
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
160
161
        $I->seeFileFound('stuff/cats.txt');
162
        $I->seeFileFound('stuff/dogs.txt');
163
        $I->seeFileFound('stuff/sheep.txt');
164
        $I->seeFileFound('stuff/fish.txt');
165
        $I->seeFileFound('stuff/horses.txt');
166
        $I->seeFileFound('stuff/cows.txt');
167
    }
168
169
    public function toRollbackANestedCollection(CliGuy $I)
170
    {
171
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
172
        // except we force an error at the end, and confirm that the
173
        // rollback function is called.
174
        $collection = $I->collectionBuilder();
175
        $collection->taskFilesystemStack()
176
                ->mkdir('j')
177
                ->touch('j/j.txt')
178
            ->rollback(
179
                $I->taskDeleteDir('j')
180
            )
181
            ->taskFilesystemStack()
182
                ->mkdir('j/k')
183
                ->touch('j/k/k.txt')
184
            ->taskFilesystemStack()
185
                ->mkdir('j/k/m')
186
                ->touch('j/k/m/m.txt');
187
188
        $result = $I->collectionBuilder()
189
            ->taskFilesystemStack()
190
                ->mkdir('q')
191
                ->touch('q/q.txt')
192
            ->addTask($collection)
193
            ->taskCopyDir(['doesNotExist' => 'copied'])
194
            ->run();
195
196
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
197
198
        // All of the tasks created by the builder should be added
199
        // to a collection, and `run()` should run them all.
200
        $I->seeFileFound('q/q.txt');
201
        $I->dontSeeFileFound('j/j.txt');
202
        $I->dontSeeFileFound('j/k/k.txt');
203
        $I->dontSeeFileFound('j/k/m/m.txt');
204
    }
205
206
    public function toRollbackInCorrectOrder(CliGuy $I)
207
    {
208
        $expected_order = [4,3,2,1];
209
        $actual_order = [];
210
        $collection = $I->collectionBuilder();
211
        $collection->rollbackCode(function () use (&$actual_order) {
212
            $actual_order[] = 1;
213
        });
214
        $collection->rollbackCode(function () use (&$actual_order) {
215
            $actual_order[] = 2;
216
        });
217
        $collection->rollbackCode(function () use (&$actual_order) {
218
            $actual_order[] = 3;
219
        });
220
        $collection->rollbackCode(function () use (&$actual_order) {
221
            $actual_order[] = 4;
222
        });
223
        $collection->addCode(function () {
224
            return Result::EXITCODE_ERROR;
225
        });
226
        $result = $collection->run();
0 ignored issues
show
Unused Code introduced by James Sansbury
$result 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...
227
        $I->assertEquals($expected_order, $actual_order);
228
    }
229
230 View Code Duplication
    public function toCreateDirViaCollection(CliGuy $I)
0 ignored issues
show
Duplication introduced by Greg Anderson
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
231
    {
232
        // Set up a collection to add tasks to
233
        $collection = $I->collectionBuilder();
234
235
        // Set up a filesystem stack
236
        $collection->taskFilesystemStack()
237
            ->mkdir('log')
238
            ->touch('log/error.txt');
239
240
        // FilesystemStack has not run yet, so file should not be found.
241
        $I->dontSeeFileFound('log/error.txt');
242
243
        // Run the task collection; now the files should be present
244
        $collection->run();
245
        $I->seeFileFound('log/error.txt');
246
        $I->seeDirFound('log');
247
    }
248
249
    public function toUseATmpDirAndConfirmItIsDeleted(CliGuy $I)
250
    {
251
        // Set up a collection to add tasks to
252
        $collection = $I->collectionBuilder();
253
254
        // Get a temporary directory to work in. Note that we get a
255
        // name back, but the directory is not created until the task
256
        // runs.  This technically is not thread-safe, but we create
257
        // a random name, so it is unlikely to conflict.
258
        $tmpPath = $collection->tmpDir();
259
260
        // Set up a filesystem stack, but use a collection to defer execution
261
        $collection->taskFilesystemStack()
262
            ->mkdir("$tmpPath/tmp")
263
            ->touch("$tmpPath/tmp/error.txt")
264
            ->rename("$tmpPath/tmp", "$tmpPath/log");
265
266
        // Copy our tmp directory to a location that is not transient
267
        $collection->taskCopyDir([$tmpPath => 'copied']);
268
269
        // FilesystemStack has not run yet, so no files should be found.
270
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
271
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
272
        $I->dontSeeFileFound('copied/log/error.txt');
273
274
        // Run the task collection
275
        $result = $collection->run();
276
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
277
        $I->assertEquals($result['path'], $tmpPath, "Tmp dir result matches accessor.");
278
279
        // The file 'error.txt' should have been copied into the "copied" dir.
280
        // This also proves that the tmp directory was created.
281
        $I->seeFileFound('copied/log/error.txt');
282
        // $tmpPath should be deleted after $collection->run() completes.
283
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
284
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
285
        $I->dontSeeFileFound("$tmpPath");
286
    }
287
288
    public function toUseATmpDirAndChangeWorkingDirectory(CliGuy $I)
289
    {
290
        // Set up a collection to add tasks to
291
        $collection = $I->collectionBuilder();
292
293
        $cwd = getcwd();
294
295
        $tmpPath = $collection->taskTmpDir()
296
            ->cwd()
297
            ->getPath();
298
299
        // Set up a filesystem stack, but use a collection to defer execution.
300
        // Note that since we used 'cwd()' above, the relative file paths
301
        // used below will be inside the temporary directory.
302
        $collection->taskFilesystemStack()
303
            ->mkdir("log")
304
            ->touch("log/error.txt");
305
306
        // Copy our tmp directory to a location that is not transient
307
        $collection->taskCopyDir(['log' => "$cwd/copied2"]);
308
309
        // FilesystemStack has not run yet, so no files should be found.
310
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
311
        $I->dontSeeFileFound('$cwd/copied2/log/error.txt');
312
313
        // Run the task collection
314
        $result = $collection->run();
315
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
316
317
        // The file 'error.txt' should have been copied into the "copied" dir
318
        $I->seeFileFound("$cwd/copied2/error.txt");
319
        // $tmpPath should be deleted after $collection->run() completes.
320
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
321
        // Make sure that 'log' was created in the temporary directory, not
322
        // at the current working directory.
323
        $I->dontSeeFileFound("$cwd/log/error.txt");
324
325
        // Make sure that our working directory was restored.
326
        $finalWorkingDir = getcwd();
327
        $I->assertEquals($cwd, $finalWorkingDir);
328
    }
329
330
    public function toCreateATmpFileAndConfirmItIsDeleted(CliGuy $I)
331
    {
332
        // Set up a collection to add tasks to
333
        $collection = $I->collectionBuilder();
334
335
        // Write to a temporary file. Note that we can get the path
336
        // to the tempoary file that will be created, even though the
337
        // the file is not created until the task collecction runs.
338
        $tmpPath = $collection->taskTmpFile('tmp', '.txt')
339
            ->line("This is a test file")
340
            ->getPath();
341
342
        // Copy our tmp directory to a location that is not transient
343
        $collection->taskFilesystemStack()
344
            ->copy($tmpPath, 'copied.txt');
345
346
        // FilesystemStack has not run yet, so no files should be found.
347
        $I->dontSeeFileFound("$tmpPath");
348
        $I->dontSeeFileFound('copied.txt');
349
350
        // Run the task collection
351
        $result = $collection->run();
352
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
353
354
        // The file 'copied.txt' should have been copied from the tmp file
355
        $I->seeFileFound('copied.txt');
356
        // $tmpPath should be deleted after $collection->run() completes.
357
        $I->dontSeeFileFound("$tmpPath");
358
    }
359
360
    public function toUseATmpDirWithAlternateSyntax(CliGuy $I)
361
    {
362
        $collection = $I->collectionBuilder();
363
364
        // This test is equivalent to toUseATmpDirAndConfirmItIsDeleted,
365
        // but uses a different technique to create a collection of tasks.
366
        $tmpPath = $collection->tmpDir();
367
368
        // Now, rather than creating the tasks with a collection builder,
369
        // which automatically adds the tasks to the collection as they are
370
        // created, we will instead create them individually and then add
371
        // them to the collection via the addTaskList() method.
372
        $result = $collection->addTaskList(
373
            [
374
                $I->taskFilesystemStack()->mkdir("$tmpPath/log")->touch("$tmpPath/log/error.txt"),
375
                $I->taskCopyDir([$tmpPath => 'copied3']),
376
            ]
377
        )->run();
378
379
        // The results of this operation should be the same.
380
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
381
        $I->seeFileFound('copied3/log/error.txt');
382
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
383
    }
384
385
    public function toCreateATmpDirWithoutACollection(CliGuy $I)
386
    {
387
        // Create a temporary directory, using our function name as
388
        // the prefix for the directory name.
389
        $tmpDirTask = $I->taskTmpDir(__FUNCTION__);
390
        $tmpPath = $tmpDirTask->getPath();
391
        $I->dontSeeFileFound($tmpPath);
392
        $tmpDirTask->run();
393
        $I->seeDirFound($tmpPath);
394
        // Creating a temporary directory without a task collection will
395
        // cause the temporary directory to be deleted when the program
396
        // terminates.  We can force it to clean up sooner by calling
397
        // TransientManager::complete(); note that this deletes ALL global tmp
398
        // directories, so this is not thread-safe!  Useful in tests, though.
399
        Temporary::complete();
400
        $I->dontSeeFileFound($tmpPath);
401
    }
402
403
    public function toCreateATmpDirUsingShortcut(CliGuy $I)
404
    {
405
        // Create a temporary directory, using our function name as
406
        // the prefix for the directory name.
407
        $tmpPath = $I->shortcutTmpDir(__FUNCTION__);
408
        $I->seeDirFound($tmpPath);
409
        // Creating a temporary directory without a task collection will
410
        // cause the temporary directory to be deleted when the program
411
        // terminates.  We can force it to clean up sooner by calling
412
        // TransientManager::complete(); note that this deletes ALL global tmp
413
        // directories, so this is not thread-safe!  Useful in tests, though.
414
        Temporary::complete();
415
        $I->dontSeeFileFound($tmpPath);
416
    }
417
418
    public function toThrowAnExceptionAndConfirmItIsCaught(CliGuy $I)
419
    {
420
        $collection = $I->getContainer()->get('collection');
421
422
        $collection->addCode(
423
            function () {
424
                throw new \RuntimeException('Error');
425
            }
426
        );
427
        $result = $collection->run();
428
        $I->assertEquals('Error', $result->getMessage());
429
        $I->assertEquals(1, $result->getExitCode());
430
    }
431
432
    public function toChainData(CliGuy $I)
433
    {
434
        $collection = $I->collectionBuilder();
435
436
        $result = $collection
0 ignored issues
show
Unused Code introduced by Greg Anderson
$result 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...
437
            ->taskValueProvider()
438
                ->provideMessage('1st') // Sets Result's message to '1st'
439
                ->storeState('one') // Copy Result's message to $state['one']
440
            ->taskValueProvider()
441
                ->provideMessage('2nd')
442
                ->storeState('two')
443
            ->taskValueProvider()
444
                ->deferTaskConfiguration('provideItem', 'one') // Same as ->proivdeItem($state['one']), but runs immediately before this task's run() method.
445
                ->deferTaskConfiguration('provideMessage', 'two')
446
                ->storeState('final')
447
            ->run();
448
449
        $state = $collection->getState();
450
        $I->assertEquals('1st', $state['one']);
451
        $I->assertEquals('1st', $state['item']);
452
        $I->assertEquals('2nd', $state['final']);
453
    }
454
}
455