CakeTestCase.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. <?php
  2. /**
  3. * CakeTestCase file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  8. * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * Redistributions of files must retain the above copyright notice
  12. *
  13. * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  15. * @package Cake.TestSuite
  16. * @since CakePHP(tm) v 1.2.0.4667
  17. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  18. */
  19. App::uses('CakeFixtureManager', 'TestSuite/Fixture');
  20. App::uses('CakeTestFixture', 'TestSuite/Fixture');
  21. /**
  22. * CakeTestCase class
  23. *
  24. * @package Cake.TestSuite
  25. */
  26. abstract class CakeTestCase extends PHPUnit_Framework_TestCase {
  27. /**
  28. * The class responsible for managing the creation, loading and removing of fixtures
  29. *
  30. * @var CakeFixtureManager
  31. */
  32. public $fixtureManager = null;
  33. /**
  34. * By default, all fixtures attached to this class will be truncated and reloaded after each test.
  35. * Set this to false to handle manually
  36. *
  37. * @var array
  38. */
  39. public $autoFixtures = true;
  40. /**
  41. * Set this to false to avoid tables to be dropped if they already exist
  42. *
  43. * @var boolean
  44. */
  45. public $dropTables = true;
  46. /**
  47. * Configure values to restore at end of test.
  48. *
  49. * @var array
  50. */
  51. protected $_configure = array();
  52. /**
  53. * Path settings to restore at the end of the test.
  54. *
  55. * @var array
  56. */
  57. protected $_pathRestore = array();
  58. /**
  59. * Runs the test case and collects the results in a TestResult object.
  60. * If no TestResult object is passed a new one will be created.
  61. * This method is run for each test method in this class
  62. *
  63. * @param PHPUnit_Framework_TestResult $result
  64. * @return PHPUnit_Framework_TestResult
  65. * @throws InvalidArgumentException
  66. */
  67. public function run(PHPUnit_Framework_TestResult $result = null) {
  68. if (!empty($this->fixtureManager)) {
  69. $this->fixtureManager->load($this);
  70. }
  71. $result = parent::run($result);
  72. if (!empty($this->fixtureManager)) {
  73. $this->fixtureManager->unload($this);
  74. }
  75. return $result;
  76. }
  77. /**
  78. * Called when a test case method is about to start (to be overridden when needed.)
  79. *
  80. * @param string $method Test method about to get executed.
  81. * @return void
  82. */
  83. public function startTest($method) {
  84. }
  85. /**
  86. * Called when a test case method has been executed (to be overridden when needed.)
  87. *
  88. * @param string $method Test method about that was executed.
  89. * @return void
  90. */
  91. public function endTest($method) {
  92. }
  93. /**
  94. * Overrides SimpleTestCase::skipIf to provide a boolean return value
  95. *
  96. * @param boolean $shouldSkip
  97. * @param string $message
  98. * @return boolean
  99. */
  100. public function skipIf($shouldSkip, $message = '') {
  101. if ($shouldSkip) {
  102. $this->markTestSkipped($message);
  103. }
  104. return $shouldSkip;
  105. }
  106. /**
  107. * Setup the test case, backup the static object values so they can be restored.
  108. * Specifically backs up the contents of Configure and paths in App if they have
  109. * not already been backed up.
  110. *
  111. * @return void
  112. */
  113. public function setUp() {
  114. parent::setUp();
  115. if (empty($this->_configure)) {
  116. $this->_configure = Configure::read();
  117. }
  118. if (empty($this->_pathRestore)) {
  119. $this->_pathRestore = App::paths();
  120. }
  121. if (class_exists('Router', false)) {
  122. Router::reload();
  123. }
  124. }
  125. /**
  126. * teardown any static object changes and restore them.
  127. *
  128. * @return void
  129. */
  130. public function tearDown() {
  131. parent::tearDown();
  132. App::build($this->_pathRestore, App::RESET);
  133. if (class_exists('ClassRegistry', false)) {
  134. ClassRegistry::flush();
  135. }
  136. if (!empty($this->_configure)) {
  137. Configure::clear();
  138. Configure::write($this->_configure);
  139. }
  140. if (isset($_GET['debug']) && $_GET['debug']) {
  141. ob_flush();
  142. }
  143. }
  144. /**
  145. * See CakeTestSuiteDispatcher::date()
  146. *
  147. * @param string $format format to be used.
  148. * @return string
  149. */
  150. public static function date($format = 'Y-m-d H:i:s') {
  151. return CakeTestSuiteDispatcher::date($format);
  152. }
  153. // @codingStandardsIgnoreStart PHPUnit overrides don't match CakePHP
  154. /**
  155. * Announces the start of a test.
  156. *
  157. * @return void
  158. */
  159. protected function assertPreConditions() {
  160. parent::assertPreConditions();
  161. $this->startTest($this->getName());
  162. }
  163. /**
  164. * Announces the end of a test.
  165. *
  166. * @return void
  167. */
  168. protected function assertPostConditions() {
  169. parent::assertPostConditions();
  170. $this->endTest($this->getName());
  171. }
  172. // @codingStandardsIgnoreEnd
  173. /**
  174. * Chooses which fixtures to load for a given test
  175. *
  176. * @param string $fixture Each parameter is a model name that corresponds to a
  177. * fixture, i.e. 'Post', 'Author', etc.
  178. * @return void
  179. * @see CakeTestCase::$autoFixtures
  180. * @throws Exception when no fixture manager is available.
  181. */
  182. public function loadFixtures() {
  183. if (empty($this->fixtureManager)) {
  184. throw new Exception(__d('cake_dev', 'No fixture manager to load the test fixture'));
  185. }
  186. $args = func_get_args();
  187. foreach ($args as $class) {
  188. $this->fixtureManager->loadSingle($class);
  189. }
  190. }
  191. /**
  192. * Assert text equality, ignoring differences in newlines.
  193. * Helpful for doing cross platform tests of blocks of text.
  194. *
  195. * @param string $expected The expected value.
  196. * @param string $result The actual value.
  197. * @param message The message to use for failure.
  198. * @return boolean
  199. */
  200. public function assertTextNotEquals($expected, $result, $message = '') {
  201. $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
  202. $result = str_replace(array("\r\n", "\r"), "\n", $result);
  203. return $this->assertNotEquals($expected, $result, $message);
  204. }
  205. /**
  206. * Assert text equality, ignoring differences in newlines.
  207. * Helpful for doing cross platform tests of blocks of text.
  208. *
  209. * @param string $expected The expected value.
  210. * @param string $result The actual value.
  211. * @param message The message to use for failure.
  212. * @return boolean
  213. */
  214. public function assertTextEquals($expected, $result, $message = '') {
  215. $expected = str_replace(array("\r\n", "\r"), "\n", $expected);
  216. $result = str_replace(array("\r\n", "\r"), "\n", $result);
  217. return $this->assertEquals($expected, $result, $message);
  218. }
  219. /**
  220. * Asserts that a string starts with a given prefix, ignoring differences in newlines.
  221. * Helpful for doing cross platform tests of blocks of text.
  222. *
  223. * @param string $prefix
  224. * @param string $string
  225. * @param string $message
  226. * @return boolean
  227. */
  228. public function assertTextStartsWith($prefix, $string, $message = '') {
  229. $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
  230. $string = str_replace(array("\r\n", "\r"), "\n", $string);
  231. return $this->assertStringStartsWith($prefix, $string, $message);
  232. }
  233. /**
  234. * Asserts that a string starts not with a given prefix, ignoring differences in newlines.
  235. * Helpful for doing cross platform tests of blocks of text.
  236. *
  237. * @param string $prefix
  238. * @param string $string
  239. * @param string $message
  240. * @return boolean
  241. */
  242. public function assertTextStartsNotWith($prefix, $string, $message = '') {
  243. $prefix = str_replace(array("\r\n", "\r"), "\n", $prefix);
  244. $string = str_replace(array("\r\n", "\r"), "\n", $string);
  245. return $this->assertStringStartsNotWith($prefix, $string, $message);
  246. }
  247. /**
  248. * Asserts that a string ends with a given prefix, ignoring differences in newlines.
  249. * Helpful for doing cross platform tests of blocks of text.
  250. *
  251. * @param string $suffix
  252. * @param string $string
  253. * @param string $message
  254. * @return boolean
  255. */
  256. public function assertTextEndsWith($suffix, $string, $message = '') {
  257. $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
  258. $string = str_replace(array("\r\n", "\r"), "\n", $string);
  259. return $this->assertStringEndsWith($suffix, $string, $message);
  260. }
  261. /**
  262. * Asserts that a string ends not with a given prefix, ignoring differences in newlines.
  263. * Helpful for doing cross platform tests of blocks of text.
  264. *
  265. * @param string $suffix
  266. * @param string $string
  267. * @param string $message
  268. * @return boolean
  269. */
  270. public function assertTextEndsNotWith($suffix, $string, $message = '') {
  271. $suffix = str_replace(array("\r\n", "\r"), "\n", $suffix);
  272. $string = str_replace(array("\r\n", "\r"), "\n", $string);
  273. return $this->assertStringEndsNotWith($suffix, $string, $message);
  274. }
  275. /**
  276. * Assert that a string contains another string, ignoring differences in newlines.
  277. * Helpful for doing cross platform tests of blocks of text.
  278. *
  279. * @param string $needle
  280. * @param string $haystack
  281. * @param string $message
  282. * @param boolean $ignoreCase
  283. * @return boolean
  284. */
  285. public function assertTextContains($needle, $haystack, $message = '', $ignoreCase = false) {
  286. $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
  287. $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
  288. return $this->assertContains($needle, $haystack, $message, $ignoreCase);
  289. }
  290. /**
  291. * Assert that a text doesn't contain another text, ignoring differences in newlines.
  292. * Helpful for doing cross platform tests of blocks of text.
  293. *
  294. * @param string $needle
  295. * @param string $haystack
  296. * @param string $message
  297. * @param boolean $ignoreCase
  298. * @return boolean
  299. */
  300. public function assertTextNotContains($needle, $haystack, $message = '', $ignoreCase = false) {
  301. $needle = str_replace(array("\r\n", "\r"), "\n", $needle);
  302. $haystack = str_replace(array("\r\n", "\r"), "\n", $haystack);
  303. return $this->assertNotContains($needle, $haystack, $message, $ignoreCase);
  304. }
  305. /**
  306. * Takes an array $expected and generates a regex from it to match the provided $string.
  307. * Samples for $expected:
  308. *
  309. * Checks for an input tag with a name attribute (contains any non-empty value) and an id
  310. * attribute that contains 'my-input':
  311. * array('input' => array('name', 'id' => 'my-input'))
  312. *
  313. * Checks for two p elements with some text in them:
  314. * array(
  315. * array('p' => true),
  316. * 'textA',
  317. * '/p',
  318. * array('p' => true),
  319. * 'textB',
  320. * '/p'
  321. * )
  322. *
  323. * You can also specify a pattern expression as part of the attribute values, or the tag
  324. * being defined, if you prepend the value with preg: and enclose it with slashes, like so:
  325. * array(
  326. * array('input' => array('name', 'id' => 'preg:/FieldName\d+/')),
  327. * 'preg:/My\s+field/'
  328. * )
  329. *
  330. * Important: This function is very forgiving about whitespace and also accepts any
  331. * permutation of attribute order. It will also allow whitespace between specified tags.
  332. *
  333. * @param string $string An HTML/XHTML/XML string
  334. * @param array $expected An array, see above
  335. * @param string $message SimpleTest failure output string
  336. * @return boolean
  337. */
  338. public function assertTags($string, $expected, $fullDebug = false) {
  339. $regex = array();
  340. $normalized = array();
  341. foreach ((array)$expected as $key => $val) {
  342. if (!is_numeric($key)) {
  343. $normalized[] = array($key => $val);
  344. } else {
  345. $normalized[] = $val;
  346. }
  347. }
  348. $i = 0;
  349. foreach ($normalized as $tags) {
  350. if (!is_array($tags)) {
  351. $tags = (string)$tags;
  352. }
  353. $i++;
  354. if (is_string($tags) && $tags{0} == '<') {
  355. $tags = array(substr($tags, 1) => array());
  356. } elseif (is_string($tags)) {
  357. $tagsTrimmed = preg_replace('/\s+/m', '', $tags);
  358. if (preg_match('/^\*?\//', $tags, $match) && $tagsTrimmed !== '//') {
  359. $prefix = array(null, null);
  360. if ($match[0] == '*/') {
  361. $prefix = array('Anything, ', '.*?');
  362. }
  363. $regex[] = array(
  364. sprintf('%sClose %s tag', $prefix[0], substr($tags, strlen($match[0]))),
  365. sprintf('%s<[\s]*\/[\s]*%s[\s]*>[\n\r]*', $prefix[1], substr($tags, strlen($match[0]))),
  366. $i,
  367. );
  368. continue;
  369. }
  370. if (!empty($tags) && preg_match('/^preg\:\/(.+)\/$/i', $tags, $matches)) {
  371. $tags = $matches[1];
  372. $type = 'Regex matches';
  373. } else {
  374. $tags = preg_quote($tags, '/');
  375. $type = 'Text equals';
  376. }
  377. $regex[] = array(
  378. sprintf('%s "%s"', $type, $tags),
  379. $tags,
  380. $i,
  381. );
  382. continue;
  383. }
  384. foreach ($tags as $tag => $attributes) {
  385. $regex[] = array(
  386. sprintf('Open %s tag', $tag),
  387. sprintf('[\s]*<%s', preg_quote($tag, '/')),
  388. $i,
  389. );
  390. if ($attributes === true) {
  391. $attributes = array();
  392. }
  393. $attrs = array();
  394. $explanations = array();
  395. $i = 1;
  396. foreach ($attributes as $attr => $val) {
  397. if (is_numeric($attr) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
  398. $attrs[] = $matches[1];
  399. $explanations[] = sprintf('Regex "%s" matches', $matches[1]);
  400. continue;
  401. } else {
  402. $quotes = '["\']';
  403. if (is_numeric($attr)) {
  404. $attr = $val;
  405. $val = '.+?';
  406. $explanations[] = sprintf('Attribute "%s" present', $attr);
  407. } elseif (!empty($val) && preg_match('/^preg\:\/(.+)\/$/i', $val, $matches)) {
  408. $quotes = '["\']?';
  409. $val = $matches[1];
  410. $explanations[] = sprintf('Attribute "%s" matches "%s"', $attr, $val);
  411. } else {
  412. $explanations[] = sprintf('Attribute "%s" == "%s"', $attr, $val);
  413. $val = preg_quote($val, '/');
  414. }
  415. $attrs[] = '[\s]+' . preg_quote($attr, '/') . '=' . $quotes . $val . $quotes;
  416. }
  417. $i++;
  418. }
  419. if ($attrs) {
  420. $permutations = $this->_arrayPermute($attrs);
  421. $permutationTokens = array();
  422. foreach ($permutations as $permutation) {
  423. $permutationTokens[] = implode('', $permutation);
  424. }
  425. $regex[] = array(
  426. sprintf('%s', implode(', ', $explanations)),
  427. $permutationTokens,
  428. $i,
  429. );
  430. }
  431. $regex[] = array(
  432. sprintf('End %s tag', $tag),
  433. '[\s]*\/?[\s]*>[\n\r]*',
  434. $i,
  435. );
  436. }
  437. }
  438. foreach ($regex as $i => $assertation) {
  439. list($description, $expressions, $itemNum) = $assertation;
  440. $matches = false;
  441. foreach ((array)$expressions as $expression) {
  442. if (preg_match(sprintf('/^%s/s', $expression), $string, $match)) {
  443. $matches = true;
  444. $string = substr($string, strlen($match[0]));
  445. break;
  446. }
  447. }
  448. if (!$matches) {
  449. $this->assertTrue(false, sprintf('Item #%d / regex #%d failed: %s', $itemNum, $i, $description));
  450. if ($fullDebug) {
  451. debug($string, true);
  452. debug($regex, true);
  453. }
  454. return false;
  455. }
  456. }
  457. $this->assertTrue(true, '%s');
  458. return true;
  459. }
  460. /**
  461. * Generates all permutation of an array $items and returns them in a new array.
  462. *
  463. * @param array $items An array of items
  464. * @param array $perms
  465. * @return array
  466. */
  467. protected function _arrayPermute($items, $perms = array()) {
  468. static $permuted;
  469. if (empty($perms)) {
  470. $permuted = array();
  471. }
  472. if (empty($items)) {
  473. $permuted[] = $perms;
  474. } else {
  475. $numItems = count($items) - 1;
  476. for ($i = $numItems; $i >= 0; --$i) {
  477. $newItems = $items;
  478. $newPerms = $perms;
  479. list($tmp) = array_splice($newItems, $i, 1);
  480. array_unshift($newPerms, $tmp);
  481. $this->_arrayPermute($newItems, $newPerms);
  482. }
  483. return $permuted;
  484. }
  485. }
  486. // @codingStandardsIgnoreStart
  487. /**
  488. * Compatibility wrapper function for assertEquals
  489. *
  490. *
  491. * @param mixed $result
  492. * @param mixed $expected
  493. * @param string $message the text to display if the assertion is not correct
  494. * @return void
  495. */
  496. protected static function assertEqual($result, $expected, $message = '') {
  497. return self::assertEquals($expected, $result, $message);
  498. }
  499. /**
  500. * Compatibility wrapper function for assertNotEquals
  501. *
  502. * @param mixed $result
  503. * @param mixed $expected
  504. * @param string $message the text to display if the assertion is not correct
  505. * @return void
  506. */
  507. protected static function assertNotEqual($result, $expected, $message = '') {
  508. return self::assertNotEquals($expected, $result, $message);
  509. }
  510. /**
  511. * Compatibility wrapper function for assertRegexp
  512. *
  513. * @param mixed $pattern a regular expression
  514. * @param string $string the text to be matched
  515. * @param string $message the text to display if the assertion is not correct
  516. * @return void
  517. */
  518. protected static function assertPattern($pattern, $string, $message = '') {
  519. return self::assertRegExp($pattern, $string, $message);
  520. }
  521. /**
  522. * Compatibility wrapper function for assertEquals
  523. *
  524. * @param mixed $actual
  525. * @param mixed $expected
  526. * @param string $message the text to display if the assertion is not correct
  527. * @return void
  528. */
  529. protected static function assertIdentical($actual, $expected, $message = '') {
  530. return self::assertSame($expected, $actual, $message);
  531. }
  532. /**
  533. * Compatibility wrapper function for assertNotEquals
  534. *
  535. * @param mixed $actual
  536. * @param mixed $expected
  537. * @param string $message the text to display if the assertion is not correct
  538. * @return void
  539. */
  540. protected static function assertNotIdentical($actual, $expected, $message = '') {
  541. return self::assertNotSame($expected, $actual, $message);
  542. }
  543. /**
  544. * Compatibility wrapper function for assertNotRegExp
  545. *
  546. * @param mixed $pattern a regular expression
  547. * @param string $string the text to be matched
  548. * @param string $message the text to display if the assertion is not correct
  549. * @return void
  550. */
  551. protected static function assertNoPattern($pattern, $string, $message = '') {
  552. return self::assertNotRegExp($pattern, $string, $message);
  553. }
  554. /**
  555. * assert no errors
  556. */
  557. protected function assertNoErrors() {
  558. }
  559. /**
  560. * Compatibility wrapper function for setExpectedException
  561. *
  562. * @param mixed $expected the name of the Exception or error
  563. * @param string $message the text to display if the assertion is not correct
  564. * @return void
  565. */
  566. protected function expectError($expected = false, $message = '') {
  567. if (!$expected) {
  568. $expected = 'Exception';
  569. }
  570. $this->setExpectedException($expected, $message);
  571. }
  572. /**
  573. * Compatibility wrapper function for setExpectedException
  574. *
  575. * @param mixed $expected the name of the Exception
  576. * @param string $message the text to display if the assertion is not correct
  577. * @return void
  578. */
  579. protected function expectException($name = 'Exception', $message = '') {
  580. $this->setExpectedException($name, $message);
  581. }
  582. /**
  583. * Compatibility wrapper function for assertSame
  584. *
  585. * @param mixed $first
  586. * @param mixed $second
  587. * @param string $message the text to display if the assertion is not correct
  588. * @return void
  589. */
  590. protected static function assertReference(&$first, &$second, $message = '') {
  591. return self::assertSame($first, $second, $message);
  592. }
  593. /**
  594. * Compatibility wrapper for assertIsA
  595. *
  596. * @param string $object
  597. * @param string $type
  598. * @param string $message
  599. * @return void
  600. */
  601. protected static function assertIsA($object, $type, $message = '') {
  602. return self::assertInstanceOf($type, $object, $message);
  603. }
  604. /**
  605. * Compatibility function to test if value is between an acceptable range
  606. *
  607. * @param mixed $result
  608. * @param mixed $expected
  609. * @param mixed $margin the rage of acceptation
  610. * @param string $message the text to display if the assertion is not correct
  611. * @return void
  612. */
  613. protected static function assertWithinMargin($result, $expected, $margin, $message = '') {
  614. $upper = $result + $margin;
  615. $lower = $result - $margin;
  616. return self::assertTrue((($expected <= $upper) && ($expected >= $lower)), $message);
  617. }
  618. /**
  619. * Compatibility function for skipping.
  620. *
  621. * @param boolean $condition Condition to trigger skipping
  622. * @param string $message Message for skip
  623. * @return boolean
  624. */
  625. protected function skipUnless($condition, $message = '') {
  626. if (!$condition) {
  627. $this->markTestSkipped($message);
  628. }
  629. return $condition;
  630. }
  631. // @codingStandardsIgnoreEnd
  632. /**
  633. * Mock a model, maintain fixtures and table association
  634. *
  635. * @param string $model
  636. * @param mixed $methods
  637. * @param mixed $config
  638. * @return Model
  639. */
  640. public function getMockForModel($model, $methods = array(), $config = null) {
  641. if (is_null($config)) {
  642. $config = ClassRegistry::config('Model');
  643. }
  644. list($plugin, $name) = pluginSplit($model, true);
  645. App::uses($name, $plugin . 'Model');
  646. $config = array_merge((array)$config, array('name' => $name));
  647. $mock = $this->getMock($name, $methods, array($config));
  648. ClassRegistry::removeObject($name);
  649. ClassRegistry::addObject($name, $mock);
  650. return $mock;
  651. }
  652. }