/vendor/phpspec/phpspec/src/PhpSpec/Listener/MethodReturnedNullListener.php

https://gitlab.com/judielsm/Handora · PHP · 174 lines · 111 code · 27 blank · 36 comment · 12 complexity · d1233ae9fb6fd8965da47246c6e9236d MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of PhpSpec, A php toolset to drive emergent
  4. * design by specification.
  5. *
  6. * (c) Marcello Duarte <marcello.duarte@gmail.com>
  7. * (c) Konstantin Kudryashov <ever.zet@gmail.com>
  8. *
  9. * For the full copyright and license information, please view the LICENSE
  10. * file that was distributed with this source code.
  11. */
  12. namespace PhpSpec\Listener;
  13. use PhpSpec\CodeGenerator\GeneratorManager;
  14. use PhpSpec\Console\IO;
  15. use PhpSpec\Event\ExampleEvent;
  16. use PhpSpec\Event\MethodCallEvent;
  17. use PhpSpec\Event\SuiteEvent;
  18. use PhpSpec\Exception\Example\NotEqualException;
  19. use PhpSpec\Locator\ResourceManager;
  20. use PhpSpec\Util\MethodAnalyser;
  21. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  22. class MethodReturnedNullListener implements EventSubscriberInterface
  23. {
  24. /**
  25. * @var \PhpSpec\Console\IO
  26. */
  27. private $io;
  28. /**
  29. * @var MethodCallEvent[]
  30. */
  31. private $nullMethods = array();
  32. /**
  33. * @var MethodCallEvent|null
  34. */
  35. private $lastMethodCallEvent = null;
  36. /**
  37. * @var \PhpSpec\Locator\ResourceManager
  38. */
  39. private $resources;
  40. /**
  41. * @var \PhpSpec\CodeGenerator\GeneratorManager
  42. */
  43. private $generator;
  44. /**
  45. * @var MethodAnalyser
  46. */
  47. private $methodAnalyser;
  48. /**
  49. * @param IO $io
  50. * @param ResourceManager $resources
  51. * @param GeneratorManager $generator
  52. */
  53. public function __construct(
  54. IO $io,
  55. ResourceManager $resources,
  56. GeneratorManager $generator,
  57. MethodAnalyser $methodAnalyser
  58. ) {
  59. $this->io = $io;
  60. $this->resources = $resources;
  61. $this->generator = $generator;
  62. $this->methodAnalyser = $methodAnalyser;
  63. }
  64. /**
  65. * @{inheritdoc}
  66. */
  67. public static function getSubscribedEvents()
  68. {
  69. return array(
  70. 'afterExample' => array('afterExample', 10),
  71. 'afterSuite' => array('afterSuite', -20),
  72. 'afterMethodCall' => array('afterMethodCall')
  73. );
  74. }
  75. public function afterMethodCall(MethodCallEvent $methodCallEvent)
  76. {
  77. $this->lastMethodCallEvent = $methodCallEvent;
  78. }
  79. public function afterExample(ExampleEvent $exampleEvent)
  80. {
  81. $exception = $exampleEvent->getException();
  82. if (!$exception instanceof NotEqualException) {
  83. return;
  84. }
  85. if ($exception->getActual() !== null) {
  86. return;
  87. }
  88. if (is_object($exception->getExpected())
  89. || is_array($exception->getExpected())
  90. || is_resource($exception->getExpected())
  91. ) {
  92. return;
  93. }
  94. if (!$this->lastMethodCallEvent) {
  95. return;
  96. }
  97. $class = get_class($this->lastMethodCallEvent->getSubject());
  98. $method = $this->lastMethodCallEvent->getMethod();
  99. if (!$this->methodAnalyser->methodIsEmpty($class, $method)) {
  100. return;
  101. }
  102. $key = $class.'::'.$method;
  103. if (!array_key_exists($key, $this->nullMethods)) {
  104. $this->nullMethods[$key] = array(
  105. 'class' => $this->methodAnalyser->getMethodOwnerName($class, $method),
  106. 'method' => $method,
  107. 'expected' => array()
  108. );
  109. }
  110. $this->nullMethods[$key]['expected'][] = $exception->getExpected();
  111. }
  112. public function afterSuite(SuiteEvent $event)
  113. {
  114. if (!$this->io->isCodeGenerationEnabled()) {
  115. return;
  116. }
  117. if (!$this->io->isFakingEnabled()) {
  118. return;
  119. }
  120. foreach ($this->nullMethods as $methodString => $failedCall) {
  121. $failedCall['expected'] = array_unique($failedCall['expected']);
  122. if (count($failedCall['expected'])>1) {
  123. continue;
  124. }
  125. $expected = current($failedCall['expected']);
  126. $class = $failedCall['class'];
  127. $message = sprintf(
  128. 'Do you want me to make `%s()` always return %s for you?',
  129. $methodString,
  130. var_export($expected, true)
  131. );
  132. try {
  133. $resource = $this->resources->createResource($class);
  134. } catch (\RuntimeException $exception) {
  135. continue;
  136. }
  137. if ($this->io->askConfirmation($message)) {
  138. $this->generator->generate(
  139. $resource,
  140. 'returnConstant',
  141. array('method' => $failedCall['method'], 'expected' => $expected)
  142. );
  143. $event->markAsWorthRerunning();
  144. }
  145. }
  146. }
  147. }