Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15366898
D17819.id42863.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D17819.id42863.diff
View Options
diff --git a/src/parser/xhpast/__tests__/PHPASTParserTestCase.php b/src/parser/xhpast/__tests__/PHPASTParserTestCase.php
--- a/src/parser/xhpast/__tests__/PHPASTParserTestCase.php
+++ b/src/parser/xhpast/__tests__/PHPASTParserTestCase.php
@@ -80,7 +80,6 @@
switch ($type) {
case 'pass':
- case 'fail-parse':
$this->assertEqual(0, $err, pht('Exit code for "%s".', $name));
if (!strlen($expect)) {
@@ -89,16 +88,6 @@
}
try {
- $expect = phutil_json_decode($expect);
- } catch (PhutilJSONParserException $ex) {
- throw new PhutilProxyException(
- pht(
- 'Expect data for test "%s" is not valid JSON.',
- $name),
- $ex);
- }
-
- try {
$stdout = phutil_json_decode($stdout);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
@@ -108,21 +97,12 @@
$ex);
}
- $json = new PhutilJSON();
-
- $expect_nice = $json->encodeFormatted($expect);
- $stdout_nice = $json->encodeFormatted($stdout);
+ $stdout_nice = $this->newReadableAST($stdout, $data);
- if ($type == 'pass') {
- $this->assertEqual(
- $expect_nice,
- $stdout_nice,
- pht('Parser output for "%s".', $name));
- } else {
- $this->assertFalse(
- ($expect_nice == $stdout_nice),
- pht('Expected parser to parse "%s" incorrectly.', $name));
- }
+ $this->assertEqual(
+ $expect,
+ $stdout_nice,
+ pht('Parser output for "%s".', $name));
break;
case 'fail-syntax':
$this->assertEqual(1, $err, pht('Exit code for "%s".', $name));
@@ -130,7 +110,141 @@
(bool)preg_match('/syntax error/', $stderr),
pht('Expect "syntax error" in stderr or "%s".', $name));
break;
+ default:
+ throw new Exception(
+ pht(
+ 'Unknown PHPAST parser test type "%s"!',
+ $type));
+ }
+ }
+
+ /**
+ * Build a human-readable, stable, relatively diff-able string representing
+ * an AST (both the node tree itself and the accompanying token stream) for
+ * use in unit tests.
+ */
+ private function newReadableAST(array $data, $source) {
+ $tree = new XHPASTTree($data['tree'], $data['stream'], $source);
+
+ $out = array();
+ $out[] = $this->newReadableTree($tree);
+ $out[] = $this->newReadableDivider();
+ $out[] = $this->newReadableStream($tree);
+ $out = implode('', $out);
+
+ return $out;
+ }
+
+ private function newReadableTree(XHPASTTree $tree) {
+ $root = $tree->getRootNode();
+
+ $depth = 0;
+ $list = $this->newReadableTreeLines($root, $depth);
+
+ return implode('', $list);
+ }
+
+ private function newReadableDivider() {
+ return str_repeat('-', 80)."\n";
+ }
+
+ private function newReadableStream(XHPASTTree $tree) {
+ $tokens = $tree->getRawTokenStream();
+
+ // Identify the longest token name this stream uses so we can format the
+ // output into two columns.
+ $max_len = 0;
+ foreach ($tokens as $token) {
+ $max_len = max($max_len, strlen($token->getTypeName()));
+ }
+
+ $out = array();
+
+ $tokens = $tree->getRawTokenStream();
+ foreach ($tokens as $token) {
+ $value = $token->getValue();
+ $vector = $this->getEscapedValueVector($value);
+
+ $vector = array_merge(
+ array(
+ str_pad($token->getTypeName(), $max_len),
+ ' ',
+ ),
+ $vector);
+
+ $out[] = $this->wrapVector($vector);
+ }
+
+ $out = implode('', $out);
+
+ return $out;
+ }
+
+ private function newReadableTreeLines(AASTNode $node, $depth) {
+ $out = array();
+
+ try {
+ $type_name = $node->getTypeName();
+ } catch (Exception $ex) {
+ $type_name = sprintf('<INVALID TYPE "%s">', $node->getTypeID());
+ }
+
+ $out[] = str_repeat(' ', $depth).'+ '.$type_name."\n";
+
+ $children = $node->getChildren();
+ if ($children) {
+ foreach ($children as $child) {
+ foreach ($this->newReadableTreeLines($child, $depth + 1) as $line) {
+ $out[] = $line;
+ }
+ }
+ } else {
+ $value = $node->getConcreteString();
+ $vector = $this->getEscapedValueVector($value);
+ $out[] = $this->wrapVector($vector, $depth + 1);
+ }
+
+ return $out;
+ }
+
+ private function getEscapedValueVector($value) {
+ if (!$value) {
+ return array('<null>');
}
+
+ $vector = phutil_utf8v_combined($value);
+ foreach ($vector as $key => $character) {
+ $vector[$key] = addcslashes($character, "\r\n\t\"\\");
+ }
+
+ return $vector;
+ }
+
+ private function wrapVector(array $vector, $indent = 0, $width = 80) {
+ $lines = array();
+ $prefix = str_repeat(' ', $indent);
+
+ $line = $prefix.'> "';
+ $len = strlen($line);
+ foreach ($vector as $character) {
+ // We're just wrapping based on bytes. This isn't the most correct
+ // wrapping for human language, but sufficient and stable for unit
+ // tests, which will rarely have long sequences of combining or
+ // multibyte characters.
+ $charlen = strlen($character);
+ if ($len + $charlen > ($width - 1)) {
+ $lines[] = $line."\"\n";
+ $line = $prefix.'. "';
+ $len = strlen($line);
+ }
+
+ $line .= $character;
+ $len += $charlen;
+ }
+
+ $lines[] = $line."\"\n";
+
+ return implode('', $lines);
}
}
diff --git a/src/parser/xhpast/__tests__/data/a-self-test.php.test b/src/parser/xhpast/__tests__/data/a-self-test.php.test
new file mode 100644
--- /dev/null
+++ b/src/parser/xhpast/__tests__/data/a-self-test.php.test
@@ -0,0 +1,60 @@
+<?php
+
+$the_senate = <<<EOTRAGEDY
+Did you ever hear the tragedy of Darth Plagueis The Wise? I
+thought not. It’s not a story the Jedi would tell you. It’s a Sith legend.
+Darth Plagueis was a Dark Lord of the Sith, so powerful and so wise he could
+use the Force to influence the midichlorians to create life... He had such a
+knowledge of the dark side that he could even keep the ones he cared about from
+dying. The dark side of the Force is a pathway to many abilities some consider
+to be unnatural. He became so powerful... the only thing he was afraid of was
+losing his power, which eventually, of course, he did. Unfortunately, he taught
+his apprentice everything he knew, then his apprentice killed him in his sleep.
+Ironic. He could save others from death, but not himself.
+EOTRAGEDY;
+
+~~~~~~~~~~
+pass
+~~~~~~~~~~
++ n_PROGRAM
+ + n_STATEMENT_LIST
+ + n_OPEN_TAG
+ > "<?php"
+ + n_STATEMENT
+ + n_BINARY_EXPRESSION
+ + n_VARIABLE
+ > "$the_senate"
+ + n_OPERATOR
+ > "="
+ + n_HEREDOC
+ > "<<<EOTRAGEDY\nDid you ever hear the tragedy of Darth Plagueis The Wise?"
+ . " I\nthought not. It’s not a story the Jedi would tell you. It’s a S"
+ . "ith legend.\nDarth Plagueis was a Dark Lord of the Sith, so powerful an"
+ . "d so wise he could\nuse the Force to influence the midichlorians to cre"
+ . "ate life... He had such a\nknowledge of the dark side that he could eve"
+ . "n keep the ones he cared about from\ndying. The dark side of the Force "
+ . "is a pathway to many abilities some consider\nto be unnatural. He becam"
+ . "e so powerful... the only thing he was afraid of was\nlosing his power,"
+ . " which eventually, of course, he did. Unfortunately, he taught\nhis app"
+ . "rentice everything he knew, then his apprentice killed him in his sleep"
+ . ".\nIronic. He could save others from death, but not himself.\nEOTRAGEDY"
+--------------------------------------------------------------------------------
+> "T_OPEN_TAG <?php"
+> "T_WHITESPACE \n\n"
+> "T_VARIABLE $the_senate"
+> "T_WHITESPACE "
+> "= ="
+> "T_WHITESPACE "
+> "T_HEREDOC <<<EOTRAGEDY\nDid you ever hear the tragedy of Darth Plagueis T"
+. "he Wise? I\nthought not. It’s not a story the Jedi would tell you. It’s "
+. "a Sith legend.\nDarth Plagueis was a Dark Lord of the Sith, so powerful and "
+. "so wise he could\nuse the Force to influence the midichlorians to create lif"
+. "e... He had such a\nknowledge of the dark side that he could even keep the o"
+. "nes he cared about from\ndying. The dark side of the Force is a pathway to m"
+. "any abilities some consider\nto be unnatural. He became so powerful... the o"
+. "nly thing he was afraid of was\nlosing his power, which eventually, of cours"
+. "e, he did. Unfortunately, he taught\nhis apprentice everything he knew, then"
+. " his apprentice killed him in his sleep.\nIronic. He could save others from "
+. "death, but not himself.\nEOTRAGEDY"
+> "; ;"
+> "T_WHITESPACE \n\n"
diff --git a/src/parser/xhpast/__tests__/data/base-fail-parse.php.test b/src/parser/xhpast/__tests__/data/base-fail-parse.php.test
deleted file mode 100644
--- a/src/parser/xhpast/__tests__/data/base-fail-parse.php.test
+++ /dev/null
@@ -1,8 +0,0 @@
-<?php
-~~~~~~~~~~
-fail-parse
-~~~~~~~~~~
-{
- "tree": [],
- "stream": []
-}
diff --git a/src/parser/xhpast/__tests__/data/php-heredoc-terminal.php.test b/src/parser/xhpast/__tests__/data/php-heredoc-terminal.php.test
deleted file mode 100644
--- a/src/parser/xhpast/__tests__/data/php-heredoc-terminal.php.test
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-<<<HEREDOC
-HEREDOC;
-~~~~~~~~~~
-fail-parse, rtrim
-~~~~~~~~~~
-{
- "tree": [
- 9000,
- 0,
- 2,
- [
- [
- 9006,
- 0,
- 2,
- [
- [
- 9007,
- 0,
- 0
- ],
- [
- 9004,
- 1,
- 2,
- [
- [
- 9098,
- 1,
- 1
- ]
- ]
- ]
- ]
- ]
- ]
- ],
- "stream": [
- [
- 371,
- 6
- ],
- [
- 378,
- 18
- ],
- [
- 59,
- 1
- ]
- ]
-}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 12, 3:34 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7589063
Default Alt Text
D17819.id42863.diff (9 KB)
Attached To
Mode
D17819: Make PHPAST parser tests stable and human-readable
Attached
Detach File
Event Timeline
Log In to Comment