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.

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