CreateHandlerTest   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 203
Duplicated Lines 4.93 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 14
c 2
b 1
f 0
lcom 1
cbo 5
dl 10
loc 203
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 10 10 1
A testGenerate() 0 20 1
A generateProvider() 0 7 1
A testWriteClass() 0 21 2
A writeClassProvider() 0 5 1
A testHandleNoMigrationsDirectory() 0 9 1
B testHandle() 0 52 6
B handleProvider() 0 31 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
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace BaleenTest\Cli\CommandBus\Repository;
21
22
use Baleen\Cli\CommandBus\Repository\CreateMessage;
23
use Baleen\Cli\CommandBus\Repository\CreateHandler;
24
use Baleen\Cli\Config\Config;
25
use Baleen\Cli\Exception\CliException;
26
use Baleen\Migrations\Migration\SimpleMigration;
27
use BaleenTest\Cli\CommandBus\HandlerTestCase;
28
use League\Flysystem\Filesystem;
29
use Mockery as m;
30
use Zend\Code\Generator\ClassGenerator;
31
32
/**
33
 * Class CreateHandlerTest
34
 * @author Gabriel Somoza <[email protected]>
35
 */
36
class CreateHandlerTest extends HandlerTestCase
37
{
38
    /** @var m\Mock|Filesystem */
39
    protected $filesystem;
40
41
    /**
42
     * setUp
43
     */
44 View Code Duplication
    public function setUp()
45
    {
46
        $this->instance = m::mock(CreateHandler::class)
47
            ->shouldAllowMockingProtectedMethods()
48
            ->makePartial();
49
        $this->filesystem = m::mock(Filesystem::class);
50
        $this->command = m::mock(CreateMessage::class);
51
        $this->command->shouldReceive('getFilesystem')->zeroOrMoreTimes()->andReturn($this->filesystem);
52
        parent::setUp();
53
    }
54
55
    /**
56
     * @param $className
57
     * @param null $namespace
58
     * @dataProvider generateProvider
59
     */
60
    public function testGenerate($className, $namespace = null)
61
    {
62
        /** @var \Zend\Code\Generator\ClassGenerator $result */
63
        $result = $this->invokeMethod('generate', $this->instance, [$className, $namespace]);
64
65
        $this->assertEquals($className, $result->getName());
66
        $this->assertEquals($namespace, $result->getNamespaceName());
67
        $this->assertContains(SimpleMigration::class, $result->getUses());
68
        $this->assertEquals(
69
            substr(SimpleMigration::class, strrpos(SimpleMigration::class, '\\') + 1),
70
            $result->getExtendedClass(),
71
            sprintf(
72
                'Expected generated class to extend "%s"; got "%s" instead.',
73
                SimpleMigration::class,
74
                $result->getExtendedClass()
75
            )
76
        );
77
        $this->assertTrue($result->hasMethod('up'), 'Expected generated class to have method "up()"');
78
        $this->assertTrue($result->hasMethod('down'), 'Expected generated class to have method "down()"');
79
    }
80
81
    /**
82
     * @return array
83
     */
84
    public function generateProvider()
85
    {
86
        return [
87
            ['TestDefaults'],
88
            ['TestValidParams', 'TestNamespace'],
89
        ];
90
    }
91
92
    /**
93
     * testWriteClass
94
     * @param $has
95
     * @param $writeResult
96
     *
97
     * @dataProvider writeClassProvider
98
     */
99
    public function testWriteClass($has, $writeResult)
100
    {
101
        $generator = new ClassGenerator();
102
        $className = 'TestClass';
103
        $generator->setName($className);
104
105
        $migrationsDir = 'migrations';
106
107
        $filePath = $migrationsDir . DIRECTORY_SEPARATOR . $className . '.php';
108
109
        $this->filesystem->shouldReceive('has')->with($filePath)->andReturn($has);
110
111
        if ($has) {
112
            $this->filesystem->shouldNotReceive('write');
113
            $this->setExpectedException(CliException::class, 'already exists');
114
        } else {
115
            $this->filesystem->shouldReceive('write')->with($filePath, m::type('string'))->andReturn($writeResult);
116
        }
117
118
        $this->invokeMethod('writeClass', $this->instance, [$generator, $this->filesystem, $migrationsDir]);
119
    }
120
121
    /**
122
     * @return array
123
     */
124
    public function writeClassProvider()
125
    {
126
        $trueFalse = [true, false];
127
        return $this->combinations([$trueFalse, $trueFalse]);
128
    }
129
130
    /**
131
     * testHandleNoMigrationsDirectory
132
     */
133
    public function testHandleNoMigrationsDirectory()
134
    {
135
        $this->filesystem->shouldReceive('has')->once()->andReturn(false);
136
        $config = m::mock(Config::class);
137
        $config->shouldReceive(['getMigrationsDirectory' => 'migrations']);
138
        $this->command->shouldReceive('getConfig')->once()->andReturn($config);
139
        $this->setExpectedException(CliException::class, 'not exist');
140
        $this->handle();
141
    }
142
143
    /**
144
     * testHandle
145
     * @param $title
146
     * @param $namespace
147
     * @param $success
148
     * @param $editorCmd
149
     * @dataProvider handleProvider
150
     */
151
    public function testHandle($title, $namespace, $success, $editorCmd = null)
152
    {
153
        $migrationsDirectory = 'migrations';
154
        $this->filesystem->shouldReceive('has')->once()->with($migrationsDirectory)->andReturn(true);
155
156
        $config = m::mock(Config::class);
157
        $config->shouldReceive(['getMigrationsDirectory' => $migrationsDirectory])->once();
158
        if ($editorCmd) {
159
            $config->shouldReceive('getMigrationsDirectoryPath')->once()->andReturn($migrationsDirectory);
160
        }
161
        $this->command->shouldReceive('getConfig')->once()->andReturn($config);
162
163
        $argumentNamespace = key($namespace) ?: null;
164
        if (null === $argumentNamespace) {
165
            $config->shouldReceive(['getMigrationsNamespace' => 'DefaultNamespace'])->once();
166
            $expectedNamespace = 'DefaultNamespace';
167
        } else {
168
            $expectedNamespace = current($namespace);
169
        }
170
        $this->input->shouldReceive('getOption')->with('namespace')->once()->andReturn($argumentNamespace);
171
        $this->input->shouldReceive('getOption')->with('editor-cmd')->once()->andReturn($editorCmd);
172
173
        $argumentTitle = key($title);
174
        $expectedTitle = current($title);
175
        $this->input->shouldReceive('getArgument')->with('title')->andReturn($argumentTitle);
176
177
        $titleRegex = !empty($argumentTitle) ? "_$expectedTitle" : '';
178
        $expectedRegex = "/v[0-9]+$titleRegex/";
179
180
        $generateResult = m::mock(ClassGenerator::class);
181
        $this->instance
182
            ->shouldReceive('generate')
183
            ->once()
184
            ->with($expectedRegex, $expectedNamespace)
185
            ->andReturn($generateResult);
186
187
        $this->instance
188
            ->shouldReceive('writeClass')
189
            ->once()
190
            //->with($generateResult, $this->filesystem, $migrationsDirectory)
191
            ->andReturn($success);
192
193
        $with = null;
194
        if ($success) {
195
            $with = '/[Cc]reated/';
196
        } else {
197
            $with = '/error/';
198
        }
199
        $this->output->shouldReceive('writeln')->with($with)->once();
200
201
        $this->handle();
202
    }
203
204
    /**
205
     * @return array
206
     */
207
    public function handleProvider()
208
    {
209
        return [
210
            [ // simple test
211
                ['SimpleTitle' => 'SimpleTitle'],
212
                ['SimpleNamespace' => 'SimpleNamespace'],
213
                true, // success
214
            ],
215
            [ // simple test with editor cmd
216
                ['SimpleTitle' => 'SimpleTitle'],
217
                ['SimpleNamespace' => 'SimpleNamespace'],
218
                true,
219
                'which' // FIXME: it would be better to test whether this gets called
220
            ],
221
            [ // test null namespace (load from config)
222
                ['SimpleTitle' => 'SimpleTitle'],
223
                [0 => 'SimpleNamespace'],
224
                true,
225
            ],
226
            [ // test write failure
227
                ['SimpleTitle' => 'SimpleTitle'],
228
                ['SimpleNamespace\\' => 'SimpleNamespace'], // also test trailing \ in namespace name
229
                false,
230
            ],
231
            [ // test title and namespace sanitizing
232
                ['I!n@v@a#l$i%d=_-+^T&i*t(l)e' => 'Invalid_Title'],
233
                ['I!n@v#a$l%i^d&_¶N*a(m)e∞s-p+a=ce' => 'Invalid_Namespace'],
234
                true,
235
            ],
236
        ];
237
    }
238
}
239