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.

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