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.

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