[BUGFIX] Incorrect cHash generation may cause 404 on any page
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Unit / Page / CacheHashCalculatorTest.php
index 6e05af2..de90406 100644 (file)
 <?php
 namespace TYPO3\CMS\Frontend\Tests\Unit\Page;
 
-/***************************************************************
- *  Copyright notice
+/*
+ * This file is part of the TYPO3 CMS project.
  *
- *  (c) 2012-2013 Tolleiv Nietsch <typo3@tolleiv.de>
- *  All rights reserved
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
  *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
  *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
+ * The TYPO3 project - inspiring people to share!
+ */
 
 /**
  * Testcase
- *
- * @author 2012 Tolleiv Nietsch <typo3@tolleiv.de>
  */
-class CacheHashCalculatorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
-
-       /**
-        * @var \TYPO3\CMS\Frontend\Page\CacheHashCalculator
-        */
-       protected $fixture;
-
-       /**
-        * @var array
-        */
-       protected $confCache = array();
-
-       public function setUp() {
-               $this->confCache = array(
-                       'encryptionKey' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
-               );
-               $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 't3lib_cacheHashTest';
-               $this->fixture = $this->getMock('TYPO3\\CMS\\Frontend\\Page\\CacheHashCalculator', array('foo'));
-               $this->fixture->setConfiguration(array(
-                       'excludedParameters' => array('exclude1', 'exclude2'),
-                       'cachedParametersWhiteList' => array(),
-                       'requireCacheHashPresenceParameters' => array('req1', 'req2'),
-                       'excludedParametersIfEmpty' => array(),
-                       'excludeAllEmptyParameters' => FALSE
-               ));
-       }
-
-       public function tearDown() {
-               $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = $this->confCache['encryptionKey'];
-       }
-
-       /**
-        * @dataProvider cacheHashCalculationDataprovider
-        * @test
-        */
-       public function cacheHashCalculationWorks($params, $expected) {
-               $this->assertEquals($expected, $this->fixture->calculateCacheHash($params));
-       }
-
-       /**
-        * @return array
-        */
-       public function cacheHashCalculationDataprovider() {
-               return array(
-                       'Empty parameters should not return a hash' => array(
-                               array(),
-                               ''
-                       ),
-                       'Trivial key value combination should generate hash' => array(
-                               array(
-                                       'encryptionKey' => 't3lib_cacheHashTest',
-                                       'key' => 'value'
-                               ),
-                               '5cfdcf826275558b3613dd51714a0a17'
-                       ),
-                       'Multiple parameters should generate hash' => array(
-                               array(
-                                       'a' => 'v',
-                                       'b' => 'v',
-                                       'encryptionKey' => 't3lib_cacheHashTest'
-                               ),
-                               '0f40b089cdad149aea99e9bf4badaa93'
-                       )
-               );
-       }
-
-       /**
-        * @dataProvider getRelevantParametersDataprovider
-        * @test
-        */
-       public function getRelevantParametersWorks($params, $expected) {
-               $actual = $this->fixture->getRelevantParameters($params);
-               $this->assertEquals($expected, array_keys($actual));
-       }
-
-       /**
-        * @return array
-        */
-       public function getRelevantParametersDataprovider() {
-               return array(
-                       'Empty list should be passed through' => array('', array()),
-                       'Simple parameter should be passed through and the encryptionKey should be added' => array(
-                               'key=v',
-                               array('encryptionKey', 'key')
-                       ),
-                       'Simple parameter should be passed through' => array(
-                               'key1=v&key2=v',
-                               array('encryptionKey', 'key1', 'key2')
-                       ),
-                       'System and exclude paramters should be omitted' => array(
-                               'id=1&type=3&exclude1=x&no_cache=1',
-                               array()
-                       ),
-                       'System and exclude paramters should be omitted' => array(
-                               'id=1&type=3&key=x&no_cache=1',
-                               array('encryptionKey', 'key')
-                       )
-               );
-       }
-
-       /**
-        * @dataProvider canGenerateForParametersDataprovider
-        * @test
-        */
-       public function canGenerateForParameters($params, $expected) {
-               $this->assertEquals($expected, $this->fixture->generateForParameters($params));
-       }
-
-       /**
-        * @return array
-        */
-       public function canGenerateForParametersDataprovider() {
-               $knowHash = '5cfdcf826275558b3613dd51714a0a17';
-               return array(
-                       'Empty parameters should not return an hash' => array('', ''),
-                       'Querystring has no relevant parameters so we should not have a cacheHash' => array('&exclude1=val', ''),
-                       'Querystring has only system parameters so we should not have a cacheHash' => array('id=1&type=val', ''),
-                       'Trivial key value combination should generate hash' => array('&key=value', $knowHash),
-                       'Only the relevant parts should be taken into account' => array('&key=value&exclude1=val', $knowHash),
-                       'Only the relevant parts should be taken into account' => array('&exclude2=val&key=value', $knowHash),
-                       'System parameters should not be taken into account' => array('&id=1&key=value', $knowHash),
-                       'Admin panel parameters should not be taken into account' => array('&TSFE_ADMIN_PANEL[display]=7&key=value', $knowHash),
-                       'Trivial hash for sorted parameters should be right' => array('a=v&b=v', '0f40b089cdad149aea99e9bf4badaa93'),
-                       'Parameters should be sorted before  is created' => array('b=v&a=v', '0f40b089cdad149aea99e9bf4badaa93')
-               );
-       }
-
-       /**
-        * @dataProvider parametersRequireCacheHashDataprovider
-        * @test
-        */
-       public function parametersRequireCacheHashWorks($params, $expected) {
-               $this->assertEquals($expected, $this->fixture->doParametersRequireCacheHash($params));
-       }
-
-       /**
-        * @return array
-        */
-       public function parametersRequireCacheHashDataprovider() {
-               return array(
-                       'Empty parameter strings should not require anything.' => array('', FALSE),
-                       'Normal parameters aren\'t required.' => array('key=value', FALSE),
-                       'Configured "req1" to be required.' => array('req1=value', TRUE),
-                       'Configured "req1" to be requiredm, should also work in combined context' => array('&key=value&req1=value', TRUE),
-                       'Configured "req1" to be requiredm, should also work in combined context' => array('req1=value&key=value', TRUE)
-               );
-       }
-
-       /**
-        * In case the cHashOnlyForParameters is set, other parameters should not
-        * incluence the cHash (except the encryption key of course)
-        *
-        * @dataProvider canWhitelistParametersDataprovider
-        * @test
-        */
-       public function canWhitelistParameters($params, $expected) {
-               $method = new \ReflectionMethod('TYPO3\\CMS\\Frontend\\Page\\CacheHashCalculator', 'setCachedParametersWhiteList');
-               $method->setAccessible(TRUE);
-               $method->invoke($this->fixture, array('whitep1', 'whitep2'));
-               $this->assertEquals($expected, $this->fixture->generateForParameters($params));
-       }
-
-       /**
-        * @return array
-        */
-       public function canWhitelistParametersDataprovider() {
-               $oneParamHash = 'e2c0f2edf08be18bcff2f4272e11f66b';
-               $twoParamHash = 'f6f08c2e10a97d91b6ec61a6e2ddd0e7';
-               return array(
-                       'Even with the whitelist enabled, empty parameters should not return an hash.' => array('', ''),
-                       'Whitelisted parameters should have a hash.' => array('whitep1=value', $oneParamHash),
-                       'Blacklisted parameter should not influence hash.' => array('whitep1=value&black=value', $oneParamHash),
-                       'Multiple whitelisted parameters should work' => array('&whitep1=value&whitep2=value', $twoParamHash),
-                       'The order should not influce the hash.' => array('whitep2=value&black=value&whitep1=value', $twoParamHash)
-               );
-       }
-
-       /**
-        * @dataProvider canSkipParametersWithEmptyValuesDataprovider
-        * @test
-        */
-       public function canSkipParametersWithEmptyValues($params, $settings, $expected) {
-               $this->fixture->setConfiguration($settings);
-               $actual = $this->fixture->getRelevantParameters($params);
-               $this->assertEquals($expected, array_keys($actual));
-       }
-
-       /**
-        * @return array
-        */
-       public function canSkipParametersWithEmptyValuesDataprovider() {
-               return array(
-                       'The default configuration does not allow to skip an empty key.' => array(
-                               'key1=v&key2=&key3=',
-                               array('excludedParametersIfEmpty' => array(), 'excludeAllEmptyParameters' => FALSE),
-                               array('encryptionKey', 'key1', 'key2', 'key3')
-                       ),
-                       'Due to the empty value, "key2" should be skipped' => array(
-                               'key1=v&key2=&key3=',
-                               array('excludedParametersIfEmpty' => array('key2'), 'excludeAllEmptyParameters' => FALSE),
-                               array('encryptionKey', 'key1', 'key3')
-                       ),
-                       'Due to the empty value, "key2" should be skipped' => array(
-                               'key1=v&key2&key3',
-                               array('excludedParametersIfEmpty' => array('key2'), 'excludeAllEmptyParameters' => FALSE),
-                               array('encryptionKey', 'key1', 'key3')
-                       ),
-                       'Due to the empty value, "key2" and "key3" should be skipped' => array(
-                               'key1=v&key2=&key3=',
-                               array('excludedParametersIfEmpty' => array(), 'excludeAllEmptyParameters' => TRUE),
-                               array('encryptionKey', 'key1')
-                       )
-               );
-       }
-
+class CacheHashCalculatorTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
+{
+    /**
+     * @var \TYPO3\CMS\Frontend\Page\CacheHashCalculator
+     */
+    protected $subject;
+
+    protected function setUp()
+    {
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 't3lib_cacheHashTest';
+        $this->subject = $this->getMockBuilder(\TYPO3\CMS\Frontend\Page\CacheHashCalculator::class)
+            ->setMethods(['foo'])
+            ->getMock();
+        $this->subject->setConfiguration([
+            'excludedParameters' => ['exclude1', 'exclude2'],
+            'cachedParametersWhiteList' => [],
+            'requireCacheHashPresenceParameters' => ['req1', 'req2'],
+            'excludedParametersIfEmpty' => [],
+            'includePageId' => true,
+            'excludeAllEmptyParameters' => false
+        ]);
+    }
+
+    /**
+     * @dataProvider cacheHashCalculationDataProvider
+     * @test
+     */
+    public function cacheHashCalculationWorks($params, $expected)
+    {
+        $this->assertEquals($expected, $this->subject->calculateCacheHash($params));
+    }
+
+    /**
+     * @return array
+     */
+    public function cacheHashCalculationDataProvider()
+    {
+        return [
+            'Empty parameters should not return a hash' => [
+                [],
+                ''
+            ],
+            'Trivial key value combination should generate hash' => [
+                [
+                    'encryptionKey' => 't3lib_cacheHashTest',
+                    'key' => 'value'
+                ],
+                '5cfdcf826275558b3613dd51714a0a17'
+            ],
+            'Multiple parameters should generate hash' => [
+                [
+                    'a' => 'v',
+                    'b' => 'v',
+                    'encryptionKey' => 't3lib_cacheHashTest'
+                ],
+                '0f40b089cdad149aea99e9bf4badaa93'
+            ]
+        ];
+    }
+
+    /**
+     * @dataProvider getRelevantParametersDataprovider
+     * @test
+     */
+    public function getRelevantParametersWorks($params, $expected)
+    {
+        $actual = $this->subject->getRelevantParameters($params);
+        $this->assertEquals($expected, array_keys($actual));
+    }
+
+    /**
+     * @return array
+     */
+    public function getRelevantParametersDataprovider()
+    {
+        return [
+            'Empty list should be passed through' => ['', []],
+            'Simple parameter should be passed through and the encryptionKey should be added' => [
+                'key=v&id=42',
+                ['encryptionKey', 'id', 'key']
+            ],
+            'Simple parameter should be passed through' => [
+                'key1=v&key2=v&id=42',
+                ['encryptionKey', 'id', 'key1', 'key2']
+            ],
+            'System and exclude parameters should be omitted' => [
+                'id=1&type=3&exclude1=x&no_cache=1',
+                []
+            ],
+            'System and exclude parameters (except id) should be omitted, others should stay' => [
+                'id=1&type=3&key=x&no_cache=1',
+                ['encryptionKey', 'id', 'key']
+            ],
+            'System and exclude parameters should be omitted and id is not required to be specified' => [
+                '&type=3&no_cache=1',
+                []
+            ]
+        ];
+    }
+
+    /**
+     * @dataProvider canGenerateForParametersDataProvider
+     * @test
+     */
+    public function canGenerateForParameters($params, $expected)
+    {
+        $this->assertEquals($expected, $this->subject->generateForParameters($params));
+    }
+
+    /**
+     * @test
+     * @expectedException \RuntimeException
+     * @expectedExceptionCode 1467983513
+     */
+    public function generateForParametersThrowsExceptionWhenIdIsNotSpecified()
+    {
+        $this->subject->generateForParameters('&key=x');
+    }
+
+    /**
+     * @return array
+     */
+    public function canGenerateForParametersDataProvider()
+    {
+        $knowHash = 'fac112f7e662c83c19b57142c3a921f5';
+        return [
+            'Empty parameters should not return an hash' => ['&id=42', ''],
+            'Querystring has no relevant parameters so we should not have a cacheHash' => ['&exclude1=val', ''],
+            'Querystring has only system parameters so we should not have a cacheHash' => ['&id=42&type=val', ''],
+            'Trivial key value combination should generate hash' => ['&id=42&key=value', $knowHash],
+            'Only the relevant parts should be taken into account' => ['&id=42&key=value&exclude1=val', $knowHash],
+            'Only the relevant parts should be taken into account(exclude2 before key)' => ['&id=42&exclude2=val&key=value', $knowHash],
+            'System parameters should not be taken into account (except id)' => ['&id=42&type=23&key=value', $knowHash],
+            'Admin panel parameters should not be taken into account' => ['&id=42&TSFE_ADMIN_PANEL[display]=7&key=value', $knowHash],
+            'Trivial hash for sorted parameters should be right' => ['&id=42&a=v&b=v', '52c8a1299e20324f90377c43153c4987'],
+            'Parameters should be sorted before cHash is created' => ['&id=42&b=v&a=v', '52c8a1299e20324f90377c43153c4987'],
+            'Empty argument names are filtered out before cHash calculation' => ['&id=42&b=v&a=v&=dummy', '52c8a1299e20324f90377c43153c4987']
+        ];
+    }
+
+    /**
+     * @dataProvider parametersRequireCacheHashDataprovider
+     * @test
+     */
+    public function parametersRequireCacheHashWorks($params, $expected)
+    {
+        $this->assertEquals($expected, $this->subject->doParametersRequireCacheHash($params));
+    }
+
+    /**
+     * @return array
+     */
+    public function parametersRequireCacheHashDataprovider()
+    {
+        return [
+            'Empty parameter strings should not require anything.' => ['', false],
+            'Normal parameters aren\'t required.' => ['key=value', false],
+            'Configured "req1" to be required.' => ['req1=value', true],
+            'Configured "req1" to be required, should also work in combined context' => ['&key=value&req1=value', true],
+            'Configured "req1" to be required, should also work in combined context (key at the end)' => ['req1=value&key=value', true]
+        ];
+    }
+
+    /**
+     * In case the cHashOnlyForParameters is set, other parameters should not
+     * incluence the cHash (except the encryption key of course)
+     *
+     * @dataProvider canWhitelistParametersDataProvider
+     * @test
+     */
+    public function canWhitelistParameters($params, $expected)
+    {
+        $method = new \ReflectionMethod(\TYPO3\CMS\Frontend\Page\CacheHashCalculator::class, 'setCachedParametersWhiteList');
+        $method->setAccessible(true);
+        $method->invoke($this->subject, ['whitep1', 'whitep2']);
+        $this->assertEquals($expected, $this->subject->generateForParameters($params));
+    }
+
+    /**
+     * @return array
+     */
+    public function canWhitelistParametersDataProvider()
+    {
+        $oneParamHash = 'eae50a13101afd53a9d2c543230eb5bb';
+        $twoParamHash = '701e2d2f1becc9d1b71d327e5cb1c3ed';
+        return [
+            'Even with the whitelist enabled, empty parameters should not return an hash.' => ['', ''],
+            'Whitelisted parameters should have a hash.' => ['&id=42&whitep1=value', $oneParamHash],
+            'Blacklisted parameter should not influence hash.' => ['&id=42&whitep1=value&black=value', $oneParamHash],
+            'Multiple whitelisted parameters should work' => ['&id=42&whitep1=value&whitep2=value', $twoParamHash],
+            'The order should not influce the hash.' => ['&id=42&whitep2=value&black=value&whitep1=value', $twoParamHash]
+        ];
+    }
+
+    /**
+     * @dataProvider canSkipParametersWithEmptyValuesDataProvider
+     * @test
+     */
+    public function canSkipParametersWithEmptyValues($params, $settings, $expected)
+    {
+        $this->subject->setConfiguration($settings);
+        $actual = $this->subject->getRelevantParameters($params);
+        $this->assertEquals($expected, array_keys($actual));
+    }
+
+    /**
+     * @return array
+     */
+    public function canSkipParametersWithEmptyValuesDataProvider()
+    {
+        return [
+            'The default configuration does not allow to skip an empty key.' => [
+                '&id=42&key1=v&key2=&key3=',
+                ['excludedParametersIfEmpty' => [], 'excludeAllEmptyParameters' => false],
+                ['encryptionKey', 'id', 'key1', 'key2', 'key3']
+            ],
+            'Due to the empty value, "key2" should be skipped(with equals sign' => [
+                '&id=42&key1=v&key2=&key3=',
+                ['excludedParametersIfEmpty' => ['key2'], 'excludeAllEmptyParameters' => false],
+                ['encryptionKey', 'id', 'key1', 'key3']
+            ],
+            'Due to the empty value, "key2" should be skipped(without equals sign)' => [
+                '&id=42&key1=v&key2&key3',
+                ['excludedParametersIfEmpty' => ['key2'], 'excludeAllEmptyParameters' => false],
+                ['encryptionKey', 'id', 'key1', 'key3']
+            ],
+            'Due to the empty value, "key2" and "key3" should be skipped' => [
+                '&id=42&key1=v&key2=&key3=',
+                ['excludedParametersIfEmpty' => [], 'excludeAllEmptyParameters' => true],
+                ['encryptionKey', 'id', 'key1']
+            ]
+        ];
+    }
 }
-
-?>
\ No newline at end of file