[BUGFIX] Reallow '0' as valid userFunc argument in TypoScript 28/46428/3
authorFrank Naegler <frank.naegler@typo3.org>
Mon, 1 Feb 2016 13:32:06 +0000 (14:32 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Mon, 1 Feb 2016 14:24:43 +0000 (15:24 +0100)
With #47301 the parsing of userFunc in TypoScript has changed.
The change prevents '0' as valid argument.

This patch fix the '0' bug but also adds some new unit tests.
The parser method also includes a bug with quoted values which are not the
last argument. this bug is now fixed too.

Resolves: #72936
Related: #47301
Releases: master, 7.6, 6.2
Change-Id: Ic8df6ea21642e012438dba0a6a299c15939ab119
Reviewed-on: https://review.typo3.org/46428
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Configuration/TypoScript/ConditionMatching/AbstractConditionMatcher.php
typo3/sysext/core/Tests/Unit/Configuration/ConditionMatcherUserFuncs.php
typo3/sysext/core/Tests/Unit/Configuration/TypoScript/ConditionMatching/AbstractConditionMatcherTest.php

index 61da41a..ae8590a 100644 (file)
@@ -407,7 +407,7 @@ abstract class AbstractConditionMatcher {
                                $matches = array();
                                preg_match_all('/^\s*([^\(\s]+)\s*(?:\((.*)\))?\s*$/', $value, $matches);
                                $funcName = $matches[1][0];
-                               $funcValues = $matches[2][0] ? $this->parseUserFuncArguments($matches[2][0]) : array();
+                               $funcValues = trim($matches[2][0]) !== '' ? $this->parseUserFuncArguments($matches[2][0]) : array();
                                if (is_callable($funcName) && call_user_func_array($funcName, $funcValues)) {
                                        return TRUE;
                                }
@@ -437,11 +437,13 @@ abstract class AbstractConditionMatcher {
                                        $segment = preg_replace('/^(.*?[^\\\])' . $quote . '.*$/', '\1', substr($arguments, 1));
                                        $segment = str_replace('\\' . $quote, $quote, $segment);
                                        $result[] = $segment;
-                                       $offset = strpos($arguments, ',', strlen($segment) + 2);
+                                       // shorten $arguments
+                                       $arguments = substr($arguments, strlen($segment) + 2);
+                                       $offset = strpos($arguments, ',');
                                        if ($offset === FALSE) {
                                                $offset = strlen($arguments);
                                        }
-                                       $arguments = substr($arguments, $offset);
+                                       $arguments = substr($arguments, $offset + 1);
                                } else {
                                        $result[] = trim(substr($arguments, 0, $pos));
                                        $arguments = substr($arguments, $pos + 1);
index 716cf75..3c209a8 100644 (file)
  */
 
 namespace {
+       function user_testFunctionWithNoArgument()
+       {
+               return count(func_get_args()) === 0;
+       }
+
        function user_testFunctionWithSingleArgument() {
                return count(func_get_args()) === 1;
        }
@@ -61,5 +66,3 @@ namespace {
 
        }
 }
-
-?>
index 704e251..b2c6c52 100644 (file)
@@ -14,16 +14,21 @@ namespace TYPO3\CMS\Core\Tests\Unit\Configuration\TypoScript\ConditionMatching;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher;
 use TYPO3\CMS\Core\Core\ApplicationContext;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
+require_once(ExtensionManagementUtility::extPath('core', 'Tests/Unit/Configuration/ConditionMatcherUserFuncs.php'));
+
 /**
  * Testcases for
  * TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher
  *
  * @author Steffen Müller <typo3@t3node.com>
  */
-class AbstractConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+class AbstractConditionMatcherTest extends UnitTestCase {
 
        /**
         * @var \TYPO3\CMS\Core\Core\ApplicationContext
@@ -31,10 +36,23 @@ class AbstractConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        protected $backupApplicationContext = NULL;
 
        /**
+        * @var AbstractConditionMatcher|\PHPUnit_Framework_MockObject_MockObject
+        */
+       protected $conditionMatcher;
+
+       /**
+        * @var \ReflectionMethod
+        */
+       protected $evaluateConditionCommonMethod;
+
+       /**
         *
         */
        public function setUp() {
                $this->backupApplicationContext = GeneralUtility::getApplicationContext();
+               $this->conditionMatcher = $this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Configuration\\TypoScript\\ConditionMatching\\AbstractConditionMatcher');
+               $this->evaluateConditionCommonMethod = new \ReflectionMethod('TYPO3\\CMS\\Core\\Configuration\\TypoScript\\ConditionMatching\\AbstractConditionMatcher', 'evaluateConditionCommon');
+               $this->evaluateConditionCommonMethod->setAccessible(true);
        }
 
        /**
@@ -221,4 +239,232 @@ class AbstractConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $actualResult = $method->invokeArgs($abstractConditionMatcherMock, array('IP', 'devIP'));
                $this->assertSame($expectedResult, $actualResult);
        }
-}
\ No newline at end of file
+
+       /**
+        * @test
+        */
+       public function testUserFuncIsCalled() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunction')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithSingleArgument() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithSingleArgument(x)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithIntegerZeroArgument() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithSingleArgument(0)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithWhitespaceArgument() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithNoArgument( )')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleArguments() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments(1,2,3)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsNullBoolString() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments(0,true,"foo")')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsNullStringBool() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments(0,"foo",true)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsStringBoolNull() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments("foo",true,0)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsStringNullBool() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments("foo",0,true)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsBoolNullString() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments(true,0,"foo")')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsBoolStringNull() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments(true,"foo",0)')
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsNullBoolStringSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments(0,true,'foo')")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsNullStringBoolSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments(0,'foo',true)")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsStringBoolNullSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments('foo',true,0)")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsStringNullBoolSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments('foo',0,true)")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsBoolNullStringSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments(true,0,'foo')")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleDifferentArgumentsBoolStringNullSingleQuotes() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments(true,'foo',0)")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleSingleQuotedArguments() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', "user_testFunctionWithThreeArguments('foo','bar', 'baz')")
+                       )
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function testUserFuncWithMultipleSoubleQuotedArguments() {
+               $this->assertTrue(
+                       $this->evaluateConditionCommonMethod->invokeArgs(
+                               $this->conditionMatcher,
+                               array('userFunc', 'user_testFunctionWithThreeArguments("foo","bar","baz")')
+                       )
+               );
+       }
+}