lithium\test\Unit::assertTags()
Takes an array $expected and generates a regex from it to match the provided $string. Samples for $expected:
Checks for an input tag with a name attribute (contains any non-empty value) and an id attribute that contains 'my-input':
['input' => ['name', 'id' => 'my-input']]
Checks for two p elements with some text in them:
[
['p' => true],
'textA',
'/p',
['p' => true],
'textB',
'/p'
]
You can also specify a pattern expression as part of the attribute values, or the tag being defined, if you prepend the value with preg: and enclose it with slashes, like so:
[
['input' => ['name', 'id' => 'preg:/FieldName\d+/']],
'preg:/My\s+field/'
]
Important: This function is very forgiving about whitespace and also accepts any permutation of attribute order. It will also allow whitespaces between specified tags.
Parameters
-
string
$string
An HTML/XHTML/XML string
-
array
$expected
An array, see above
Returns
booleantrue
if the assertion succeeded, false
otherwise.
Source
public function assertTags($string, $expected) {
$regex = [];
$normalized = [];
foreach ((array) $expected as $key => $val) {
if (!is_numeric($key)) {
$normalized[] = [$key => $val];
} else {
$normalized[] = $val;
}
}
$i = 0;
foreach ($normalized as $tags) {
$i++;
if (is_string($tags) && $tags[0] === '<') {
$tags = [substr($tags, 1) => []];
} elseif (is_string($tags)) {
$tagsTrimmed = preg_replace('/\s+/m', '', $tags);
if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
$prefix = [null, null];
if ($match[0] === '*/') {
$prefix = ['Anything, ', '.*?'];
}
$regex[] = [
sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr(
$tags, strlen($match[0])
)),
$i
];
continue;
}
if (!empty($tags) && preg_match('/^regex\:\/(.+)\/$/i', $tags, $matches)) {
$tags = $matches[1];
$type = 'Regex matches';
} else {
$tags = preg_quote($tags, '/');
$type = 'Text equals';
}
$regex[] = [sprintf('%s "%s"', $type, $tags), $tags, $i];
continue;
}
foreach ($tags as $tag => $attributes) {
$regex[] = [
sprintf('Open %s tag', $tag),
sprintf('[\s]*<%s', preg_quote($tag, '/')),
$i
];
if ($attributes === true) {
$attributes = [];
}
$attrs = [];
$explanations = [];
foreach ($attributes as $attr => $val) {
if (is_numeric($attr) && preg_match('/^regex\:\/(.+)\/$/i', $val, $matches)) {
$attrs[] = $matches[1];
$explanations[] = sprintf('Regex "%s" matches', $matches[1]);
continue;
} else {
$quotes = '"';
if (is_numeric($attr)) {
$attr = $val;
$val = '.+?';
$explanations[] = sprintf('Attribute "%s" present', $attr);
} elseif (
!empty($val) && preg_match('/^regex\:\/(.+)\/$/i', $val, $matches)
) {
$quotes = '"?';
$val = $matches[1];
$explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
} else {
$explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
$val = preg_quote($val, '/');
}
$attrs[] = '[\s]+' . preg_quote($attr, '/') . "={$quotes}{$val}{$quotes}";
}
}
if ($attrs) {
$permutations = $this->_arrayPermute($attrs);
$permutationTokens = [];
foreach ($permutations as $permutation) {
$permutationTokens[] = join('', $permutation);
}
$regex[] = [
sprintf('%s', join(', ', $explanations)),
$permutationTokens,
$i
];
}
$regex[] = [sprintf('End %s tag', $tag), '[\s]*\/?[\s]*>[\n\r]*', $i];
}
}
foreach ($regex as $i => $assertation) {
list($description, $expressions, $itemNum) = $assertation;
$matches = false;
foreach ((array) $expressions as $expression) {
if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
$matches = true;
$string = substr($string, strlen($match[0]));
break;
}
}
if (!$matches) {
$this->assert(false, sprintf(
'- Item #%d / regex #%d failed: %s', $itemNum, $i, $description
));
return false;
}
}
return $this->assert(true);
}