NodeAbstractTest.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <?php
  2. namespace PhpParser;
  3. class DummyNode extends NodeAbstract {
  4. public $subNode1;
  5. public $subNode2;
  6. public function __construct($subNode1, $subNode2, $attributes) {
  7. parent::__construct($attributes);
  8. $this->subNode1 = $subNode1;
  9. $this->subNode2 = $subNode2;
  10. }
  11. public function getSubNodeNames() {
  12. return array('subNode1', 'subNode2');
  13. }
  14. // This method is only overwritten because the node is located in an unusual namespace
  15. public function getType() {
  16. return 'Dummy';
  17. }
  18. }
  19. class NodeAbstractTest extends \PHPUnit_Framework_TestCase
  20. {
  21. public function provideNodes() {
  22. $attributes = array(
  23. 'startLine' => 10,
  24. 'comments' => array(
  25. new Comment('// Comment' . "\n"),
  26. new Comment\Doc('/** doc comment */'),
  27. ),
  28. );
  29. $node = new DummyNode('value1', 'value2', $attributes);
  30. $node->notSubNode = 'value3';
  31. return array(
  32. array($attributes, $node),
  33. );
  34. }
  35. /**
  36. * @dataProvider provideNodes
  37. */
  38. public function testConstruct(array $attributes, Node $node) {
  39. $this->assertSame('Dummy', $node->getType());
  40. $this->assertSame(array('subNode1', 'subNode2'), $node->getSubNodeNames());
  41. $this->assertSame(10, $node->getLine());
  42. $this->assertSame('/** doc comment */', $node->getDocComment()->getText());
  43. $this->assertSame('value1', $node->subNode1);
  44. $this->assertSame('value2', $node->subNode2);
  45. $this->assertTrue(isset($node->subNode1));
  46. $this->assertTrue(isset($node->subNode2));
  47. $this->assertFalse(isset($node->subNode3));
  48. $this->assertSame($attributes, $node->getAttributes());
  49. return $node;
  50. }
  51. /**
  52. * @dataProvider provideNodes
  53. */
  54. public function testGetDocComment(array $attributes, Node $node) {
  55. $this->assertSame('/** doc comment */', $node->getDocComment()->getText());
  56. array_pop($node->getAttribute('comments')); // remove doc comment
  57. $this->assertNull($node->getDocComment());
  58. array_pop($node->getAttribute('comments')); // remove comment
  59. $this->assertNull($node->getDocComment());
  60. }
  61. public function testSetDocComment() {
  62. $node = new DummyNode(null, null, []);
  63. // Add doc comment to node without comments
  64. $docComment = new Comment\Doc('/** doc */');
  65. $node->setDocComment($docComment);
  66. $this->assertSame($docComment, $node->getDocComment());
  67. // Replace it
  68. $docComment = new Comment\Doc('/** doc 2 */');
  69. $node->setDocComment($docComment);
  70. $this->assertSame($docComment, $node->getDocComment());
  71. // Add docmment to node with other comments
  72. $c1 = new Comment('/* foo */');
  73. $c2 = new Comment('/* bar */');
  74. $docComment = new Comment\Doc('/** baz */');
  75. $node->setAttribute('comments', [$c1, $c2]);
  76. $node->setDocComment($docComment);
  77. $this->assertSame([$c1, $c2, $docComment], $node->getAttribute('comments'));
  78. }
  79. /**
  80. * @dataProvider provideNodes
  81. */
  82. public function testChange(array $attributes, Node $node) {
  83. // change of line
  84. $node->setLine(15);
  85. $this->assertSame(15, $node->getLine());
  86. // direct modification
  87. $node->subNode = 'newValue';
  88. $this->assertSame('newValue', $node->subNode);
  89. // indirect modification
  90. $subNode =& $node->subNode;
  91. $subNode = 'newNewValue';
  92. $this->assertSame('newNewValue', $node->subNode);
  93. // removal
  94. unset($node->subNode);
  95. $this->assertFalse(isset($node->subNode));
  96. }
  97. /**
  98. * @dataProvider provideNodes
  99. */
  100. public function testIteration(array $attributes, Node $node) {
  101. // Iteration is simple object iteration over properties,
  102. // not over subnodes
  103. $i = 0;
  104. foreach ($node as $key => $value) {
  105. if ($i === 0) {
  106. $this->assertSame('subNode1', $key);
  107. $this->assertSame('value1', $value);
  108. } else if ($i === 1) {
  109. $this->assertSame('subNode2', $key);
  110. $this->assertSame('value2', $value);
  111. } else if ($i === 2) {
  112. $this->assertSame('notSubNode', $key);
  113. $this->assertSame('value3', $value);
  114. } else {
  115. throw new \Exception;
  116. }
  117. $i++;
  118. }
  119. $this->assertSame(3, $i);
  120. }
  121. public function testAttributes() {
  122. /** @var $node Node */
  123. $node = $this->getMockForAbstractClass('PhpParser\NodeAbstract');
  124. $this->assertEmpty($node->getAttributes());
  125. $node->setAttribute('key', 'value');
  126. $this->assertTrue($node->hasAttribute('key'));
  127. $this->assertSame('value', $node->getAttribute('key'));
  128. $this->assertFalse($node->hasAttribute('doesNotExist'));
  129. $this->assertNull($node->getAttribute('doesNotExist'));
  130. $this->assertSame('default', $node->getAttribute('doesNotExist', 'default'));
  131. $node->setAttribute('null', null);
  132. $this->assertTrue($node->hasAttribute('null'));
  133. $this->assertNull($node->getAttribute('null'));
  134. $this->assertNull($node->getAttribute('null', 'default'));
  135. $this->assertSame(
  136. array(
  137. 'key' => 'value',
  138. 'null' => null,
  139. ),
  140. $node->getAttributes()
  141. );
  142. }
  143. public function testJsonSerialization() {
  144. $code = <<<'PHP'
  145. <?php
  146. // comment
  147. /** doc comment */
  148. function functionName(&$a = 0, $b = 1.0) {
  149. echo 'Foo';
  150. }
  151. PHP;
  152. $expected = <<<'JSON'
  153. [
  154. {
  155. "nodeType": "Stmt_Function",
  156. "byRef": false,
  157. "name": "functionName",
  158. "params": [
  159. {
  160. "nodeType": "Param",
  161. "type": null,
  162. "byRef": true,
  163. "variadic": false,
  164. "name": "a",
  165. "default": {
  166. "nodeType": "Scalar_LNumber",
  167. "value": 0,
  168. "attributes": {
  169. "startLine": 4,
  170. "endLine": 4,
  171. "kind": 10
  172. }
  173. },
  174. "attributes": {
  175. "startLine": 4,
  176. "endLine": 4
  177. }
  178. },
  179. {
  180. "nodeType": "Param",
  181. "type": null,
  182. "byRef": false,
  183. "variadic": false,
  184. "name": "b",
  185. "default": {
  186. "nodeType": "Scalar_DNumber",
  187. "value": 1,
  188. "attributes": {
  189. "startLine": 4,
  190. "endLine": 4
  191. }
  192. },
  193. "attributes": {
  194. "startLine": 4,
  195. "endLine": 4
  196. }
  197. }
  198. ],
  199. "returnType": null,
  200. "stmts": [
  201. {
  202. "nodeType": "Stmt_Echo",
  203. "exprs": [
  204. {
  205. "nodeType": "Scalar_String",
  206. "value": "Foo",
  207. "attributes": {
  208. "startLine": 5,
  209. "endLine": 5,
  210. "kind": 1
  211. }
  212. }
  213. ],
  214. "attributes": {
  215. "startLine": 5,
  216. "endLine": 5
  217. }
  218. }
  219. ],
  220. "attributes": {
  221. "startLine": 4,
  222. "comments": [
  223. {
  224. "nodeType": "Comment",
  225. "text": "\/\/ comment\n",
  226. "line": 2,
  227. "filePos": 6
  228. },
  229. {
  230. "nodeType": "Comment_Doc",
  231. "text": "\/** doc comment *\/",
  232. "line": 3,
  233. "filePos": 17
  234. }
  235. ],
  236. "endLine": 6
  237. }
  238. }
  239. ]
  240. JSON;
  241. $parser = new Parser\Php7(new Lexer());
  242. $stmts = $parser->parse(canonicalize($code));
  243. $json = json_encode($stmts, JSON_PRETTY_PRINT);
  244. $this->assertEquals(canonicalize($expected), canonicalize($json));
  245. }
  246. }