PageRenderTime 55ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Mockery/Container.php

https://github.com/DocAl/mockery
PHP | 322 lines | 191 code | 22 blank | 109 comment | 32 complexity | f94223017d59abb000e1ab5522715a9e MD5 | raw file
  1. <?php
  2. /**
  3. * Mockery
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://github.com/padraic/mockery/blob/master/LICENSE
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to padraic@php.net so we can send you a copy immediately.
  14. *
  15. * @category Mockery
  16. * @package Mockery
  17. * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
  18. * @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
  19. */
  20. namespace Mockery;
  21. class Container
  22. {
  23. const BLOCKS = \Mockery::BLOCKS;
  24. /**
  25. * Store of mock objects
  26. *
  27. * @var array
  28. */
  29. protected $_mocks = array();
  30. /**
  31. * Order number of allocation
  32. *
  33. * @var int
  34. */
  35. protected $_allocatedOrder = 0;
  36. /**
  37. * Current ordered number
  38. *
  39. * @var int
  40. */
  41. protected $_currentOrder = 0;
  42. /**
  43. * Ordered groups
  44. *
  45. * @var array
  46. */
  47. protected $_groups = array();
  48. /**
  49. * Generates a new mock object for this container
  50. *
  51. * I apologies in advance for this. A God Method just fits the API which
  52. * doesn't require differentiating between classes, interfaces, abstracts,
  53. * names or partials - just so long as it's something that can be mocked.
  54. * I'll refactor it one day so it's easier to follow.
  55. *
  56. * @return \Mockery\Mock
  57. */
  58. public function mock()
  59. {
  60. $class = null;
  61. $name = null;
  62. $partial = null;
  63. $expectationClosure = null;
  64. $quickdefs = array();
  65. $blocks = array();
  66. $makeInstanceMock = false;
  67. $args = func_get_args();
  68. $partialMethods = array();
  69. if (count($args) > 1) {
  70. $finalArg = end($args);
  71. reset($args);
  72. if (is_callable($finalArg)) {
  73. $expectationClosure = array_pop($args);
  74. }
  75. }
  76. while (count($args) > 0) {
  77. $arg = current($args);
  78. // check for multiple interfaces
  79. if (is_string($arg) && strpos($arg, ',') && !strpos($arg, ']')) {
  80. $interfaces = explode(',', str_replace(' ', '', $arg));
  81. foreach ($interfaces as $i) {
  82. if (!interface_exists($i, true) && !class_exists($i, true)) {
  83. throw new \Mockery\Exception(
  84. 'Class name follows the format for defining multiple'
  85. . ' interfaces, however one or more of the interfaces'
  86. . ' do not exist or are not included, or the base class'
  87. . ' (optional) does not exist'
  88. );
  89. }
  90. }
  91. $class = $interfaces;
  92. array_shift($args);
  93. } elseif (is_string($arg) && substr($arg, 0, 6) == 'alias:') {
  94. $class = 'stdClass';
  95. $name = array_shift($args);
  96. $name = str_replace('alias:', '', $name);
  97. } elseif (is_string($arg) && substr($arg, 0, 9) == 'overload:') {
  98. $class = 'stdClass';
  99. $name = array_shift($args);
  100. $name = str_replace('overload:', '', $name);
  101. $makeInstanceMock = true;
  102. } elseif (is_string($arg) && substr($arg, strlen($arg)-1, 1) == ']') {
  103. $parts = explode('[', $arg);
  104. if (!class_exists($parts[0], true) && !interface_exists($parts[0], true)) {
  105. throw new \Mockery\Exception('Can only create a partial mock from'
  106. . ' an existing class or interface');
  107. }
  108. $class = $parts[0];
  109. $parts[1] = str_replace(' ','', $parts[1]);
  110. $partialMethods = explode(',', strtolower(rtrim($parts[1], ']')));
  111. array_shift($args);
  112. } elseif (is_string($arg) && (class_exists($arg, true) || interface_exists($arg, true))) {
  113. $class = array_shift($args);
  114. } elseif (is_string($arg)) {
  115. $name = array_shift($args);
  116. } elseif (is_object($arg)) {
  117. $partial = array_shift($args);
  118. } elseif (is_array($arg)) {
  119. if(array_key_exists(self::BLOCKS, $arg)) $blocks = $arg[self::BLOCKS]; unset($arg[self::BLOCKS]);
  120. $quickdefs = array_shift($args);
  121. } else {
  122. throw new \Mockery\Exception(
  123. 'Unable to parse arguments sent to '
  124. . get_class($this) . '::mock()'
  125. );
  126. }
  127. }
  128. if (!is_null($name) && !is_null($class)) {
  129. if (!$makeInstanceMock) {
  130. $mockName = \Mockery\Generator::createClassMock($class);
  131. } else {
  132. $mockName = \Mockery\Generator::createClassMock($class, null, null, array(), true);
  133. }
  134. $result = class_alias($mockName, $name);
  135. $mock = $this->_getInstance($name);
  136. $mock->mockery_init($class, $this);
  137. } elseif (!is_null($name)) {
  138. $mock = new \Mockery\Mock();
  139. $mock->mockery_init($name, $this);
  140. } elseif(!is_null($class)) {
  141. $mockName = \Mockery\Generator::createClassMock($class, null, null, array(), false, $partialMethods);
  142. $mock = $this->_getInstance($mockName);
  143. $mock->mockery_init($class, $this);
  144. } elseif(!is_null($partial)) {
  145. $mockName = \Mockery\Generator::createClassMock(get_class($partial), null, true, $blocks);
  146. $mock = $this->_getInstance($mockName);
  147. $mock->mockery_init(get_class($partial), $this, $partial);
  148. } else {
  149. $mock = new \Mockery\Mock();
  150. $mock->mockery_init('unknown', $this);
  151. }
  152. if (!empty($quickdefs)) {
  153. $mock->shouldReceive($quickdefs);
  154. }
  155. if (!empty($expectationClosure)) {
  156. $expectationClosure($mock);
  157. }
  158. $this->rememberMock($mock);
  159. return $mock;
  160. }
  161. public function instanceMock()
  162. {
  163. }
  164. /**
  165. * Tear down tasks for this container
  166. *
  167. * @return void
  168. */
  169. public function mockery_teardown()
  170. {
  171. try {
  172. $this->mockery_verify();
  173. } catch (\Exception $e) {
  174. $this->mockery_close();
  175. throw $e;
  176. }
  177. }
  178. /**
  179. * Verify the container mocks
  180. *
  181. * @return void
  182. */
  183. public function mockery_verify()
  184. {
  185. foreach($this->_mocks as $mock) {
  186. $mock->mockery_verify();
  187. }
  188. }
  189. /**
  190. * Reset the container to its original state
  191. *
  192. * @return void
  193. */
  194. public function mockery_close()
  195. {
  196. foreach($this->_mocks as $mock) {
  197. $mock->mockery_teardown();
  198. }
  199. $this->_mocks = array();
  200. }
  201. /**
  202. * Fetch the next available allocation order number
  203. *
  204. * @return int
  205. */
  206. public function mockery_allocateOrder()
  207. {
  208. $this->_allocatedOrder += 1;
  209. return $this->_allocatedOrder;
  210. }
  211. /**
  212. * Set ordering for a group
  213. *
  214. * @param mixed $group
  215. * @param int $order
  216. */
  217. public function mockery_setGroup($group, $order)
  218. {
  219. $this->_groups[$group] = $order;
  220. }
  221. /**
  222. * Fetch array of ordered groups
  223. *
  224. * @return array
  225. */
  226. public function mockery_getGroups()
  227. {
  228. return $this->_groups;
  229. }
  230. /**
  231. * Set current ordered number
  232. *
  233. * @param int $order
  234. * @return int The current order number that was set
  235. */
  236. public function mockery_setCurrentOrder($order)
  237. {
  238. $this->_currentOrder = $order;
  239. return $this->_currentOrder;
  240. }
  241. /**
  242. * Get current ordered number
  243. *
  244. * @return int
  245. */
  246. public function mockery_getCurrentOrder()
  247. {
  248. return $this->_currentOrder;
  249. }
  250. /**
  251. * Validate the current mock's ordering
  252. *
  253. * @param string $method
  254. * @param int $order
  255. * @throws \Mockery\Exception
  256. * @return void
  257. */
  258. public function mockery_validateOrder($method, $order)
  259. {
  260. if ($order < $this->_currentOrder) {
  261. throw new \Mockery\Exception(
  262. 'Method ' . $method . ' called out of order: expected order '
  263. . $order . ', was ' . $this->_currentOrder
  264. );
  265. }
  266. $this->mockery_setCurrentOrder($order);
  267. }
  268. /**
  269. * Store a mock and set its container reference
  270. *
  271. * @param \Mockery\Mock
  272. * @return \Mockery\Mock
  273. */
  274. public function rememberMock(\Mockery\MockInterface $mock)
  275. {
  276. if (!isset($this->_mocks[get_class($mock)])) {
  277. $this->_mocks[get_class($mock)] = $mock;
  278. } else {
  279. /**
  280. * This condition triggers for an instance mock where origin mock
  281. * is already remembered
  282. */
  283. $this->_mocks[] = $mock;
  284. }
  285. return $mock;
  286. }
  287. public function fetchMock($reference)
  288. {
  289. if (isset($this->_mocks[$reference])) return $this->_mocks[$reference];
  290. }
  291. protected function _getInstance($mockName)
  292. {
  293. if (!method_exists($mockName, '__construct')) {
  294. $return = new $mockName;
  295. return $return;
  296. }
  297. $return = unserialize(sprintf('O:%d:"%s":0:{}', strlen($mockName), $mockName));
  298. return $return;
  299. }
  300. }