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.

370 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__) . '/../../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. if (!defined('DEBUG')) {
  70. define('DEBUG', false);
  71. }
  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. if (!defined('DEBUG')) {
  87. define('DEBUG', false);
  88. }
  89. $this->setDriverGetConnectionMethod();
  90. $this->sql = 'PLAIN SQL';
  91. $result = $this->stmt->execute(array());
  92. $this->assertTrue($result);
  93. }
  94. /**
  95. * @runInSeparateProcess
  96. * @group MySQL
  97. */
  98. public function testFetchNoResult()
  99. {
  100. if (!defined('DEBUG')) {
  101. define('DEBUG', false);
  102. }
  103. $this->assertFalse($this->stmt->fetch());
  104. }
  105. /**
  106. * @runInSeparateProcess
  107. * @group MySQL
  108. */
  109. public function testDriverExecuteNoResult()
  110. {
  111. if (!defined('DEBUG')) {
  112. define('DEBUG', false);
  113. }
  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. if (!defined('DEBUG')) {
  125. define('DEBUG', false);
  126. }
  127. $this->setDriverGetConnectionMethod();
  128. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  129. $this->assertSame('OBJECT', $this->stmt->fetch());
  130. $this->assertSame('ARRAY', $this->stmt->fetch(Db::FETCH_NUM));
  131. $this->assertSame('ASSOC', $this->stmt->fetch(Db::FETCH_ASSOC));
  132. $this->assertSame('ARRAY', $this->stmt->fetch(Db::FETCH_BOTH));
  133. }
  134. /**
  135. * @runInSeparateProcess
  136. * @group MySQL
  137. */
  138. public function testFetchObject()
  139. {
  140. if (!defined('DEBUG')) {
  141. define('DEBUG', false);
  142. }
  143. $this->setDriverGetConnectionMethod();
  144. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  145. $this->assertSame('OBJECT', $this->stmt->fetchObject());
  146. }
  147. /**
  148. * @runInSeparateProcess
  149. * @group MySQL
  150. */
  151. public function testFetchPairs()
  152. {
  153. if (!defined('DEBUG')) {
  154. define('DEBUG', false);
  155. }
  156. $resultMock = $this->getMockBuilder('mysqli_result')
  157. ->disableOriginalConstructor()
  158. ->setMethods(array('fetch_array', 'close'))
  159. ->setMockClassName('Mysqli_Result_Mock')
  160. ->getMock();
  161. $resultMock
  162. ->expects($this->at(0))
  163. ->method('fetch_array')
  164. ->will($this->returnValue(array('pair', 'value')));
  165. $resultMock
  166. ->expects($this->at(1))
  167. ->method('fetch_array')
  168. ->will($this->returnValue(false));
  169. $resultMock
  170. ->expects($this->any())
  171. ->method('close')
  172. ->will($this->returnValue(TRUE));
  173. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  174. $mysqliMock
  175. ->expects($this->any())
  176. ->method('query')
  177. ->with($this->anything())
  178. ->will($this->returnValue($resultMock));
  179. $this->driver
  180. ->expects($this->any())
  181. ->method('getConnection')
  182. ->will($this->returnValue($mysqliMock));
  183. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  184. $this->assertSame(array('pair' => 'value'), $this->stmt->fetchPairs());
  185. }
  186. /**
  187. * @runInSeparateProcess
  188. */
  189. public function testFetchWithDebug()
  190. {
  191. if (!defined('DEBUG')) {
  192. define('DEBUG', true);
  193. }
  194. $this->setDriverGetConnectionMethod();
  195. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  196. $this->assertSame('OBJECT', $this->stmt->fetch());
  197. }
  198. /**
  199. * @runInSeparateProcess
  200. * @group MySQL
  201. */
  202. public function testClose()
  203. {
  204. if (!defined('DEBUG')) {
  205. define('DEBUG', false);
  206. }
  207. $this->assertAttributeEquals(null, 'result', $this->stmt);
  208. $this->setDriverGetConnectionMethod();
  209. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  210. $this->assertAttributeNotEquals(null, 'result', $this->stmt);
  211. $this->stmt->close();
  212. $this->assertAttributeEquals(null, 'result', $this->stmt);
  213. }
  214. /**
  215. * @group MySQL
  216. */
  217. public function testAffectedRows()
  218. {
  219. $mysqliMock = $this->getMockBuilder('MysqliDrvr');
  220. $mysqliMock->affected_rows = 'AFFECTED_ROWS';
  221. $this->driver
  222. ->expects($this->any())
  223. ->method('getConnection')
  224. ->will($this->returnValue($mysqliMock));
  225. $this->assertSame('AFFECTED_ROWS', $this->stmt->affectedRows());
  226. }
  227. /**
  228. * @group MySQL
  229. */
  230. public function testNumRowsNoResult()
  231. {
  232. $this->assertFalse($this->stmt->numRows());
  233. }
  234. /**
  235. * @runInSeparateProcess
  236. * @TODO: exception just for code coverage - could not mock mysqli properties
  237. * @group MySQL
  238. */
  239. public function testNumRows()
  240. {
  241. $this->markTestSkipped('Unable to execute a method or access a property of an incomplete object.');
  242. if (!defined('DEBUG')) {
  243. define('DEBUG', false);
  244. }
  245. $this->setDriverGetConnectionMethod();
  246. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  247. $this->assertNull($this->stmt->numRows());
  248. }
  249. /**
  250. * @runInSeparateProcess
  251. * @group MySQL
  252. */
  253. public function testFetchInvalidMode()
  254. {
  255. if (!defined('DEBUG')) {
  256. define('DEBUG', false);
  257. }
  258. $this->setDriverGetConnectionMethod();
  259. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  260. $this->setExpectedException('GeneralException');
  261. $this->stmt->fetch(324);
  262. }
  263. private function setDriverGetConnectionMethod()
  264. {
  265. $resultMock = $this->getMockBuilder('mysqli_result')
  266. ->disableOriginalConstructor()
  267. ->setMethods(array('fetch_object', 'fetch_array', 'fetch_assoc', 'close'))
  268. ->setMockClassName('Mysqli_Result_Mock')
  269. ->getMock();
  270. $resultMock
  271. ->expects($this->any())
  272. ->method('fetch_object')
  273. ->will($this->returnValue('OBJECT'));
  274. $resultMock
  275. ->expects($this->any())
  276. ->method('fetch_array')
  277. ->will($this->returnValue('ARRAY'));
  278. $resultMock
  279. ->expects($this->any())
  280. ->method('fetch_assoc')
  281. ->will($this->returnValue('ASSOC'));
  282. $resultMock
  283. ->expects($this->any())
  284. ->method('close')
  285. ->will($this->returnValue(TRUE));
  286. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  287. $mysqliMock
  288. ->expects($this->any())
  289. ->method('query')
  290. ->with($this->anything())
  291. ->will($this->returnValue($resultMock));
  292. $this->driver
  293. ->expects($this->any())
  294. ->method('getConnection')
  295. ->will($this->returnValue($mysqliMock));
  296. return $this;
  297. }
  298. private function setDriverGetConnectionWrongResultMethod()
  299. {
  300. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  301. $mysqliMock
  302. ->expects($this->any())
  303. ->method('query')
  304. ->with($this->anything())
  305. ->will($this->returnValue(false));
  306. $mysqliMock->error = 'ERROR';
  307. $mysqliMock->errno = 0;
  308. $this->driver
  309. ->expects($this->any())
  310. ->method('getConnection')
  311. ->will($this->returnValue($mysqliMock));
  312. return $this;
  313. }
  314. public function driverQuote($val)
  315. {
  316. return $val;
  317. }
  318. public function dbStatementAssemble($val)
  319. {
  320. return $val;
  321. }
  322. }