mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Make assertTags() run much faster.
Generating the various permutations a priori is incredibly expensive with sets of attributes. Using nested loops that look for matches is more efficient. Add replacments for `.*` and `.+` in preg:/ prefixed attribute matchers so they do not greedily eat all content. This also requires that preg:/ based attribute matchers *must* be quoted. Fixes #3072
This commit is contained in:
parent
c1b2b560bb
commit
af68f61e7a
2 changed files with 77 additions and 41 deletions
|
@ -62,24 +62,31 @@ class CakeTestCaseTest extends CakeTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* testAssertGoodTags
|
||||
* testAssertTags
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAssertTagsQuotes() {
|
||||
public function testAssertTagsBasic() {
|
||||
$test = new AssertTagsTestCase('testAssertTagsQuotes');
|
||||
$result = $test->run();
|
||||
$this->assertEquals(0, $result->errorCount());
|
||||
$this->assertTrue($result->wasSuccessful());
|
||||
$this->assertEquals(0, $result->failureCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* test assertTags works with single and double quotes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAssertTagsQuoting() {
|
||||
$input = '<a href="/test.html" class="active">My link</a>';
|
||||
$pattern = array(
|
||||
'a' => array('href' => '/test.html', 'class' => 'active'),
|
||||
'My link',
|
||||
'/a'
|
||||
);
|
||||
$this->assertTrue($test->assertTags($input, $pattern), 'Double quoted attributes %s');
|
||||
$this->assertTags($input, $pattern);
|
||||
|
||||
$input = "<a href='/test.html' class='active'>My link</a>";
|
||||
$pattern = array(
|
||||
|
@ -87,7 +94,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
|||
'My link',
|
||||
'/a'
|
||||
);
|
||||
$this->assertTrue($test->assertTags($input, $pattern), 'Single quoted attributes %s');
|
||||
$this->assertTags($input, $pattern);
|
||||
|
||||
$input = "<a href='/test.html' class='active'>My link</a>";
|
||||
$pattern = array(
|
||||
|
@ -95,7 +102,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
|||
'My link',
|
||||
'/a'
|
||||
);
|
||||
$this->assertTrue($test->assertTags($input, $pattern), 'Single quoted attributes %s');
|
||||
$this->assertTags($input, $pattern);
|
||||
|
||||
$input = "<span><strong>Text</strong></span>";
|
||||
$pattern = array(
|
||||
|
@ -105,7 +112,7 @@ class CakeTestCaseTest extends CakeTestCase {
|
|||
'/strong',
|
||||
'/span'
|
||||
);
|
||||
$this->assertTrue($test->assertTags($input, $pattern), 'Tags with no attributes');
|
||||
$this->assertTags($input, $pattern);
|
||||
|
||||
$input = "<span class='active'><strong>Text</strong></span>";
|
||||
$pattern = array(
|
||||
|
@ -115,7 +122,34 @@ class CakeTestCaseTest extends CakeTestCase {
|
|||
'/strong',
|
||||
'/span'
|
||||
);
|
||||
$this->assertTrue($test->assertTags($input, $pattern), 'Test attribute presence');
|
||||
$this->assertTags($input, $pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that assertTags runs quickly.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testAssertTagsRuntimeComplexity() {
|
||||
$pattern = array(
|
||||
'div' => array(
|
||||
'attr1' => 'val1',
|
||||
'attr2' => 'val2',
|
||||
'attr3' => 'val3',
|
||||
'attr4' => 'val4',
|
||||
'attr5' => 'val5',
|
||||
'attr6' => 'val6',
|
||||
'attr7' => 'val7',
|
||||
'attr8' => 'val8',
|
||||
),
|
||||
'My div',
|
||||
'/div'
|
||||
);
|
||||
$input = '<div attr8="val8" attr6="val6" attr4="val4" attr2="val2"' .
|
||||
' attr1="val1" attr3="val3" attr5="val5" attr7="val7" />' .
|
||||
'My div' .
|
||||
'</div>';
|
||||
$this->assertTags($input, $pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -448,8 +448,12 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
|||
$val = '.+?';
|
||||
$explanations[] = sprintf('Attribute "%s" present', $attr);
|
||||
} elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
|
||||
$quotes = '["\']?';
|
||||
$val = $matches[1];
|
||||
$quotes = '["\']';
|
||||
$val = str_replace(
|
||||
array('.*', '.+'),
|
||||
array('.*?', '.+?'),
|
||||
$matches[1]
|
||||
);
|
||||
$explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
|
||||
} else {
|
||||
$explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
|
||||
|
@ -460,16 +464,9 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
|||
$i++;
|
||||
}
|
||||
if ($attrs) {
|
||||
$permutations = $this->_arrayPermute($attrs);
|
||||
|
||||
$permutationTokens = array();
|
||||
foreach ($permutations as $permutation) {
|
||||
$permutationTokens[] = implode('', $permutation);
|
||||
}
|
||||
$regex[] = array(
|
||||
sprintf('%s', implode(', ', $explanations)),
|
||||
$permutationTokens,
|
||||
$i,
|
||||
'explains' => $explanations,
|
||||
'attrs' => $attrs,
|
||||
);
|
||||
}
|
||||
$regex[] = array(
|
||||
|
@ -479,9 +476,14 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
|||
);
|
||||
}
|
||||
}
|
||||
foreach ($regex as $i => $assertation) {
|
||||
list($description, $expressions, $itemNum) = $assertation;
|
||||
foreach ($regex as $i => $assertion) {
|
||||
$matches = false;
|
||||
if (isset($assertion['attrs'])) {
|
||||
$string = $this->_assertAttributes($assertion, $string);
|
||||
continue;
|
||||
}
|
||||
|
||||
list($description, $expressions, $itemNum) = $assertion;
|
||||
foreach ((array)$expressions as $expression) {
|
||||
if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
|
||||
$matches = true;
|
||||
|
@ -504,31 +506,31 @@ abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generates all permutation of an array $items and returns them in a new array.
|
||||
* Check the attributes as part of an assertTags() check.
|
||||
*
|
||||
* @param array $items An array of items
|
||||
* @param array $perms
|
||||
* @return array
|
||||
* @param array $assertions Assertions to run.
|
||||
* @param string $string The HTML string to check.
|
||||
* @return void
|
||||
*/
|
||||
protected function _arrayPermute($items, $perms = array()) {
|
||||
static $permuted;
|
||||
if (empty($perms)) {
|
||||
$permuted = array();
|
||||
}
|
||||
|
||||
if (empty($items)) {
|
||||
$permuted[] = $perms;
|
||||
} else {
|
||||
$numItems = count($items) - 1;
|
||||
for ($i = $numItems; $i >= 0; --$i) {
|
||||
$newItems = $items;
|
||||
$newPerms = $perms;
|
||||
list($tmp) = array_splice($newItems, $i, 1);
|
||||
array_unshift($newPerms, $tmp);
|
||||
$this->_arrayPermute($newItems, $newPerms);
|
||||
protected function _assertAttributes($assertions, $string) {
|
||||
$asserts = $assertions['attrs'];
|
||||
$explains = $assertions['explains'];
|
||||
while (count($asserts) > 0) {
|
||||
$matches = false;
|
||||
foreach ($asserts as $j => $assert) {
|
||||
if (preg_match(sprintf('/^%s/s', $assert), $string, $match)) {
|
||||
$matches = true;
|
||||
$string = substr($string, strlen($match[0]));
|
||||
array_splice($asserts, $j, 1);
|
||||
array_splice($explains, $j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($matches === false) {
|
||||
$this->assertTrue(false, 'Attribute did not match. Was expecting ' . $explains[$j]);
|
||||
}
|
||||
return $permuted;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
|
|
Loading…
Reference in a new issue