PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/mockery/mockery/library/Mockery/Container.php

https://bitbucket.org/cnavalici/csvgenerator
PHP | 484 lines | 285 code | 56 blank | 143 comment | 42 complexity | 9475f5e8d84c38082cd1dba83dde2288 MD5 | raw file
Possible License(s): BSD-3-Clause
  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-2014 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. use Mockery\Generator\Generator;
  22. use Mockery\Generator\MockConfigurationBuilder;
  23. use Mockery\Loader\Loader as LoaderInterface;
  24. class Container
  25. {
  26. const BLOCKS = \Mockery::BLOCKS;
  27. /**
  28. * Store of mock objects
  29. *
  30. * @var array
  31. */
  32. protected $_mocks = array();
  33. /**
  34. * Order number of allocation
  35. *
  36. * @var int
  37. */
  38. protected $_allocatedOrder = 0;
  39. /**
  40. * Current ordered number
  41. *
  42. * @var int
  43. */
  44. protected $_currentOrder = 0;
  45. /**
  46. * Ordered groups
  47. *
  48. * @var array
  49. */
  50. protected $_groups = array();
  51. /**
  52. * @var Generator\Generator
  53. */
  54. protected $_generator;
  55. /**
  56. * @var LoaderInterface
  57. */
  58. protected $_loader;
  59. /**
  60. * @var array
  61. */
  62. protected $_namedMocks = array();
  63. public function __construct(Generator $generator = null, LoaderInterface $loader = null)
  64. {
  65. $this->_generator = $generator ?: \Mockery::getDefaultGenerator();
  66. $this->_loader = $loader ?: \Mockery::getDefaultLoader();
  67. }
  68. /**
  69. * Generates a new mock object for this container
  70. *
  71. * I apologies in advance for this. A God Method just fits the API which
  72. * doesn't require differentiating between classes, interfaces, abstracts,
  73. * names or partials - just so long as it's something that can be mocked.
  74. * I'll refactor it one day so it's easier to follow.
  75. *
  76. * @return \Mockery\Mock
  77. */
  78. public function mock()
  79. {
  80. $expectationClosure = null;
  81. $quickdefs = array();
  82. $constructorArgs = null;
  83. $blocks = array();
  84. $args = func_get_args();
  85. if (count($args) > 1) {
  86. $finalArg = end($args);
  87. reset($args);
  88. if (is_callable($finalArg) && is_object($finalArg)) {
  89. $expectationClosure = array_pop($args);
  90. }
  91. }
  92. $builder = new MockConfigurationBuilder();
  93. foreach ($args as $k => $arg) {
  94. if ($arg instanceof MockConfigurationBuilder) {
  95. $builder = $arg;
  96. unset($args[$k]);
  97. }
  98. }
  99. reset($args);
  100. $builder->setParameterOverrides(\Mockery::getConfiguration()->getInternalClassMethodParamMaps());
  101. while (count($args) > 0) {
  102. $arg = current($args);
  103. // check for multiple interfaces
  104. if (is_string($arg) && strpos($arg, ',') && !strpos($arg, ']')) {
  105. $interfaces = explode(',', str_replace(' ', '', $arg));
  106. foreach ($interfaces as $i) {
  107. if (!interface_exists($i, true) && !class_exists($i, true)) {
  108. throw new \Mockery\Exception(
  109. 'Class name follows the format for defining multiple'
  110. . ' interfaces, however one or more of the interfaces'
  111. . ' do not exist or are not included, or the base class'
  112. . ' (which you may omit from the mock definition) does not exist'
  113. );
  114. }
  115. }
  116. $builder->addTargets($interfaces);
  117. array_shift($args);
  118. continue;
  119. } elseif (is_string($arg) && substr($arg, 0, 6) == 'alias:') {
  120. $name = array_shift($args);
  121. $name = str_replace('alias:', '', $name);
  122. $builder->addTarget('stdClass');
  123. $builder->setName($name);
  124. continue;
  125. } elseif (is_string($arg) && substr($arg, 0, 9) == 'overload:') {
  126. $name = array_shift($args);
  127. $name = str_replace('overload:', '', $name);
  128. $builder->setInstanceMock(true);
  129. $builder->addTarget('stdClass');
  130. $builder->setName($name);
  131. continue;
  132. } elseif (is_string($arg) && substr($arg, strlen($arg)-1, 1) == ']') {
  133. $parts = explode('[', $arg);
  134. if (!class_exists($parts[0], true) && !interface_exists($parts[0], true)) {
  135. throw new \Mockery\Exception('Can only create a partial mock from'
  136. . ' an existing class or interface');
  137. }
  138. $class = $parts[0];
  139. $parts[1] = str_replace(' ','', $parts[1]);
  140. $partialMethods = explode(',', strtolower(rtrim($parts[1], ']')));
  141. $builder->addTarget($class);
  142. $builder->setWhiteListedMethods($partialMethods);
  143. array_shift($args);
  144. continue;
  145. } elseif (is_string($arg) && (class_exists($arg, true) || interface_exists($arg, true))) {
  146. $class = array_shift($args);
  147. $builder->addTarget($class);
  148. continue;
  149. } elseif (is_string($arg)) {
  150. $class = array_shift($args);
  151. $builder->addTarget($class);
  152. continue;
  153. } elseif (is_object($arg)) {
  154. $partial = array_shift($args);
  155. $builder->addTarget($partial);
  156. continue;
  157. } elseif (is_array($arg) && !empty($arg) && array_keys($arg) !== range(0, count($arg) - 1)) {
  158. // if associative array
  159. if(array_key_exists(self::BLOCKS, $arg)) $blocks = $arg[self::BLOCKS]; unset($arg[self::BLOCKS]);
  160. $quickdefs = array_shift($args);
  161. continue;
  162. } elseif (is_array($arg)) {
  163. $constructorArgs = array_shift($args);
  164. continue;
  165. }
  166. throw new \Mockery\Exception(
  167. 'Unable to parse arguments sent to '
  168. . get_class($this) . '::mock()'
  169. );
  170. }
  171. $builder->addBlackListedMethods($blocks);
  172. if (!is_null($constructorArgs)) {
  173. $builder->addBlackListedMethod("__construct"); // we need to pass through
  174. }
  175. if (!empty($partialMethods) && $constructorArgs === null) {
  176. $constructorArgs = array();
  177. }
  178. $config = $builder->getMockConfiguration();
  179. $this->checkForNamedMockClashes($config);
  180. $def = $this->getGenerator()->generate($config);
  181. if (class_exists($def->getClassName(), $attemptAutoload = false)) {
  182. $rfc = new \ReflectionClass($def->getClassName());
  183. if (!$rfc->implementsInterface("Mockery\MockInterface")) {
  184. throw new \Mockery\Exception\RuntimeException("Could not load mock {$def->getClassName()}, class already exists");
  185. }
  186. }
  187. $this->getLoader()->load($def);
  188. $mock = $this->_getInstance($def->getClassName(), $constructorArgs);
  189. $mock->mockery_init($this, $config->getTargetObject());
  190. if (!empty($quickdefs)) {
  191. $mock->shouldReceive($quickdefs)->byDefault();
  192. }
  193. if (!empty($expectationClosure)) {
  194. $expectationClosure($mock);
  195. }
  196. $this->rememberMock($mock);
  197. return $mock;
  198. }
  199. public function instanceMock()
  200. {
  201. }
  202. public function getLoader()
  203. {
  204. return $this->_loader;
  205. }
  206. public function getGenerator()
  207. {
  208. return $this->_generator;
  209. }
  210. /**
  211. * Tear down tasks for this container
  212. *
  213. * @return void
  214. */
  215. public function mockery_teardown()
  216. {
  217. try {
  218. $this->mockery_verify();
  219. } catch (\Exception $e) {
  220. $this->mockery_close();
  221. throw $e;
  222. }
  223. }
  224. /**
  225. * Verify the container mocks
  226. *
  227. * @return void
  228. */
  229. public function mockery_verify()
  230. {
  231. foreach($this->_mocks as $mock) {
  232. $mock->mockery_verify();
  233. }
  234. }
  235. /**
  236. * Reset the container to its original state
  237. *
  238. * @return void
  239. */
  240. public function mockery_close()
  241. {
  242. foreach($this->_mocks as $mock) {
  243. $mock->mockery_teardown();
  244. }
  245. $this->_mocks = array();
  246. }
  247. /**
  248. * Fetch the next available allocation order number
  249. *
  250. * @return int
  251. */
  252. public function mockery_allocateOrder()
  253. {
  254. $this->_allocatedOrder += 1;
  255. return $this->_allocatedOrder;
  256. }
  257. /**
  258. * Set ordering for a group
  259. *
  260. * @param mixed $group
  261. * @param int $order
  262. */
  263. public function mockery_setGroup($group, $order)
  264. {
  265. $this->_groups[$group] = $order;
  266. }
  267. /**
  268. * Fetch array of ordered groups
  269. *
  270. * @return array
  271. */
  272. public function mockery_getGroups()
  273. {
  274. return $this->_groups;
  275. }
  276. /**
  277. * Set current ordered number
  278. *
  279. * @param int $order
  280. * @return int The current order number that was set
  281. */
  282. public function mockery_setCurrentOrder($order)
  283. {
  284. $this->_currentOrder = $order;
  285. return $this->_currentOrder;
  286. }
  287. /**
  288. * Get current ordered number
  289. *
  290. * @return int
  291. */
  292. public function mockery_getCurrentOrder()
  293. {
  294. return $this->_currentOrder;
  295. }
  296. /**
  297. * Validate the current mock's ordering
  298. *
  299. * @param string $method
  300. * @param int $order
  301. * @throws \Mockery\Exception
  302. * @return void
  303. */
  304. public function mockery_validateOrder($method, $order, \Mockery\MockInterface $mock)
  305. {
  306. if ($order < $this->_currentOrder) {
  307. $exception = new \Mockery\Exception\InvalidOrderException(
  308. 'Method ' . $method . ' called out of order: expected order '
  309. . $order . ', was ' . $this->_currentOrder
  310. );
  311. $exception->setMock($mock)
  312. ->setMethodName($method)
  313. ->setExpectedOrder($order)
  314. ->setActualOrder($this->_currentOrder);
  315. throw $exception;
  316. }
  317. $this->mockery_setCurrentOrder($order);
  318. }
  319. /**
  320. * Gets the count of expectations on the mocks
  321. *
  322. * @return int
  323. */
  324. public function mockery_getExpectationCount()
  325. {
  326. $count = 0;
  327. foreach($this->_mocks as $mock) {
  328. $count += $mock->mockery_getExpectationCount();
  329. }
  330. return $count;
  331. }
  332. /**
  333. * Store a mock and set its container reference
  334. *
  335. * @param \Mockery\Mock
  336. * @return \Mockery\Mock
  337. */
  338. public function rememberMock(\Mockery\MockInterface $mock)
  339. {
  340. if (!isset($this->_mocks[get_class($mock)])) {
  341. $this->_mocks[get_class($mock)] = $mock;
  342. } else {
  343. /**
  344. * This condition triggers for an instance mock where origin mock
  345. * is already remembered
  346. */
  347. $this->_mocks[] = $mock;
  348. }
  349. return $mock;
  350. }
  351. /**
  352. * Retrieve the last remembered mock object, which is the same as saying
  353. * retrieve the current mock being programmed where you have yet to call
  354. * mock() to change it - thus why the method name is "self" since it will be
  355. * be used during the programming of the same mock.
  356. *
  357. * @return \Mockery\Mock
  358. */
  359. public function self()
  360. {
  361. $mocks = array_values($this->_mocks);
  362. $index = count($mocks) - 1;
  363. return $mocks[$index];
  364. }
  365. /**
  366. * Return a specific remembered mock according to the array index it
  367. * was stored to in this container instance
  368. *
  369. * @return \Mockery\Mock
  370. */
  371. public function fetchMock($reference)
  372. {
  373. if (isset($this->_mocks[$reference])) return $this->_mocks[$reference];
  374. }
  375. protected function _getInstance($mockName, $constructorArgs = null)
  376. {
  377. $r = new \ReflectionClass($mockName);
  378. if (null === $r->getConstructor()) {
  379. $return = new $mockName;
  380. return $return;
  381. }
  382. if ($constructorArgs !== null) {
  383. return $r->newInstanceArgs($constructorArgs);
  384. }
  385. $return = unserialize(sprintf('O:%d:"%s":0:{}', strlen($mockName), $mockName));
  386. return $return;
  387. }
  388. /**
  389. * Takes a class name and declares it
  390. *
  391. * @param string $fqcn
  392. */
  393. public function declareClass($fqcn)
  394. {
  395. if (false !== strpos($fqcn, '/')) {
  396. throw new \Mockery\Exception(
  397. 'Class name contains a forward slash instead of backslash needed '
  398. . 'when employing namespaces'
  399. );
  400. }
  401. if (false !== strpos($fqcn, "\\")) {
  402. $parts = array_filter(explode("\\", $fqcn), function ($part) {
  403. return $part !== "";
  404. });
  405. $cl = array_pop($parts);
  406. $ns = implode("\\", $parts);
  407. eval(" namespace $ns { class $cl {} }");
  408. } else {
  409. eval(" class $fqcn {} ");
  410. }
  411. }
  412. protected function checkForNamedMockClashes($config)
  413. {
  414. $name = $config->getName();
  415. if (!$name) {
  416. return;
  417. }
  418. $hash = $config->getHash();
  419. if (isset($this->_namedMocks[$name])) {
  420. if ($hash !== $this->_namedMocks[$name]) {
  421. throw new \Mockery\Exception(
  422. "The mock named '$name' has been already defined with a different mock configuration"
  423. );
  424. }
  425. }
  426. $this->_namedMocks[$name] = $hash;
  427. }
  428. }