MapperTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of sebastian/code-unit.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\CodeUnit;
  11. use function range;
  12. use function realpath;
  13. use PHPUnit\Framework\TestCase;
  14. use SebastianBergmann\CodeUnit\Fixture\FixtureAnotherChildClass;
  15. use SebastianBergmann\CodeUnit\Fixture\FixtureAnotherParentClass;
  16. use SebastianBergmann\CodeUnit\Fixture\FixtureAnotherTrait;
  17. use SebastianBergmann\CodeUnit\Fixture\FixtureChildClassWithTrait;
  18. use SebastianBergmann\CodeUnit\Fixture\FixtureClass;
  19. use SebastianBergmann\CodeUnit\Fixture\FixtureClassWithTrait;
  20. use SebastianBergmann\CodeUnit\Fixture\FixtureInterface;
  21. use SebastianBergmann\CodeUnit\Fixture\FixtureParentClassWithTrait;
  22. use SebastianBergmann\CodeUnit\Fixture\FixtureTrait;
  23. use SebastianBergmann\CodeUnit\Fixture\Getopt;
  24. use SebastianBergmann\CodeUnit\Fixture\Issue5Exception;
  25. /**
  26. * @covers \SebastianBergmann\CodeUnit\Mapper
  27. *
  28. * @uses \SebastianBergmann\CodeUnit\CodeUnit
  29. * @uses \SebastianBergmann\CodeUnit\CodeUnitCollection
  30. * @uses \SebastianBergmann\CodeUnit\CodeUnitCollectionIterator
  31. */
  32. final class MapperTest extends TestCase
  33. {
  34. /**
  35. * @testdox Can map 'function_name' string to code unit objects
  36. */
  37. public function testCanMapStringWithFunctionNameToCodeUnitObjects(): void
  38. {
  39. $units = (new Mapper)->stringToCodeUnits('SebastianBergmann\CodeUnit\Fixture\f');
  40. $this->assertSame('SebastianBergmann\CodeUnit\Fixture\f', $units->asArray()[0]->name());
  41. }
  42. /**
  43. * @testdox Can map '::function_name' string to code unit objects
  44. */
  45. public function testCanMapStringWithFunctionNamePrefixedWithDoubleColonsToCodeUnitObjects(): void
  46. {
  47. $units = (new Mapper)->stringToCodeUnits('::f');
  48. $this->assertSame('f', $units->asArray()[0]->name());
  49. }
  50. /**
  51. * @testdox Can map 'ClassName' string to code unit objects
  52. */
  53. public function testCanMapStringWithClassNameToCodeUnitObjects(): void
  54. {
  55. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class);
  56. $this->assertCount(1, $units);
  57. $this->assertSame(FixtureClass::class, $units->asArray()[0]->name());
  58. }
  59. /**
  60. * @testdox Can map 'ClassName' string to code unit objects
  61. */
  62. public function testMapClassesAndTheTraitsTheyUseToCodeUnitObjects(): void
  63. {
  64. $units = (new Mapper)->stringToCodeUnits(FixtureClassWithTrait::class);
  65. $this->assertCount(2, $units);
  66. $this->assertSame(FixtureClassWithTrait::class, $units->asArray()[0]->name());
  67. $this->assertSame(FixtureTrait::class, $units->asArray()[1]->name());
  68. }
  69. /**
  70. * @testdox Can map 'ClassName<extended>' string to code unit objects
  71. */
  72. public function testCanMapStringWithClassNameAndSelectorForParentClassesToCodeUnitObjects(): void
  73. {
  74. $units = (new Mapper)->stringToCodeUnits(FixtureChildClassWithTrait::class . '<extended>');
  75. $this->assertCount(4, $units);
  76. $this->assertSame(FixtureChildClassWithTrait::class, $units->asArray()[0]->name());
  77. $this->assertSame(FixtureAnotherTrait::class, $units->asArray()[1]->name());
  78. $this->assertSame(FixtureParentClassWithTrait::class, $units->asArray()[2]->name());
  79. $this->assertSame(FixtureTrait::class, $units->asArray()[3]->name());
  80. }
  81. /**
  82. * @testdox Can map 'ClassName::methodName' string to code unit objects
  83. */
  84. public function testCanMapStringWithClassNameAndMethodNameToCodeUnitObjects(): void
  85. {
  86. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::publicMethod');
  87. $this->assertSame(FixtureClass::class . '::publicMethod', $units->asArray()[0]->name());
  88. }
  89. /**
  90. * @testdox Can map 'ClassName::<public>' string to code unit objects
  91. */
  92. public function testCanMapStringWithClassNameAndPublicMethodSelectorToCodeUnitObjects(): void
  93. {
  94. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<public>');
  95. $this->assertCount(1, $units);
  96. $this->assertSame(FixtureClass::class . '::publicMethod', $units->asArray()[0]->name());
  97. }
  98. /**
  99. * @testdox Can map 'ClassName::<!public>' string to code unit objects
  100. */
  101. public function testCanMapStringWithClassNameAndNoPublicMethodSelectorToCodeUnitObjects(): void
  102. {
  103. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<!public>');
  104. $this->assertCount(2, $units);
  105. $this->assertSame(FixtureClass::class . '::protectedMethod', $units->asArray()[0]->name());
  106. $this->assertSame(FixtureClass::class . '::privateMethod', $units->asArray()[1]->name());
  107. }
  108. /**
  109. * @testdox Can map 'ClassName::<protected>' string to code unit objects
  110. */
  111. public function testCanMapStringWithClassNameAndProtectedMethodSelectorToCodeUnitObjects(): void
  112. {
  113. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<protected>');
  114. $this->assertCount(1, $units);
  115. $this->assertSame(FixtureClass::class . '::protectedMethod', $units->asArray()[0]->name());
  116. }
  117. /**
  118. * @testdox Can map 'ClassName::<!protected>' string to code unit objects
  119. */
  120. public function testCanMapStringWithClassNameAndNoProtectedMethodSelectorToCodeUnitObjects(): void
  121. {
  122. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<!protected>');
  123. $this->assertCount(2, $units);
  124. $this->assertSame(FixtureClass::class . '::publicMethod', $units->asArray()[0]->name());
  125. $this->assertSame(FixtureClass::class . '::privateMethod', $units->asArray()[1]->name());
  126. }
  127. /**
  128. * @testdox Can map 'ClassName::<private>' string to code unit objects
  129. */
  130. public function testCanMapStringWithClassNameAndPrivateMethodSelectorToCodeUnitObjects(): void
  131. {
  132. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<private>');
  133. $this->assertCount(1, $units);
  134. $this->assertSame(FixtureClass::class . '::privateMethod', $units->asArray()[0]->name());
  135. }
  136. /**
  137. * @testdox Can map 'ClassName::<!private>' string to code unit objects
  138. */
  139. public function testCanMapStringWithClassNameAndNoPrivateMethodSelectorToCodeUnitObjects(): void
  140. {
  141. $units = (new Mapper)->stringToCodeUnits(FixtureClass::class . '::<!private>');
  142. $this->assertCount(2, $units);
  143. $this->assertSame(FixtureClass::class . '::publicMethod', $units->asArray()[0]->name());
  144. $this->assertSame(FixtureClass::class . '::protectedMethod', $units->asArray()[1]->name());
  145. }
  146. /**
  147. * @testdox Can map 'InterfaceName' string to code unit objects
  148. */
  149. public function testCanMapStringWithInterfaceNameToCodeUnitObjects(): void
  150. {
  151. $units = (new Mapper)->stringToCodeUnits(FixtureInterface::class);
  152. $this->assertSame(FixtureInterface::class, $units->asArray()[0]->name());
  153. }
  154. /**
  155. * @testdox Can map 'InterfaceName::methodName' string to code unit objects
  156. */
  157. public function testCanMapStringWithInterfaceNameAndMethodNameToCodeUnitObjects(): void
  158. {
  159. $units = (new Mapper)->stringToCodeUnits(FixtureInterface::class . '::method');
  160. $this->assertSame(FixtureInterface::class . '::method', $units->asArray()[0]->name());
  161. }
  162. /**
  163. * @testdox Can map 'TraitName' string to code unit objects
  164. */
  165. public function testCanMapStringWithTraitNameToCodeUnitObjects(): void
  166. {
  167. $units = (new Mapper)->stringToCodeUnits(FixtureTrait::class);
  168. $this->assertSame(FixtureTrait::class, $units->asArray()[0]->name());
  169. }
  170. /**
  171. * @testdox Can map 'TraitName::methodName' string to code unit objects
  172. */
  173. public function testCanMapStringWithTraitNameAndMethodNameToCodeUnitObjects(): void
  174. {
  175. $units = (new Mapper)->stringToCodeUnits(FixtureTrait::class . '::method');
  176. $this->assertSame(FixtureTrait::class . '::method', $units->asArray()[0]->name());
  177. }
  178. public function testCannotMapInvalidStringToCodeUnitObjects(): void
  179. {
  180. $this->expectException(InvalidCodeUnitException::class);
  181. (new Mapper)->stringToCodeUnits('invalid');
  182. }
  183. public function testCanMapCodeUnitObjectsToArrayWithSourceLinesInSingleFile(): void
  184. {
  185. $codeUnits = CodeUnitCollection::fromList(
  186. CodeUnit::forFunction('SebastianBergmann\CodeUnit\Fixture\another_function'),
  187. CodeUnit::forClass(FixtureAnotherParentClass::class),
  188. CodeUnit::forClass(FixtureAnotherChildClass::class),
  189. );
  190. $this->assertSame(
  191. [
  192. realpath(__DIR__ . '/../_fixture/file_with_multiple_code_units.php') => [
  193. 12,
  194. 13,
  195. 14,
  196. 16,
  197. 17,
  198. 18,
  199. 20,
  200. 21,
  201. 22,
  202. ],
  203. ],
  204. (new Mapper)->codeUnitsToSourceLines($codeUnits)
  205. );
  206. }
  207. public function testCanMapCodeUnitObjectsToArrayWithSourceLinesInMultipleFiles(): void
  208. {
  209. $codeUnits = CodeUnitCollection::fromList(
  210. CodeUnit::forInterface(FixtureInterface::class),
  211. CodeUnit::forClass(FixtureClass::class),
  212. CodeUnit::forClass(FixtureClass::class)
  213. );
  214. $this->assertSame(
  215. [
  216. realpath(__DIR__ . '/../_fixture/FixtureClass.php') => range(12, 28),
  217. realpath(__DIR__ . '/../_fixture/FixtureInterface.php') => range(12, 15),
  218. ],
  219. (new Mapper)->codeUnitsToSourceLines($codeUnits)
  220. );
  221. }
  222. public function testCanMapOverlappingCodeUnitObjectsToArrayWithSourceLines(): void
  223. {
  224. $codeUnits = CodeUnitCollection::fromList(
  225. CodeUnit::forClass(FixtureClass::class),
  226. CodeUnit::forClassMethod(FixtureClass::class, 'publicMethod'),
  227. CodeUnit::forClassMethod(FixtureClass::class, 'protectedMethod'),
  228. CodeUnit::forClassMethod(FixtureClass::class, 'privateMethod'),
  229. );
  230. $this->assertSame(
  231. [
  232. realpath(__DIR__ . '/../_fixture/FixtureClass.php') => range(12, 28),
  233. ],
  234. (new Mapper)->codeUnitsToSourceLines($codeUnits)
  235. );
  236. }
  237. /**
  238. * @ticket https://github.com/sebastianbergmann/code-unit/issues/3
  239. */
  240. public function testIssue3(): void
  241. {
  242. $units = (new Mapper)->stringToCodeUnits(Getopt::class . '::getopt');
  243. $this->assertSame(Getopt::class . '::getopt', $units->asArray()[0]->name());
  244. }
  245. /**
  246. * @ticket https://github.com/sebastianbergmann/code-unit/issues/5
  247. */
  248. public function testIssue5(): void
  249. {
  250. $units = (new Mapper)->stringToCodeUnits(Issue5Exception::class . '::<!public>');
  251. $this->assertCount(0, $units->asArray());
  252. }
  253. }