Completed
Push — master ( fdd9ad...2548bf )
by Sam
11:48
created

DirectorTest::testAlternativeBaseURL()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 58
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 41
nc 1
nop 0
dl 0
loc 58
rs 9.639
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Control\Tests;
4
5
use SilverStripe\Control\Cookie_Backend;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Control\HTTPResponse;
8
use SilverStripe\Control\HTTPResponse_Exception;
9
use SilverStripe\Control\Tests\DirectorTest\TestController;
10
use SilverStripe\Core\Config\Config;
11
use SilverStripe\Core\Injector\Injector;
12
use SilverStripe\Dev\SapphireTest;
13
use SilverStripe\Control\Director;
14
use SilverStripe\Control\RequestProcessor;
15
use SilverStripe\Security\Security;
16
17
/**
18
 * @todo test Director::alternateBaseFolder()
19
 */
20
class DirectorTest extends SapphireTest
21
{
22
23
    protected static $originalRequestURI;
24
25
    protected $originalProtocolHeaders = array();
26
27
    protected $originalGet = array();
28
29
    protected $originalSession = array();
30
31
    protected static $extra_controllers = [
32
        TestController::class,
33
    ];
34
35
    protected function setUp()
0 ignored issues
show
Coding Style introduced by
setUp uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
setUp uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
setUp uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
36
    {
37
        parent::setUp();
38
39
        // Hold the original request URI once so it doesn't get overwritten
40
        if (!self::$originalRequestURI) {
41
            self::$originalRequestURI = $_SERVER['REQUEST_URI'];
42
        }
43
        $_SERVER['REQUEST_URI'] = 'http://www.mysite.com';
44
45
        $this->originalGet = $_GET;
46
        $this->originalSession = $_SESSION;
47
        $_SESSION = array();
48
49
        $headers = array(
50
            'HTTP_X_FORWARDED_PROTOCOL', 'HTTPS', 'SSL'
51
        );
52
53
        foreach ($headers as $header) {
54
            if (isset($_SERVER[$header])) {
55
                $this->originalProtocolHeaders[$header] = $_SERVER[$header];
56
            }
57
        }
58
59
        Config::modify()->set(Director::class, 'alternate_base_url', '/');
60
    }
61
62
    protected function getExtraRoutes()
63
    {
64
        $rules = parent::getExtraRoutes();
65
66
        $rules['DirectorTestRule/$Action/$ID/$OtherID'] = TestController::class;
67
        $rules['en-nz/$Action/$ID/$OtherID'] = [
68
            'Controller' => TestController::class,
69
            'Locale' => 'en_NZ',
70
        ];
71
        return $rules;
72
    }
73
74
    protected function setUpRoutes()
75
    {
76
        // Don't merge with any existing rules
77
        Director::config()->set('rules', $this->getExtraRoutes());
78
    }
79
80
    protected function tearDown()
0 ignored issues
show
Coding Style introduced by
tearDown uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
tearDown uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
tearDown uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
81
    {
82
        $_GET = $this->originalGet;
83
        $_SESSION = $this->originalSession;
84
85
        // Reinstate the original REQUEST_URI after it was modified by some tests
86
        $_SERVER['REQUEST_URI'] = self::$originalRequestURI;
87
88
        if ($this->originalProtocolHeaders) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->originalProtocolHeaders of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
89
            foreach ($this->originalProtocolHeaders as $header => $value) {
90
                $_SERVER[$header] = $value;
91
            }
92
        }
93
94
95
        parent::tearDown();
96
    }
97
98
    public function testFileExists()
99
    {
100
        $tempFileName = 'DirectorTest_testFileExists.tmp';
101
        $tempFilePath = TEMP_FOLDER . '/' . $tempFileName;
102
103
        // create temp file
104
        file_put_contents($tempFilePath, '');
105
106
        $this->assertTrue(
107
            Director::fileExists($tempFilePath),
108
            'File exist check with absolute path'
109
        );
110
111
        $this->assertTrue(
112
            Director::fileExists($tempFilePath . '?queryparams=1&foo[bar]=bar'),
113
            'File exist check with query params ignored'
114
        );
115
116
        unlink($tempFilePath);
117
    }
118
119
    public function testAbsoluteURL()
0 ignored issues
show
Coding Style introduced by
testAbsoluteURL uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
120
    {
121
122
        $rootURL = Director::protocolAndHost();
123
        $_SERVER['REQUEST_URI'] = "$rootURL/mysite/sub-page/";
124
        Director::config()->set('alternate_base_url', '/mysite/');
125
126
        //test empty / local urls
127
        foreach (array('', './', '.') as $url) {
128
            $this->assertEquals("$rootURL/mysite/", Director::absoluteURL($url, Director::BASE));
129
            $this->assertEquals("$rootURL/", Director::absoluteURL($url, Director::ROOT));
130
            $this->assertEquals("$rootURL/mysite/sub-page/", Director::absoluteURL($url, Director::REQUEST));
131
        }
132
133
        // Test site root url
134
        $this->assertEquals("$rootURL/", Director::absoluteURL('/'));
135
136
        // Test Director::BASE
137
        $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::BASE));
0 ignored issues
show
Bug introduced by
It seems like $rootURL defined by \SilverStripe\Control\Director::protocolAndHost() on line 122 can also be of type boolean; however, SilverStripe\Control\Director::absoluteURL() does only seem to accept 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...
138
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::BASE));
139
        $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::BASE));
140
        $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::BASE));
141
        $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::BASE));
142
143
        // Test Director::ROOT
144
        $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::ROOT));
0 ignored issues
show
Bug introduced by
It seems like $rootURL defined by \SilverStripe\Control\Director::protocolAndHost() on line 122 can also be of type boolean; however, SilverStripe\Control\Director::absoluteURL() does only seem to accept 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...
145
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::ROOT));
146
        $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::ROOT));
147
        $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::ROOT));
148
        $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::ROOT));
149
150
        // Test Director::REQUEST
151
        $this->assertEquals($rootURL, Director::absoluteURL($rootURL, Director::REQUEST));
0 ignored issues
show
Bug introduced by
It seems like $rootURL defined by \SilverStripe\Control\Director::protocolAndHost() on line 122 can also be of type boolean; however, SilverStripe\Control\Director::absoluteURL() does only seem to accept 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...
152
        $this->assertEquals('http://www.mytest.com', Director::absoluteURL('http://www.mytest.com', Director::REQUEST));
153
        $this->assertEquals("$rootURL/test", Director::absoluteURL("$rootURL/test", Director::REQUEST));
154
        $this->assertEquals("$rootURL/root", Director::absoluteURL("/root", Director::REQUEST));
155
        $this->assertEquals("$rootURL/root/url", Director::absoluteURL("/root/url", Director::REQUEST));
156
157
        // Test evaluating relative urls relative to base (default)
158
        $this->assertEquals("$rootURL/mysite/test", Director::absoluteURL("test"));
159
        $this->assertEquals("$rootURL/mysite/test/url", Director::absoluteURL("test/url"));
160
        $this->assertEquals("$rootURL/mysite/test", Director::absoluteURL("test", Director::BASE));
161
        $this->assertEquals("$rootURL/mysite/test/url", Director::absoluteURL("test/url", Director::BASE));
162
163
        // Test evaluting relative urls relative to root
164
        $this->assertEquals("$rootURL/test", Director::absoluteURL("test", Director::ROOT));
165
        $this->assertEquals("$rootURL/test/url", Director::absoluteURL("test/url", Director::ROOT));
166
167
        // Test relative to requested page
168
        $this->assertEquals("$rootURL/mysite/sub-page/test", Director::absoluteURL("test", Director::REQUEST));
169
        $this->assertEquals("$rootURL/mysite/sub-page/test/url", Director::absoluteURL("test/url", Director::REQUEST));
170
171
        // Test that javascript links are not left intact
172
        $this->assertStringStartsNotWith('javascript', Director::absoluteURL('javascript:alert("attack")'));
173
        $this->assertStringStartsNotWith('alert', Director::absoluteURL('javascript:alert("attack")'));
174
        $this->assertStringStartsNotWith('javascript', Director::absoluteURL('alert("attack")'));
175
        $this->assertStringStartsNotWith('alert', Director::absoluteURL('alert("attack")'));
176
    }
177
178
    public function testAlternativeBaseURL()
0 ignored issues
show
Coding Style introduced by
testAlternativeBaseURL uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
179
    {
180
        // Get original protocol and hostname
181
        $rootURL = Director::protocolAndHost();
182
183
        // relative base URLs - you should end them in a /
184
        Director::config()->set('alternate_base_url', '/relativebase/');
185
        $_SERVER['REQUEST_URI'] = "$rootURL/relativebase/sub-page/";
186
187
        $this->assertEquals('/relativebase/', Director::baseURL());
188
        $this->assertEquals($rootURL . '/relativebase/', Director::absoluteBaseURL());
189
        $this->assertEquals(
190
            $rootURL . '/relativebase/subfolder/test',
191
            Director::absoluteURL('subfolder/test')
192
        );
193
194
        // absolute base URLS with subdirectory - You should end them in a /
195
        Director::config()->set('alternate_base_url', 'http://www.example.org/relativebase/');
196
        $_SERVER['REQUEST_URI'] = "http://www.example.org/relativebase/sub-page/";
197
        $this->assertEquals('/relativebase/', Director::baseURL()); // Non-absolute url
198
        $this->assertEquals('http://www.example.org/relativebase/', Director::absoluteBaseURL());
199
        $this->assertEquals('http://www.example.org/relativebase/sub-page/', Director::absoluteURL('', Director::REQUEST));
200
        $this->assertEquals('http://www.example.org/relativebase/', Director::absoluteURL('', Director::BASE));
201
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
202
        $this->assertEquals(
203
            'http://www.example.org/relativebase/sub-page/subfolder/test',
204
            Director::absoluteURL('subfolder/test', Director::REQUEST)
205
        );
206
        $this->assertEquals(
207
            'http://www.example.org/subfolder/test',
208
            Director::absoluteURL('subfolder/test', Director::ROOT)
209
        );
210
        $this->assertEquals(
211
            'http://www.example.org/relativebase/subfolder/test',
212
            Director::absoluteURL('subfolder/test', Director::BASE)
213
        );
214
215
        // absolute base URLs - you should end them in a /
216
        Director::config()->set('alternate_base_url', 'http://www.example.org/');
217
        $_SERVER['REQUEST_URI'] = "http://www.example.org/sub-page/";
218
        $this->assertEquals('/', Director::baseURL()); // Non-absolute url
219
        $this->assertEquals('http://www.example.org/', Director::absoluteBaseURL());
220
        $this->assertEquals('http://www.example.org/sub-page/', Director::absoluteURL('', Director::REQUEST));
221
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::BASE));
222
        $this->assertEquals('http://www.example.org/', Director::absoluteURL('', Director::ROOT));
223
        $this->assertEquals(
224
            'http://www.example.org/sub-page/subfolder/test',
225
            Director::absoluteURL('subfolder/test', Director::REQUEST)
226
        );
227
        $this->assertEquals(
228
            'http://www.example.org/subfolder/test',
229
            Director::absoluteURL('subfolder/test', Director::ROOT)
230
        );
231
        $this->assertEquals(
232
            'http://www.example.org/subfolder/test',
233
            Director::absoluteURL('subfolder/test', Director::BASE)
234
        );
235
    }
236
237
    /**
238
     * Tests that {@link Director::is_absolute()} works under different environment types
239
     */
240
    public function testIsAbsolute()
241
    {
242
        $expected = array (
243
            'C:/something' => true,
244
            'd:\\'         => true,
245
            'e/'           => false,
246
            's:/directory' => true,
247
            '/var/www'     => true,
248
            '\\Something'  => true,
249
            'something/c:' => false,
250
            'folder'       => false,
251
            'a/c:/'        => false
252
        );
253
254
        foreach ($expected as $path => $result) {
255
            $this->assertEquals(Director::is_absolute($path), $result, "Test result for $path");
256
        }
257
    }
258
259
    public function testIsAbsoluteUrl()
260
    {
261
        $this->assertTrue(Director::is_absolute_url('http://test.com/testpage'));
262
        $this->assertTrue(Director::is_absolute_url('ftp://test.com'));
263
        $this->assertFalse(Director::is_absolute_url('test.com/testpage'));
264
        $this->assertFalse(Director::is_absolute_url('/relative'));
265
        $this->assertFalse(Director::is_absolute_url('relative'));
266
        $this->assertFalse(Director::is_absolute_url("/relative/?url=http://foo.com"));
267
        $this->assertFalse(Director::is_absolute_url("/relative/#http://foo.com"));
268
        $this->assertTrue(Director::is_absolute_url("https://test.com/?url=http://foo.com"));
269
        $this->assertTrue(Director::is_absolute_url("trickparseurl:http://test.com"));
270
        $this->assertTrue(Director::is_absolute_url('//test.com'));
271
        $this->assertTrue(Director::is_absolute_url('/////test.com'));
272
        $this->assertTrue(Director::is_absolute_url('  ///test.com'));
273
        $this->assertTrue(Director::is_absolute_url('http:test.com'));
274
        $this->assertTrue(Director::is_absolute_url('//http://test.com'));
275
    }
276
277
    public function testIsRelativeUrl()
278
    {
279
        $this->assertFalse(Director::is_relative_url('http://test.com'));
280
        $this->assertFalse(Director::is_relative_url('https://test.com'));
281
        $this->assertFalse(Director::is_relative_url('   https://test.com/testpage   '));
282
        $this->assertTrue(Director::is_relative_url('test.com/testpage'));
283
        $this->assertFalse(Director::is_relative_url('ftp://test.com'));
284
        $this->assertTrue(Director::is_relative_url('/relative'));
285
        $this->assertTrue(Director::is_relative_url('relative'));
286
        $this->assertTrue(Director::is_relative_url('/relative/?url=http://test.com'));
287
        $this->assertTrue(Director::is_relative_url('/relative/#=http://test.com'));
288
    }
289
290
    public function testMakeRelative()
291
    {
292
        $siteUrl = Director::absoluteBaseURL();
293
        $siteUrlNoProtocol = preg_replace('/https?:\/\//', '', $siteUrl);
294
295
        $this->assertEquals(Director::makeRelative("$siteUrl"), '');
296
        $this->assertEquals(Director::makeRelative("https://$siteUrlNoProtocol"), '');
297
        $this->assertEquals(Director::makeRelative("http://$siteUrlNoProtocol"), '');
298
299
        $this->assertEquals(Director::makeRelative("   $siteUrl/testpage   "), 'testpage');
300
        $this->assertEquals(Director::makeRelative("$siteUrlNoProtocol/testpage"), 'testpage');
301
302
        $this->assertEquals(Director::makeRelative('ftp://test.com'), 'ftp://test.com');
303
        $this->assertEquals(Director::makeRelative('http://test.com'), 'http://test.com');
304
305
        $this->assertEquals(Director::makeRelative('relative'), 'relative');
306
        $this->assertEquals(Director::makeRelative("$siteUrl/?url=http://test.com"), '?url=http://test.com');
307
308
        $this->assertEquals("test", Director::makeRelative("https://".$siteUrlNoProtocol."/test"));
309
        $this->assertEquals("test", Director::makeRelative("http://".$siteUrlNoProtocol."/test"));
310
    }
311
312
    /**
313
     * Mostly tested by {@link testIsRelativeUrl()},
314
     * just adding the host name matching aspect here.
315
     */
316
    public function testIsSiteUrl()
317
    {
318
        $this->assertFalse(Director::is_site_url("http://test.com"));
319
        $this->assertTrue(Director::is_site_url(Director::absoluteBaseURL()));
0 ignored issues
show
Security Bug introduced by
It seems like \SilverStripe\Control\Director::absoluteBaseURL() targeting SilverStripe\Control\Director::absoluteBaseURL() can also be of type false; however, SilverStripe\Control\Director::is_site_url() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
320
        $this->assertFalse(Director::is_site_url("http://test.com?url=" . Director::absoluteBaseURL()));
321
        $this->assertFalse(Director::is_site_url("http://test.com?url=" . urlencode(Director::absoluteBaseURL())));
322
        $this->assertFalse(Director::is_site_url("//test.com?url=" . Director::absoluteBaseURL()));
323
    }
324
325
    /**
326
     * Tests isDev, isTest, isLive set from querystring
327
     */
328
    public function testQueryIsEnvironment()
0 ignored issues
show
Coding Style introduced by
testQueryIsEnvironment uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
testQueryIsEnvironment uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
329
    {
330
        if (!isset($_SESSION)) {
331
            $_SESSION = [];
332
        }
333
        // Reset
334
        unset($_SESSION['isDev']);
335
        unset($_SESSION['isLive']);
336
        unset($_GET['isTest']);
337
        unset($_GET['isDev']);
338
339
        // Test isDev=1
340
        $_GET['isDev'] = '1';
341
        $this->assertTrue(Director::isDev());
342
        $this->assertFalse(Director::isTest());
343
        $this->assertFalse(Director::isLive());
344
345
        // Test persistence
346
        unset($_GET['isDev']);
347
        $this->assertTrue(Director::isDev());
348
        $this->assertFalse(Director::isTest());
349
        $this->assertFalse(Director::isLive());
350
351
        // Test change to isTest
352
        $_GET['isTest'] = '1';
353
        $this->assertFalse(Director::isDev());
354
        $this->assertTrue(Director::isTest());
355
        $this->assertFalse(Director::isLive());
356
357
        // Test persistence
358
        unset($_GET['isTest']);
359
        $this->assertFalse(Director::isDev());
360
        $this->assertTrue(Director::isTest());
361
        $this->assertFalse(Director::isLive());
362
    }
363
364
    public function testResetGlobalsAfterTestRequest()
0 ignored issues
show
Coding Style introduced by
testResetGlobalsAfterTestRequest uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
testResetGlobalsAfterTestRequest uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
testResetGlobalsAfterTestRequest uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
365
    {
366
        $_GET = array('somekey' => 'getvalue');
367
        $_POST = array('somekey' => 'postvalue');
368
        $_COOKIE = array('somekey' => 'cookievalue');
369
370
        $cookies = Injector::inst()->createWithArgs(
371
            Cookie_Backend::class,
372
            array(array('somekey' => 'sometestcookievalue'))
373
        );
374
375
        Director::test(
376
            'errorpage?somekey=sometestgetvalue',
377
            array('somekey' => 'sometestpostvalue'),
378
            null,
379
            null,
380
            null,
381
            null,
382
            $cookies
383
        );
384
385
        $this->assertEquals(
386
            'getvalue',
387
            $_GET['somekey'],
388
            '$_GET reset to original value after Director::test()'
389
        );
390
        $this->assertEquals(
391
            'postvalue',
392
            $_POST['somekey'],
393
            '$_POST reset to original value after Director::test()'
394
        );
395
        $this->assertEquals(
396
            'cookievalue',
397
            $_COOKIE['somekey'],
398
            '$_COOKIE reset to original value after Director::test()'
399
        );
400
    }
401
402
    public function testTestRequestCarriesGlobals()
403
    {
404
        $fixture = array('somekey' => 'sometestvalue');
405
        foreach (array('get', 'post') as $method) {
406
            foreach (array('return%sValue', 'returnRequestValue', 'returnCookieValue') as $testfunction) {
407
                $url = 'TestController/' . sprintf($testfunction, ucfirst($method))
408
                    . '?' . http_build_query($fixture);
409
410
                $getresponse = Director::test(
411
                    $url,
412
                    $fixture,
413
                    null,
414
                    strtoupper($method),
415
                    null,
416
                    null,
417
                    Injector::inst()->createWithArgs(Cookie_Backend::class, array($fixture))
418
                );
419
420
                $this->assertInstanceOf(HTTPResponse::class, $getresponse, 'Director::test() returns HTTPResponse');
421
                $this->assertEquals($fixture['somekey'], $getresponse->getBody(), 'Director::test() ' . $testfunction);
422
            }
423
        }
424
    }
425
426
    /**
427
     * Tests that additional parameters specified in the routing table are
428
     * saved in the request
429
     */
430
    public function testRouteParams()
431
    {
432
        /** @var HTTPRequest $request */
433
        Director::test('en-nz/myaction/myid/myotherid', null, null, null, null, null, null, $request);
434
435
        $this->assertEquals(
436
            array(
437
                'Controller' => TestController::class,
438
                'Action' => 'myaction',
439
                'ID' => 'myid',
440
                'OtherID' => 'myotherid',
441
                'Locale' => 'en_NZ'
442
            ),
443
            $request->params()
444
        );
445
    }
446
447
    public function testForceSSLProtectsEntireSite()
0 ignored issues
show
Coding Style introduced by
testForceSSLProtectsEntireSite uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
448
    {
449
        $_SERVER['REQUEST_URI'] = '/admin';
450
        $output = Director::forceSSL();
451
        $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
452
453
        $_SERVER['REQUEST_URI'] = Director::baseURL() . 'some-url';
454
        $output = Director::forceSSL();
455
        $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
456
    }
457
458
    public function testForceSSLOnTopLevelPagePattern()
0 ignored issues
show
Coding Style introduced by
testForceSSLOnTopLevelPagePattern uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
459
    {
460
        $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
461
        $output = Director::forceSSL(array('/^admin/'));
462
        $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
463
    }
464
465
    public function testForceSSLOnSubPagesPattern()
0 ignored issues
show
Coding Style introduced by
testForceSSLOnSubPagesPattern uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
466
    {
467
        $_SERVER['REQUEST_URI'] = Director::baseURL() . Config::inst()->get(Security::class, 'login_url');
468
        $output = Director::forceSSL(array('/^Security/'));
469
        $this->assertEquals($output, 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
470
    }
471
472
    public function testForceSSLWithPatternDoesNotMatchOtherPages()
0 ignored issues
show
Coding Style introduced by
testForceSSLWithPatternDoesNotMatchOtherPages uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
473
    {
474
        $_SERVER['REQUEST_URI'] = Director::baseURL() . 'normal-page';
475
        $output = Director::forceSSL(array('/^admin/'));
476
        $this->assertFalse($output);
477
478
        $_SERVER['REQUEST_URI'] = Director::baseURL() . 'just-another-page/sub-url';
479
        $output = Director::forceSSL(array('/^admin/', '/^Security/'));
480
        $this->assertFalse($output);
481
    }
482
483
    public function testForceSSLAlternateDomain()
0 ignored issues
show
Coding Style introduced by
testForceSSLAlternateDomain uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
484
    {
485
        Director::config()->set('alternate_base_url', '/');
486
        $_SERVER['REQUEST_URI'] = Director::baseURL() . 'admin';
487
        $output = Director::forceSSL(array('/^admin/'), 'secure.mysite.com');
488
        $this->assertEquals($output, 'https://secure.mysite.com/admin');
489
    }
490
491
    /**
492
     * @covers \SilverStripe\Control\Director::extract_request_headers()
493
     */
494
    public function testExtractRequestHeaders()
495
    {
496
        $request = array(
497
            'REDIRECT_STATUS'      => '200',
498
            'HTTP_HOST'            => 'host',
499
            'HTTP_USER_AGENT'      => 'User Agent',
500
            'HTTP_ACCEPT'          => 'text/html',
501
            'HTTP_ACCEPT_LANGUAGE' => 'en-us',
502
            'HTTP_COOKIE'          => 'MyCookie=1',
503
            'SERVER_PROTOCOL'      => 'HTTP/1.1',
504
            'REQUEST_METHOD'       => 'GET',
505
            'REQUEST_URI'          => '/',
506
            'SCRIPT_NAME'          => FRAMEWORK_DIR . '/main.php',
507
            'CONTENT_TYPE'         => 'text/xml',
508
            'CONTENT_LENGTH'       => 10
509
        );
510
511
        $headers = array(
512
            'Host'            => 'host',
513
            'User-Agent'      => 'User Agent',
514
            'Accept'          => 'text/html',
515
            'Accept-Language' => 'en-us',
516
            'Cookie'          => 'MyCookie=1',
517
            'Content-Type'    => 'text/xml',
518
            'Content-Length'  => '10'
519
        );
520
521
        $this->assertEquals($headers, Director::extract_request_headers($request));
522
    }
523
524
    public function testUnmatchedRequestReturns404()
525
    {
526
        // Remove non-tested rules
527
        $this->assertEquals(404, Director::test('no-route')->getStatusCode());
528
    }
529
530
    public function testIsHttps()
0 ignored issues
show
Coding Style introduced by
testIsHttps uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
531
    {
532
        if (!TRUSTED_PROXY) {
533
            $this->markTestSkipped('Test cannot be run without trusted proxy');
534
        }
535
        // nothing available
536
        $headers = array(
537
            'HTTP_X_FORWARDED_PROTOCOL', 'HTTPS', 'SSL'
538
        );
539
540
        $origServer = $_SERVER;
541
542
        foreach ($headers as $header) {
543
            if (isset($_SERVER[$header])) {
544
                unset($_SERVER['HTTP_X_FORWARDED_PROTOCOL']);
545
            }
546
        }
547
548
        $this->assertFalse(Director::is_https());
549
550
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'https';
551
        $this->assertTrue(Director::is_https());
552
553
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'http';
554
        $this->assertFalse(Director::is_https());
555
556
        $_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'ftp';
557
        $this->assertFalse(Director::is_https());
558
559
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
560
        $this->assertTrue(Director::is_https());
561
562
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
563
        $this->assertFalse(Director::is_https());
564
565
        $_SERVER['HTTP_X_FORWARDED_PROTO'] = 'ftp';
566
        $this->assertFalse(Director::is_https());
567
568
        $_SERVER['HTTP_FRONT_END_HTTPS'] = 'On';
569
        $this->assertTrue(Director::is_https());
570
571
        $_SERVER['HTTP_FRONT_END_HTTPS'] = 'Off';
572
        $this->assertFalse(Director::is_https());
573
574
        // https via HTTPS
575
        $_SERVER['HTTPS'] = 'true';
576
        $this->assertTrue(Director::is_https());
577
578
        $_SERVER['HTTPS'] = '1';
579
        $this->assertTrue(Director::is_https());
580
581
        $_SERVER['HTTPS'] = 'off';
582
        $this->assertFalse(Director::is_https());
583
584
        // https via SSL
585
        $_SERVER['SSL'] = '';
586
        $this->assertTrue(Director::is_https());
587
588
        $_SERVER = $origServer;
589
    }
590
591
    public function testTestIgnoresHashes()
592
    {
593
        //test that hashes are ignored
594
        $url = "TestController/returnGetValue?somekey=key";
595
        $hash = "#test";
596
        /** @var HTTPRequest $request */
597
        $response = Director::test($url . $hash, null, null, null, null, null, null, $request);
598
        $this->assertFalse($response->isError());
599
        $this->assertEquals('key', $response->getBody());
600
        $this->assertEquals($request->getURL(true), $url);
601
602
        //test encoded hashes are accepted
603
        $url = "TestController/returnGetValue?somekey=test%23key";
604
        $response = Director::test($url, null, null, null, null, null, null, $request);
605
        $this->assertFalse($response->isError());
606
        $this->assertEquals('test#key', $response->getBody());
607
        $this->assertEquals($request->getURL(true), $url);
608
    }
609
610
    public function testRequestFilterInDirectorTest()
611
    {
612
        $filter = new DirectorTest\TestRequestFilter;
613
614
        $processor = new RequestProcessor(array($filter));
615
616
        Injector::inst()->registerService($processor, RequestProcessor::class);
617
618
        Director::test('some-dummy-url');
619
620
        $this->assertEquals(1, $filter->preCalls);
621
        $this->assertEquals(1, $filter->postCalls);
622
623
        $filter->failPost = true;
624
625
        $this->setExpectedException(HTTPResponse_Exception::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
626
627
        Director::test('some-dummy-url');
628
629
        $this->assertEquals(2, $filter->preCalls);
630
        $this->assertEquals(2, $filter->postCalls);
631
632
        $filter->failPre = true;
633
634
        Director::test('some-dummy-url');
635
636
        $this->assertEquals(3, $filter->preCalls);
637
638
        // preCall 'false' will trigger an exception and prevent post call execution
639
        $this->assertEquals(2, $filter->postCalls);
640
    }
641
}
642