You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

359 lines
11 KiB

  1. <?php
  2. /*
  3. * @copyright NetMonsters <team@netmonsters.ru>
  4. * @link http://netmonsters.ru
  5. * @package Majestic
  6. * @subpackage UnitTests
  7. * @since 2011-11-4
  8. *
  9. * Unit tests for MySQLiStatement class
  10. */
  11. require_once dirname(__FILE__) . '/../../Registry.php';
  12. require_once dirname(__FILE__) . '/../../Config.php';
  13. require_once dirname(__FILE__) . '/../../util/profiler/CommandProfiler.php';
  14. require_once dirname(__FILE__) . '/../../util/profiler/Profiler.php';
  15. require_once dirname(__FILE__) . '/../../model/Db.php';
  16. require_once dirname(__FILE__) . '/../../model/DbDriver.php';
  17. require_once dirname(__FILE__) . '/../../model/DbStatement.php';
  18. require_once dirname(__FILE__) . '/../../model/MySQLiStatement.php';
  19. require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
  20. class MySQLiStatementTest extends PHPUnit_Framework_TestCase
  21. {
  22. /**
  23. * @var MySQLiDriver|PHPUnit_Framework_MockObject_MockObject
  24. */
  25. private $driver;
  26. /**
  27. * @var MySQLiStatement
  28. */
  29. private $stmt;
  30. private $sql;
  31. private $testData = array(
  32. array('one' => 11, 'two' => 12),
  33. array('one' => 21, 'two' => 22),
  34. array('one' => 31, 'two' => 32),
  35. );
  36. public function run(PHPUnit_Framework_TestResult $result = NULL)
  37. {
  38. $this->setPreserveGlobalState(false);
  39. return parent::run($result);
  40. }
  41. public function setUp()
  42. {
  43. if (!isset($this->stmt)) {
  44. $this->driver = $this->getMockBuilder('DbDriverMock')
  45. ->disableOriginalConstructor()
  46. ->setMethods(array('quote', 'getConnection'))
  47. ->getMock();
  48. $this->sql = 'SELECT * :place FROM :place AND :new';
  49. $this->stmt = new MySQLiStatement($this->driver, $this->sql);
  50. }
  51. }
  52. public function testBindParam()
  53. {
  54. $val = $this->getMockBuilder('DbExpr')
  55. ->disableOriginalConstructor()
  56. ->getMock();
  57. $this->assertFalse($this->stmt->bindParam('var', $val));
  58. $this->assertTrue($this->stmt->bindParam('place', $val));
  59. }
  60. public function testBindParamExceptionParam()
  61. {
  62. $val = 1;
  63. $this->setExpectedException('GeneralException', 'Placeholder must be an integer or string');
  64. $this->stmt->bindParam(array(), $val);
  65. }
  66. public function testBindParamExceptionWrongObject()
  67. {
  68. $val = $this->getMock('NotDbExpr');
  69. $this->setExpectedException('GeneralException', 'Objects excepts DbExpr not allowed.');
  70. $this->stmt->bindParam('paa', $val);
  71. }
  72. /**
  73. * @runInSeparateProcess
  74. */
  75. public function testExecute()
  76. {
  77. Config::set('PROFILER_DETAILS', false);
  78. $this->driver
  79. ->expects($this->any())
  80. ->method('quote')
  81. ->with($this->anything())
  82. ->will($this->returnCallback(array($this, 'driverQuote')));
  83. $this->setDriverGetConnectionMethod();
  84. $result = $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  85. $this->assertTrue($result);
  86. }
  87. /**
  88. * @runInSeparateProcess
  89. */
  90. public function testExecuteNoPlaceholders()
  91. {
  92. Config::set('PROFILER_DETAILS', false);
  93. $this->setDriverGetConnectionMethod();
  94. $this->sql = 'PLAIN SQL';
  95. $result = $this->stmt->execute(array());
  96. $this->assertTrue($result);
  97. }
  98. /**
  99. * @runInSeparateProcess
  100. * @group MySQL
  101. */
  102. public function testFetchNoResult()
  103. {
  104. Config::set('PROFILER_DETAILS', false);
  105. $this->assertFalse($this->stmt->fetch());
  106. }
  107. /**
  108. * @runInSeparateProcess
  109. * @group MySQL
  110. */
  111. public function testDriverExecuteNoResult()
  112. {
  113. Config::set('PROFILER_DETAILS', false);
  114. $this->setDriverGetConnectionWrongResultMethod();
  115. $this->setExpectedException('GeneralException', 'ERROR');
  116. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  117. }
  118. /**
  119. * @runInSeparateProcess
  120. * @group MySQL
  121. */
  122. public function testFetch()
  123. {
  124. Config::set('PROFILER_DETAILS', false);
  125. $this->setDriverGetConnectionMethod();
  126. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  127. $this->assertSame('OBJECT', $this->stmt->fetch());
  128. $this->assertSame('ARRAY', $this->stmt->fetch(Db::FETCH_NUM));
  129. $this->assertSame('ASSOC', $this->stmt->fetch(Db::FETCH_ASSOC));
  130. $this->assertSame('ARRAY', $this->stmt->fetch(Db::FETCH_BOTH));
  131. }
  132. /**
  133. * @runInSeparateProcess
  134. * @group MySQL
  135. */
  136. public function testFetchObject()
  137. {
  138. Config::set('PROFILER_DETAILS', false);
  139. $this->setDriverGetConnectionMethod();
  140. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  141. $this->assertSame('OBJECT', $this->stmt->fetchObject());
  142. }
  143. /**
  144. * @runInSeparateProcess
  145. * @group MySQL
  146. */
  147. public function testFetchPairs()
  148. {
  149. Config::set('PROFILER_DETAILS', false);
  150. $resultMock = $this->getMockBuilder('mysqli_result')
  151. ->disableOriginalConstructor()
  152. ->setMethods(array('fetch_array', 'close'))
  153. ->setMockClassName('Mysqli_Result_Mock')
  154. ->getMock();
  155. $resultMock
  156. ->expects($this->at(0))
  157. ->method('fetch_array')
  158. ->will($this->returnValue(array('pair', 'value')));
  159. $resultMock
  160. ->expects($this->at(1))
  161. ->method('fetch_array')
  162. ->will($this->returnValue(false));
  163. $resultMock
  164. ->expects($this->any())
  165. ->method('close')
  166. ->will($this->returnValue(TRUE));
  167. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  168. $mysqliMock
  169. ->expects($this->any())
  170. ->method('query')
  171. ->with($this->anything())
  172. ->will($this->returnValue($resultMock));
  173. $this->driver
  174. ->expects($this->any())
  175. ->method('getConnection')
  176. ->will($this->returnValue($mysqliMock));
  177. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  178. $this->assertSame(array('pair' => 'value'), $this->stmt->fetchPairs());
  179. }
  180. /**
  181. * @runInSeparateProcess
  182. */
  183. public function testFetchWithDebug()
  184. {
  185. Config::set('PROFILER', true);
  186. Config::set('PROFILER_DETAILS', true);
  187. $this->setDriverGetConnectionMethod();
  188. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  189. $this->assertSame('OBJECT', $this->stmt->fetch());
  190. $this->assertContains('Queries: 1', Profiler::getInstance()->getCli());
  191. }
  192. /**
  193. * @runInSeparateProcess
  194. * @group MySQL
  195. */
  196. public function testClose()
  197. {
  198. Config::set('PROFILER', true);
  199. Config::set('PROFILER_DETAILS', false);
  200. $this->assertAttributeEquals(null, 'result', $this->stmt);
  201. $this->setDriverGetConnectionMethod();
  202. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  203. $this->assertAttributeNotEquals(null, 'result', $this->stmt);
  204. $this->stmt->close();
  205. $this->assertAttributeEquals(null, 'result', $this->stmt);
  206. $this->assertContains('Queries not counted.', Profiler::getInstance()->getCli());
  207. }
  208. /**
  209. * @group MySQL
  210. */
  211. public function testAffectedRows()
  212. {
  213. $mysqliMock = $this->getMockBuilder('MysqliDrvr');
  214. $mysqliMock->affected_rows = 'AFFECTED_ROWS';
  215. $this->driver
  216. ->expects($this->any())
  217. ->method('getConnection')
  218. ->will($this->returnValue($mysqliMock));
  219. $this->assertSame('AFFECTED_ROWS', $this->stmt->affectedRows());
  220. }
  221. /**
  222. * @group MySQL
  223. */
  224. public function testNumRowsNoResult()
  225. {
  226. $this->assertFalse($this->stmt->numRows());
  227. }
  228. /**
  229. * @runInSeparateProcess
  230. * @TODO: exception just for code coverage - could not mock mysqli properties
  231. * @group MySQL
  232. */
  233. public function testNumRows()
  234. {
  235. $this->markTestSkipped('Unable to execute a method or access a property of an incomplete object.');
  236. Config::set('PROFILER_DETAILS', false);
  237. $this->setDriverGetConnectionMethod();
  238. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  239. $this->assertNull($this->stmt->numRows());
  240. }
  241. /**
  242. * @runInSeparateProcess
  243. * @group MySQL
  244. */
  245. public function testFetchInvalidMode()
  246. {
  247. Config::set('PROFILER_DETAILS', false);
  248. $this->setDriverGetConnectionMethod();
  249. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  250. $this->setExpectedException('GeneralException');
  251. $this->stmt->fetch(324);
  252. }
  253. private function setDriverGetConnectionMethod()
  254. {
  255. $resultMock = $this->getMockBuilder('mysqli_result')
  256. ->disableOriginalConstructor()
  257. ->setMethods(array('fetch_object', 'fetch_array', 'fetch_assoc', 'close'))
  258. ->setMockClassName('Mysqli_Result_Mock')
  259. ->getMock();
  260. $resultMock
  261. ->expects($this->any())
  262. ->method('fetch_object')
  263. ->will($this->returnValue('OBJECT'));
  264. $resultMock
  265. ->expects($this->any())
  266. ->method('fetch_array')
  267. ->will($this->returnValue('ARRAY'));
  268. $resultMock
  269. ->expects($this->any())
  270. ->method('fetch_assoc')
  271. ->will($this->returnValue('ASSOC'));
  272. $resultMock
  273. ->expects($this->any())
  274. ->method('close')
  275. ->will($this->returnValue(TRUE));
  276. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  277. $mysqliMock
  278. ->expects($this->any())
  279. ->method('query')
  280. ->with($this->anything())
  281. ->will($this->returnValue($resultMock));
  282. $this->driver
  283. ->expects($this->any())
  284. ->method('getConnection')
  285. ->will($this->returnValue($mysqliMock));
  286. return $this;
  287. }
  288. private function setDriverGetConnectionWrongResultMethod()
  289. {
  290. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  291. $mysqliMock
  292. ->expects($this->any())
  293. ->method('query')
  294. ->with($this->anything())
  295. ->will($this->returnValue(false));
  296. $mysqliMock->error = 'ERROR';
  297. $mysqliMock->errno = 0;
  298. $this->driver
  299. ->expects($this->any())
  300. ->method('getConnection')
  301. ->will($this->returnValue($mysqliMock));
  302. return $this;
  303. }
  304. public function driverQuote($val)
  305. {
  306. return $val;
  307. }
  308. public function dbStatementAssemble($val)
  309. {
  310. return $val;
  311. }
  312. }