/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php

https://gitlab.com/madwanz64/laravel · PHP · 286 lines · 137 code · 47 blank · 102 comment · 5 complexity · 387599860feab47c199d9408c00134d7 MD5 · raw file

  1. <?php
  2. namespace Illuminate\Foundation\Testing\Concerns;
  3. use Illuminate\Contracts\Bus\Dispatcher as BusDispatcherContract;
  4. use Illuminate\Contracts\Events\Dispatcher as EventsDispatcherContract;
  5. use Illuminate\Contracts\Notifications\Dispatcher as NotificationDispatcher;
  6. use Illuminate\Support\Facades\Event;
  7. use Mockery;
  8. trait MocksApplicationServices
  9. {
  10. /**
  11. * All of the fired events.
  12. *
  13. * @var array
  14. */
  15. protected $firedEvents = [];
  16. /**
  17. * All of the fired model events.
  18. *
  19. * @var array
  20. */
  21. protected $firedModelEvents = [];
  22. /**
  23. * All of the dispatched jobs.
  24. *
  25. * @var array
  26. */
  27. protected $dispatchedJobs = [];
  28. /**
  29. * All of the dispatched notifications.
  30. *
  31. * @var array
  32. */
  33. protected $dispatchedNotifications = [];
  34. /**
  35. * Specify a list of events that should be fired for the given operation.
  36. *
  37. * These events will be mocked, so that handlers will not actually be executed.
  38. *
  39. * @param array|string $events
  40. * @return $this
  41. *
  42. * @throws \Exception
  43. */
  44. public function expectsEvents($events)
  45. {
  46. $events = is_array($events) ? $events : func_get_args();
  47. $this->withoutEvents();
  48. $this->beforeApplicationDestroyed(function () use ($events) {
  49. $fired = $this->getFiredEvents($events);
  50. $this->assertEmpty(
  51. $eventsNotFired = array_diff($events, $fired),
  52. 'These expected events were not fired: ['.implode(', ', $eventsNotFired).']'
  53. );
  54. });
  55. return $this;
  56. }
  57. /**
  58. * Specify a list of events that should not be fired for the given operation.
  59. *
  60. * These events will be mocked, so that handlers will not actually be executed.
  61. *
  62. * @param array|string $events
  63. * @return $this
  64. */
  65. public function doesntExpectEvents($events)
  66. {
  67. $events = is_array($events) ? $events : func_get_args();
  68. $this->withoutEvents();
  69. $this->beforeApplicationDestroyed(function () use ($events) {
  70. $this->assertEmpty(
  71. $fired = $this->getFiredEvents($events),
  72. 'These unexpected events were fired: ['.implode(', ', $fired).']'
  73. );
  74. });
  75. return $this;
  76. }
  77. /**
  78. * Mock the event dispatcher so all events are silenced and collected.
  79. *
  80. * @return $this
  81. */
  82. protected function withoutEvents()
  83. {
  84. $mock = Mockery::mock(EventsDispatcherContract::class)->shouldIgnoreMissing();
  85. $mock->shouldReceive('dispatch', 'until')->andReturnUsing(function ($called) {
  86. $this->firedEvents[] = $called;
  87. });
  88. Event::clearResolvedInstances();
  89. $this->app->instance('events', $mock);
  90. return $this;
  91. }
  92. /**
  93. * Filter the given events against the fired events.
  94. *
  95. * @param array $events
  96. * @return array
  97. */
  98. protected function getFiredEvents(array $events)
  99. {
  100. return $this->getDispatched($events, $this->firedEvents);
  101. }
  102. /**
  103. * Specify a list of jobs that should be dispatched for the given operation.
  104. *
  105. * These jobs will be mocked, so that handlers will not actually be executed.
  106. *
  107. * @param array|string $jobs
  108. * @return $this
  109. */
  110. protected function expectsJobs($jobs)
  111. {
  112. $jobs = is_array($jobs) ? $jobs : func_get_args();
  113. $this->withoutJobs();
  114. $this->beforeApplicationDestroyed(function () use ($jobs) {
  115. $dispatched = $this->getDispatchedJobs($jobs);
  116. $this->assertEmpty(
  117. $jobsNotDispatched = array_diff($jobs, $dispatched),
  118. 'These expected jobs were not dispatched: ['.implode(', ', $jobsNotDispatched).']'
  119. );
  120. });
  121. return $this;
  122. }
  123. /**
  124. * Specify a list of jobs that should not be dispatched for the given operation.
  125. *
  126. * These jobs will be mocked, so that handlers will not actually be executed.
  127. *
  128. * @param array|string $jobs
  129. * @return $this
  130. */
  131. protected function doesntExpectJobs($jobs)
  132. {
  133. $jobs = is_array($jobs) ? $jobs : func_get_args();
  134. $this->withoutJobs();
  135. $this->beforeApplicationDestroyed(function () use ($jobs) {
  136. $this->assertEmpty(
  137. $dispatched = $this->getDispatchedJobs($jobs),
  138. 'These unexpected jobs were dispatched: ['.implode(', ', $dispatched).']'
  139. );
  140. });
  141. return $this;
  142. }
  143. /**
  144. * Mock the job dispatcher so all jobs are silenced and collected.
  145. *
  146. * @return $this
  147. */
  148. protected function withoutJobs()
  149. {
  150. $mock = Mockery::mock(BusDispatcherContract::class)->shouldIgnoreMissing();
  151. $mock->shouldReceive('dispatch', 'dispatchNow')->andReturnUsing(function ($dispatched) {
  152. $this->dispatchedJobs[] = $dispatched;
  153. });
  154. $this->app->instance(
  155. BusDispatcherContract::class, $mock
  156. );
  157. return $this;
  158. }
  159. /**
  160. * Filter the given jobs against the dispatched jobs.
  161. *
  162. * @param array $jobs
  163. * @return array
  164. */
  165. protected function getDispatchedJobs(array $jobs)
  166. {
  167. return $this->getDispatched($jobs, $this->dispatchedJobs);
  168. }
  169. /**
  170. * Filter the given classes against an array of dispatched classes.
  171. *
  172. * @param array $classes
  173. * @param array $dispatched
  174. * @return array
  175. */
  176. protected function getDispatched(array $classes, array $dispatched)
  177. {
  178. return array_filter($classes, function ($class) use ($dispatched) {
  179. return $this->wasDispatched($class, $dispatched);
  180. });
  181. }
  182. /**
  183. * Check if the given class exists in an array of dispatched classes.
  184. *
  185. * @param string $needle
  186. * @param array $haystack
  187. * @return bool
  188. */
  189. protected function wasDispatched($needle, array $haystack)
  190. {
  191. foreach ($haystack as $dispatched) {
  192. if ((is_string($dispatched) && ($dispatched === $needle || is_subclass_of($dispatched, $needle))) ||
  193. $dispatched instanceof $needle) {
  194. return true;
  195. }
  196. }
  197. return false;
  198. }
  199. /**
  200. * Mock the notification dispatcher so all notifications are silenced.
  201. *
  202. * @return $this
  203. */
  204. protected function withoutNotifications()
  205. {
  206. $mock = Mockery::mock(NotificationDispatcher::class);
  207. $mock->shouldReceive('send')->andReturnUsing(function ($notifiable, $instance, $channels = []) {
  208. $this->dispatchedNotifications[] = compact(
  209. 'notifiable', 'instance', 'channels'
  210. );
  211. });
  212. $this->app->instance(NotificationDispatcher::class, $mock);
  213. return $this;
  214. }
  215. /**
  216. * Specify a notification that is expected to be dispatched.
  217. *
  218. * @param mixed $notifiable
  219. * @param string $notification
  220. * @return $this
  221. */
  222. protected function expectsNotification($notifiable, $notification)
  223. {
  224. $this->withoutNotifications();
  225. $this->beforeApplicationDestroyed(function () use ($notifiable, $notification) {
  226. foreach ($this->dispatchedNotifications as $dispatched) {
  227. $notified = $dispatched['notifiable'];
  228. if (($notified === $notifiable ||
  229. $notified->getKey() == $notifiable->getKey()) &&
  230. get_class($dispatched['instance']) === $notification
  231. ) {
  232. return $this;
  233. }
  234. }
  235. $this->fail('The following expected notification were not dispatched: ['.$notification.']');
  236. });
  237. return $this;
  238. }
  239. }