DocParserTest.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. <?php
  2. namespace Doctrine\Tests\Common\Annotations;
  3. use Doctrine\Common\Annotations\Annotation\IgnorePhpDoc;
  4. use Doctrine\Common\Annotations\Annotation\IgnoreAnnotation;
  5. use Doctrine\Common\Annotations\DocParser;
  6. use Doctrine\Common\Annotations\AnnotationRegistry;
  7. class DocParserTest extends \PHPUnit_Framework_TestCase
  8. {
  9. public function testNestedArraysWithNestedAnnotation()
  10. {
  11. $parser = $this->createTestParser();
  12. // Nested arrays with nested annotations
  13. $result = $parser->parse('@Name(foo={1,2, {"key"=@Name}})');
  14. $annot = $result[0];
  15. $this->assertTrue($annot instanceof Name);
  16. $this->assertNull($annot->value);
  17. $this->assertEquals(3, count($annot->foo));
  18. $this->assertEquals(1, $annot->foo[0]);
  19. $this->assertEquals(2, $annot->foo[1]);
  20. $this->assertTrue(is_array($annot->foo[2]));
  21. $nestedArray = $annot->foo[2];
  22. $this->assertTrue(isset($nestedArray['key']));
  23. $this->assertTrue($nestedArray['key'] instanceof Name);
  24. }
  25. public function testBasicAnnotations()
  26. {
  27. $parser = $this->createTestParser();
  28. // Marker annotation
  29. $result = $parser->parse("@Name");
  30. $annot = $result[0];
  31. $this->assertTrue($annot instanceof Name);
  32. $this->assertNull($annot->value);
  33. $this->assertNull($annot->foo);
  34. // Associative arrays
  35. $result = $parser->parse('@Name(foo={"key1" = "value1"})');
  36. $annot = $result[0];
  37. $this->assertNull($annot->value);
  38. $this->assertTrue(is_array($annot->foo));
  39. $this->assertTrue(isset($annot->foo['key1']));
  40. // Numerical arrays
  41. $result = $parser->parse('@Name({2="foo", 4="bar"})');
  42. $annot = $result[0];
  43. $this->assertTrue(is_array($annot->value));
  44. $this->assertEquals('foo', $annot->value[2]);
  45. $this->assertEquals('bar', $annot->value[4]);
  46. $this->assertFalse(isset($annot->value[0]));
  47. $this->assertFalse(isset($annot->value[1]));
  48. $this->assertFalse(isset($annot->value[3]));
  49. // Multiple values
  50. $result = $parser->parse('@Name(@Name, @Name)');
  51. $annot = $result[0];
  52. $this->assertTrue($annot instanceof Name);
  53. $this->assertTrue(is_array($annot->value));
  54. $this->assertTrue($annot->value[0] instanceof Name);
  55. $this->assertTrue($annot->value[1] instanceof Name);
  56. // Multiple types as values
  57. $result = $parser->parse('@Name(foo="Bar", @Name, {"key1"="value1", "key2"="value2"})');
  58. $annot = $result[0];
  59. $this->assertTrue($annot instanceof Name);
  60. $this->assertTrue(is_array($annot->value));
  61. $this->assertTrue($annot->value[0] instanceof Name);
  62. $this->assertTrue(is_array($annot->value[1]));
  63. $this->assertEquals('value1', $annot->value[1]['key1']);
  64. $this->assertEquals('value2', $annot->value[1]['key2']);
  65. // Complete docblock
  66. $docblock = <<<DOCBLOCK
  67. /**
  68. * Some nifty class.
  69. *
  70. * @author Mr.X
  71. * @Name(foo="bar")
  72. */
  73. DOCBLOCK;
  74. $result = $parser->parse($docblock);
  75. $this->assertEquals(1, count($result));
  76. $annot = $result[0];
  77. $this->assertTrue($annot instanceof Name);
  78. $this->assertEquals("bar", $annot->foo);
  79. $this->assertNull($annot->value);
  80. }
  81. public function testNamespacedAnnotations()
  82. {
  83. $parser = new DocParser;
  84. $parser->setIgnoreNotImportedAnnotations(true);
  85. $docblock = <<<DOCBLOCK
  86. /**
  87. * Some nifty class.
  88. *
  89. * @package foo
  90. * @subpackage bar
  91. * @author Mr.X <mr@x.com>
  92. * @Doctrine\Tests\Common\Annotations\Name(foo="bar")
  93. * @ignore
  94. */
  95. DOCBLOCK;
  96. $result = $parser->parse($docblock);
  97. $this->assertEquals(1, count($result));
  98. $annot = $result[0];
  99. $this->assertTrue($annot instanceof Name);
  100. $this->assertEquals("bar", $annot->foo);
  101. }
  102. /**
  103. * @group debug
  104. */
  105. public function testTypicalMethodDocBlock()
  106. {
  107. $parser = $this->createTestParser();
  108. $docblock = <<<DOCBLOCK
  109. /**
  110. * Some nifty method.
  111. *
  112. * @since 2.0
  113. * @Doctrine\Tests\Common\Annotations\Name(foo="bar")
  114. * @param string \$foo This is foo.
  115. * @param mixed \$bar This is bar.
  116. * @return string Foo and bar.
  117. * @This is irrelevant
  118. * @Marker
  119. */
  120. DOCBLOCK;
  121. $result = $parser->parse($docblock);
  122. $this->assertEquals(2, count($result));
  123. $this->assertTrue(isset($result[0]));
  124. $this->assertTrue(isset($result[1]));
  125. $annot = $result[0];
  126. $this->assertTrue($annot instanceof Name);
  127. $this->assertEquals("bar", $annot->foo);
  128. $marker = $result[1];
  129. $this->assertTrue($marker instanceof Marker);
  130. }
  131. /**
  132. * @group DDC-575
  133. */
  134. public function testRegressionDDC575()
  135. {
  136. $parser = $this->createTestParser();
  137. $docblock = <<<DOCBLOCK
  138. /**
  139. * @Name
  140. *
  141. * Will trigger error.
  142. */
  143. DOCBLOCK;
  144. $result = $parser->parse($docblock);
  145. $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]);
  146. $docblock = <<<DOCBLOCK
  147. /**
  148. * @Name
  149. * @Marker
  150. *
  151. * Will trigger error.
  152. */
  153. DOCBLOCK;
  154. $result = $parser->parse($docblock);
  155. $this->assertInstanceOf("Doctrine\Tests\Common\Annotations\Name", $result[0]);
  156. }
  157. /**
  158. * @group DDC-77
  159. */
  160. public function testAnnotationWithoutClassIsIgnoredWithoutWarning()
  161. {
  162. $parser = new DocParser();
  163. $parser->setIgnoreNotImportedAnnotations(true);
  164. $result = $parser->parse("@param");
  165. $this->assertEquals(0, count($result));
  166. }
  167. /**
  168. * @expectedException Doctrine\Common\Annotations\AnnotationException
  169. * @expectedExceptionMessage Expected PlainValue, got ''' at position 10.
  170. */
  171. public function testAnnotationDontAcceptSingleQuotes()
  172. {
  173. $parser = $this->createTestParser();
  174. $parser->parse("@Name(foo='bar')");
  175. }
  176. /**
  177. * @group DCOM-41
  178. */
  179. public function testAnnotationDoesntThrowExceptionWhenAtSignIsNotFollowedByIdentifier()
  180. {
  181. $parser = new DocParser();
  182. $result = $parser->parse("'@'");
  183. $this->assertEquals(0, count($result));
  184. }
  185. /**
  186. * @group DCOM-41
  187. * @expectedException Doctrine\Common\Annotations\AnnotationException
  188. */
  189. public function testAnnotationThrowsExceptionWhenAtSignIsNotFollowedByIdentifierInNestedAnnotation()
  190. {
  191. $parser = new DocParser();
  192. $result = $parser->parse("@Doctrine\Tests\Common\Annotations\Name(@')");
  193. }
  194. /**
  195. * @group DCOM-56
  196. */
  197. public function testAutoloadAnnotation()
  198. {
  199. $this->assertFalse(class_exists('Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload', false), 'Pre-condition: Doctrine\Tests\Common\Annotations\Fixture\Annotation\Autoload not allowed to be loaded.');
  200. $parser = new DocParser();
  201. AnnotationRegistry::registerAutoloadNamespace('Doctrine\Tests\Common\Annotations\Fixtures\Annotation', __DIR__ . '/../../../../');
  202. $parser->setImports(array(
  203. 'autoload' => 'Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload',
  204. ));
  205. $annotations = $parser->parse('@Autoload');
  206. $this->assertEquals(1, count($annotations));
  207. $this->assertInstanceOf('Doctrine\Tests\Common\Annotations\Fixtures\Annotation\Autoload', $annotations[0]);
  208. }
  209. public function createTestParser()
  210. {
  211. $parser = new DocParser();
  212. $parser->setIgnoreNotImportedAnnotations(true);
  213. $parser->setImports(array(
  214. 'name' => 'Doctrine\Tests\Common\Annotations\Name',
  215. '__NAMESPACE__' => 'Doctrine\Tests\Common\Annotations',
  216. ));
  217. return $parser;
  218. }
  219. /**
  220. * @group DDC-78
  221. * @expectedException Doctrine\Common\Annotations\AnnotationException
  222. * @expectedExceptionMessage Expected PlainValue, got ''' at position 10 in class \Doctrine\Tests\Common\Annotations\Name
  223. */
  224. public function testSyntaxErrorWithContextDescription()
  225. {
  226. $parser = $this->createTestParser();
  227. $parser->parse("@Name(foo='bar')", "class \Doctrine\Tests\Common\Annotations\Name");
  228. }
  229. /**
  230. * @group DDC-183
  231. */
  232. public function testSyntaxErrorWithUnknownCharacters()
  233. {
  234. $docblock = <<<DOCBLOCK
  235. /**
  236. * @test at.
  237. */
  238. class A {
  239. }
  240. DOCBLOCK;
  241. //$lexer = new \Doctrine\Common\Annotations\Lexer();
  242. //$lexer->setInput(trim($docblock, '/ *'));
  243. //var_dump($lexer);
  244. try {
  245. $parser = $this->createTestParser();
  246. $result = $parser->parse($docblock);
  247. } catch (Exception $e) {
  248. $this->fail($e->getMessage());
  249. }
  250. }
  251. /**
  252. * @group DCOM-14
  253. */
  254. public function testIgnorePHPDocThrowTag()
  255. {
  256. $docblock = <<<DOCBLOCK
  257. /**
  258. * @throws \RuntimeException
  259. */
  260. class A {
  261. }
  262. DOCBLOCK;
  263. try {
  264. $parser = $this->createTestParser();
  265. $result = $parser->parse($docblock);
  266. } catch (Exception $e) {
  267. $this->fail($e->getMessage());
  268. }
  269. }
  270. /**
  271. * @group DCOM-38
  272. */
  273. public function testCastInt()
  274. {
  275. $parser = $this->createTestParser();
  276. $result = $parser->parse("@Name(foo=1234)");
  277. $annot = $result[0];
  278. $this->assertInternalType('int', $annot->foo);
  279. }
  280. /**
  281. * @group DCOM-38
  282. */
  283. public function testCastFloat()
  284. {
  285. $parser = $this->createTestParser();
  286. $result = $parser->parse("@Name(foo=1234.345)");
  287. $annot = $result[0];
  288. $this->assertInternalType('float', $annot->foo);
  289. }
  290. public function testReservedKeywordsInAnnotations()
  291. {
  292. $parser = $this->createTestParser();
  293. $result = $parser->parse('@Doctrine\Tests\Common\Annotations\True');
  294. $this->assertTrue($result[0] instanceof True);
  295. $result = $parser->parse('@Doctrine\Tests\Common\Annotations\False');
  296. $this->assertTrue($result[0] instanceof False);
  297. $result = $parser->parse('@Doctrine\Tests\Common\Annotations\Null');
  298. $this->assertTrue($result[0] instanceof Null);
  299. $result = $parser->parse('@True');
  300. $this->assertTrue($result[0] instanceof True);
  301. $result = $parser->parse('@False');
  302. $this->assertTrue($result[0] instanceof False);
  303. $result = $parser->parse('@Null');
  304. $this->assertTrue($result[0] instanceof Null);
  305. }
  306. /**
  307. * @expectedException Doctrine\Common\Annotations\AnnotationException
  308. * @expectedExceptionMessage [Syntax Error] Expected Doctrine\Common\Annotations\DocLexer::T_IDENTIFIER or Doctrine\Common\Annotations\DocLexer::T_TRUE or Doctrine\Common\Annotations\DocLexer::T_FALSE or Doctrine\Common\Annotations\DocLexer::T_NULL, got '3.42' at position 5.
  309. */
  310. public function testInvalidIdentifierInAnnotation()
  311. {
  312. $parser = $this->createTestParser();
  313. $result = $parser->parse('@Foo\3.42');
  314. }
  315. }
  316. class Name extends \Doctrine\Common\Annotations\Annotation {
  317. public $foo;
  318. }
  319. class Marker extends \Doctrine\Common\Annotations\Annotation {}
  320. class True extends \Doctrine\Common\Annotations\Annotation {}
  321. class False extends \Doctrine\Common\Annotations\Annotation {}
  322. class Null extends \Doctrine\Common\Annotations\Annotation {}
  323. namespace Doctrine\Tests\Common\Annotations\FooBar;
  324. class Name extends \Doctrine\Common\Annotations\Annotation {
  325. }