J. King
3 years ago
8 changed files with 180 additions and 32 deletions
@ -0,0 +1,135 @@ |
|||||
|
<?php |
||||
|
/** @license MIT |
||||
|
* Copyright 2017 , Dustin Wilson, J. King et al. |
||||
|
* See LICENSE and AUTHORS files for details */ |
||||
|
|
||||
|
declare(strict_types=1); |
||||
|
namespace MensBeam\HTML\TestCase; |
||||
|
|
||||
|
use MensBeam\HTML\Document; |
||||
|
use MensBeam\HTML\Parser; |
||||
|
|
||||
|
/** |
||||
|
* @covers \MensBeam\HTML\Document |
||||
|
* @covers \MensBeam\HTML\DocumentFragment |
||||
|
* @covers \MensBeam\HTML\Element |
||||
|
* @covers \MensBeam\HTML\TemplateElement |
||||
|
* @covers \MensBeam\HTML\Comment |
||||
|
* @covers \MensBeam\HTML\Text |
||||
|
*/ |
||||
|
class TestTreeConstructor extends \PHPUnit\Framework\TestCase { |
||||
|
use \MensBeam\HTML\EscapeString; |
||||
|
|
||||
|
protected $out; |
||||
|
protected $depth; |
||||
|
|
||||
|
/** @dataProvider provideStandardSerializerTests */ |
||||
|
public function testStandardTreeTests(array $data, bool $fragment, string $exp): void { |
||||
|
$node = $this->buildTree($data, $fragment); |
||||
|
$this->assertSame($exp, (string) $node); |
||||
|
} |
||||
|
|
||||
|
public function provideStandardSerializerTests(): iterable { |
||||
|
$blacklist = []; |
||||
|
$files = new \AppendIterator(); |
||||
|
$files->append(new \GlobIterator(\MensBeam\HTML\BASE."tests/cases/serializer/*.dat", \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)); |
||||
|
foreach ($files as $file) { |
||||
|
$index = 0; |
||||
|
$l = 0; |
||||
|
if (!in_array(basename($file), $blacklist)) { |
||||
|
$lines = array_map(function($v) { |
||||
|
return rtrim($v, "\n"); |
||||
|
}, file($file)); |
||||
|
while ($l < sizeof($lines)) { |
||||
|
$pos = $l + 1; |
||||
|
assert(in_array($lines[$l], ["#document", "#fragment"]), new \Exception("Test $file #$index does not start with #doocument or #fragment tag at line ".($l + 1))); |
||||
|
$fragment = $lines[$l] === "#fragment"; |
||||
|
// collect the test input |
||||
|
$data = []; |
||||
|
for (++$l; $l < sizeof($lines); $l++) { |
||||
|
if (preg_match('/^#(script-(on|off)|output)$/', $lines[$l])) { |
||||
|
break; |
||||
|
} |
||||
|
$data[] = $lines[$l]; |
||||
|
} |
||||
|
// set the script mode, if present |
||||
|
assert(preg_match('/^#(script-(on|off)|output)$/', $lines[$l]) === 1, new \Exception("Test $file #$index follows data with something other than script flag or output at line ".($l + 1))); |
||||
|
$script = null; |
||||
|
if ($lines[$l] === "#script-off") { |
||||
|
$script = false; |
||||
|
$l++; |
||||
|
} elseif ($lines[$l] === "#script-on") { |
||||
|
$script = true; |
||||
|
$l++; |
||||
|
} |
||||
|
// collect the output string |
||||
|
$exp = []; |
||||
|
assert($lines[$l] === "#output", new \Exception("Test $file #$index follows input with something other than output at line ".($l + 1))); |
||||
|
for (++$l; $l < sizeof($lines); $l++) { |
||||
|
if ($lines[$l] === "" && in_array(($lines[$l + 1] ?? ""), ["#ddocument", "#fragment"])) { |
||||
|
break; |
||||
|
} |
||||
|
assert(preg_match('/^[^#]/', $lines[$l]) === 1, new \Exception("Test $file #$index contains unrecognized data after document at line ".($l + 1))); |
||||
|
$exp[] = $lines[$l]; |
||||
|
} |
||||
|
$exp = implode("\n", $exp); |
||||
|
if (!$script) { |
||||
|
yield basename($file)." #$index (line $pos)" => [$data, $fragment, $exp]; |
||||
|
} |
||||
|
$l++; |
||||
|
$index++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected function buildTree(array $data, bool $fragment): \DOMNode { |
||||
|
$document = new Document; |
||||
|
$out = $fragment ? $document->createDocumentFragment() : $document; |
||||
|
$cur = $out; |
||||
|
$pad = 2; |
||||
|
// process each line in turn |
||||
|
for ($l = 0; $l < sizeof($data); $l++) { |
||||
|
preg_match('/^(\|\s+)(.+)/', $data[$l], $m); |
||||
|
// pop any parents as long as the padding of the line is less than the expected padding |
||||
|
$p = strlen((string) $m[1]); |
||||
|
assert($p >= 2 && $p <= $pad && !($p % 2), new \Exception("Input data is invalid on line ".($l + 1))); |
||||
|
while ($p < $pad) { |
||||
|
$pad -= 2; |
||||
|
$cur = $cur->parentNode; |
||||
|
} |
||||
|
// act based upon what the rest of the line looks like |
||||
|
$d = $m[2]; |
||||
|
if (preg_match('/^<!-- (.*?) -->$/', $d, $m)) { |
||||
|
// comment |
||||
|
$cur->appendChild($document->createComment($m[1])); |
||||
|
} elseif (preg_match('/^<!DOCTYPE ([^ >]*)(?: "([^"]*)" "([^"]*)")?>$/', $d, $m)) { |
||||
|
// doctype |
||||
|
$name = strlen((string) $m[1]) ? $m[1] : null; |
||||
|
$public = strlen((string) $m[2]) ? $m[2] : null; |
||||
|
$system = strlen((string) $m[3]) ? $m[3] : null; |
||||
|
$cur->appendChild($document->implementation->createDocumentType($name, $public, $system)); |
||||
|
} elseif (preg_match('/^<(?:([^ ]+) )?([^>]+)>$/', $d, $m)) { |
||||
|
// element |
||||
|
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? null) : null; |
||||
|
$cur = $cur->appendChild($document->createElementNS($ns, $m[2])); |
||||
|
$pad += 2; |
||||
|
} elseif (preg_match('/^(?:([^" ]+) )?([^"=]+)="((?:[^"]|"(?!$))*)"$/', $d, $m)) { |
||||
|
// attribute |
||||
|
$ns = strlen((string) $m[1]) ? (array_flip(Parser::NAMESPACE_MAP)[$m[1]] ?? $m[1]) : ""; |
||||
|
$cur->setAttributeNS($ns, $m[2], $m[3]); |
||||
|
} elseif (preg_match('/^"((?:[^"]|"(?!$))*)("?)$/', $d, $m)) { |
||||
|
// text |
||||
|
$t = $m[1]; |
||||
|
while (!strlen((string) $m[2])) { |
||||
|
preg_match('/^((?:[^"]|"(?!$))*)("?)$/', $data[++$l], $m); |
||||
|
$t .= "\n".$m[1]; |
||||
|
} |
||||
|
$cur->appendChild($document->createTextNode($t)); |
||||
|
} else { |
||||
|
throw new \Exception("Input data is invalid on line ".($l + 1)); |
||||
|
} |
||||
|
} |
||||
|
return $out; |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue