Passed
Push — master ( 6215ec...1255dc )
by Darío
01:47
created

RouterTest::testModuleAndControllerComposition()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 46
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 23
nc 3
nop 0
dl 0
loc 46
rs 9.552
c 0
b 0
f 0
1
<?php
2
/**
3
 * DronePHP (http://www.dronephp.com)
4
 *
5
 * @link      http://github.com/Pleets/DronePHP
6
 * @copyright Copyright (c) 2016-2018 Pleets. (http://www.pleets.org)
7
 * @license   http://www.dronephp.com/license
8
 * @author    Darío Rivera <[email protected]>
9
 */
10
11
namespace DroneTest\Util;
12
13
use Drone\Mvc\Router;
14
use Drone\Mvc\AbstractController;
15
use Drone\Mvc\AbstractModule;
16
use Drone\Mvc\ModuleFactory;
17
use Drone\Mvc\Exception\MethodExecutionNotAllowedException;
18
use Drone\Mvc\Exception\RouteNotFoundException;
19
use PHPUnit\Framework\TestCase;
20
21
class RouterTest extends TestCase
22
{
23
    /**
24
     * Tests if the router can create an instance of a class
25
     *
26
     * @return null
27
     */
28
    public function testSimpleRouteMatch()
29
    {
30
        $router = new Router();
31
32
        $router->addRoute([
33
            'App1' => [
34
                'module'     => 'App',
35
                'controller' => 'Index',
36
                'view'       => 'home'
37
            ],
38
        ]);
39
40
        $router->setIdentifiers('App', 'Index', 'home');
41
        $router->match();
42
43
        $ctrl = $router->getController();
44
45
        $this->assertEquals("App\Index", get_class($ctrl));
46
    }
47
48
    /**
49
     * Tests if the router can create an instance of a class when the route does not exists
50
     *
51
     * @return null
52
     */
53
    public function testSimpleRouteMatchFail()
54
    {
55
        $router = new Router();
56
57
        $router->addRoute([
58
            'App1' => [
59
                'module'     => 'MyApp',
60
                'controller' => 'IndexController',
61
                'view'       => 'home'
62
            ],
63
        ]);
64
65
        $router->setIdentifiers('App', 'Index', 'home');
66
67
        $errorObject = null;
68
69
        try {
70
            $router->match();
71
        }
72
        catch (\Exception $e)
73
        {
74
            $errorObject = ($e instanceof RouteNotFoundException);
75
        }
76
        finally
77
        {
78
            $this->assertTrue($errorObject, $e->getMessage());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $e does not seem to be defined for all execution paths leading up to this point.
Loading history...
79
        }
80
    }
81
82
    /**
83
     * Tests if the router can create an instance of a class by a default route
84
     *
85
     * @return null
86
     */
87
    public function testDefaultRouteMatch()
88
    {
89
        $router = new Router();
90
91
        $router->addRoute([
92
            'AppRoute1' => [
93
                'module'     => 'App',
94
                'controller' => 'Index',
95
                'view'       => 'home'
96
            ]
97
        ]);
98
99
        $router->addRoute([
100
            'AppRoute2' => [
101
                'module'     => 'App',
102
                'controller' => 'Index2',
103
                'view'       => 'home'
104
            ]
105
        ]);
106
107
        $router->setDefaults('App', 'Index', 'home');
108
        $router->match();
109
        $ctrl = $router->getController();
110
111
        $this->assertEquals("App\Index", get_class($ctrl));
112
113
        $router->setIdentifiers('App', 'Index2', 'home');
114
        $router->match();
115
        $ctrl = $router->getController();
116
117
        $this->assertEquals("App\Index2", get_class($ctrl));
118
    }
119
120
    /**
121
     * Tests if the router can create an instance of a class with non-default class name builder
122
     *
123
     * @return null
124
     */
125
    public function testSimpleRouteMatchWithParticularName()
126
    {
127
        $router = new Router();
128
129
        $router->addRoute([
130
            'App3' => [
131
                'module'     => 'App',
132
                'controller' => 'Index',
133
                'view'       => 'about'
134
            ],
135
        ]);
136
137
        $router->setIdentifiers('App', 'Index', 'about');
138
139
        $router->setClassNameBuilder(function($module, $class) {
140
            return "\\$module\Controller\\$class";
141
        });
142
143
        $router->match();
144
145
        $ctrl = $router->getController();
146
147
        $this->assertEquals("App\Controller\Index", get_class($ctrl));
148
    }
149
150
    /**
151
     * Tests method execution behaviour handled by the a module
152
     *
153
     * @return null
154
     */
155
    public function testModuleAndControllerComposition()
156
    {
157
        $router = new Router();
158
159
        $router->addRoute([
160
            'App4' => [
161
                'module'     => 'App',
162
                'controller' => 'Index',
163
                'view'       => 'about'
164
            ],
165
        ]);
166
167
        $router->setIdentifiers('App', 'Index', 'about');
168
169
        $router->setClassNameBuilder(function($module, $class) {
170
            return "\\$module\Controller\\$class";
171
        });
172
173
        $router->match();
174
175
        # inject the module dependency to the controller
176
        $router->getController()->setModule(ModuleFactory::create("App"));
0 ignored issues
show
Bug introduced by
Are you sure the usage of Drone\Mvc\ModuleFactory::create('App') targeting Drone\Mvc\ModuleFactory::create() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Drone\Mvc\ModuleFactory::create('App') of type null is incompatible with the type Drone\Mvc\AbstractModule expected by parameter $module of Drone\Mvc\AbstractController::setModule(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

176
        $router->getController()->setModule(/** @scrutinizer ignore-type */ ModuleFactory::create("App"));
Loading history...
177
178
        $this->assertNotTrue($router->getController()->getModule()->executionIsAllowed());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $router->getController()...)->executionIsAllowed() targeting Drone\Mvc\AbstractModule::executionIsAllowed() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
179
180
        $errorObject = null;
181
182
        try {
183
            $router->run();
184
        }
185
        catch (\Exception $e)
186
        {
187
            $errorObject = ($e instanceof MethodExecutionNotAllowedException);
188
        }
189
        finally
190
        {
191
            $this->assertTrue($errorObject, $e->getMessage());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $e does not seem to be defined for all execution paths leading up to this point.
Loading history...
192
        }
193
194
        $router->getController()->getModule()->allowExecution();
195
196
        # returns the result of the method execution in the matched controller
197
        $result = $router->run();
198
199
        $expected = ["foo" => "bar"];
200
        $this->assertSame($expected, $result);
201
    }
202
}
203
204
/*
205
|--------------------------------------------------------------------------
206
| Controller classes
207
|--------------------------------------------------------------------------
208
|
209
| This are simple controllers implementing AbstractController.
210
|
211
*/
212
213
namespace App;
214
215
use Drone\Mvc\AbstractController;
216
217
class Index extends AbstractController
218
{
219
    public function home()
220
    {
221
        return [];
222
    }
223
}
224
225
class Index2 extends AbstractController
226
{
227
    public function home()
228
    {
229
        return [];
230
    }
231
}
232
233
/*
234
|--------------------------------------------------------------------------
235
| Another Controller class
236
|--------------------------------------------------------------------------
237
|
238
| This is a simple controller implementing AbstractController. In order to
239
| build a framework behavior, we need all classes inside Controller namespace.
240
|
241
*/
242
243
namespace App\Controller;
244
245
use Drone\Mvc\AbstractController;
246
247
class Index extends AbstractController
248
{
249
    public function about()
250
    {
251
        return ['foo' => 'bar'];
252
    }
253
}
254
255
/*
256
|--------------------------------------------------------------------------
257
| Module Class
258
|--------------------------------------------------------------------------
259
|
260
| Each module could have a Module class that handles method execution. It's
261
| useful for execute some code before method execution or for stop it.
262
|
263
*/
264
265
namespace App;
266
267
use Drone\Mvc\AbstractController;
268
use Drone\Mvc\AbstractModule;
269
270
class Module extends AbstractModule
271
{
272
    public function init()
273
    {
274
        # disallowing method execution
275
        $this->disallowExecution();
276
    }
277
}