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.

363 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. class MySQLiStatementTest extends PHPUnit_Framework_TestCase
  18. {
  19. private $driver;
  20. private $stmt;
  21. private $sql;
  22. private $testData = array(
  23. array('one' => 11, 'two' => 12),
  24. array('one' => 21, 'two' => 22),
  25. array('one' => 31, 'two' => 32),
  26. );
  27. public function run(PHPUnit_Framework_TestResult $result = NULL)
  28. {
  29. $this->setPreserveGlobalState(false);
  30. return parent::run($result);
  31. }
  32. public function setUp()
  33. {
  34. if (!isset($this->stmt)) {
  35. $this->driver = $this->getMockBuilder('DbDriverMock')
  36. ->disableOriginalConstructor()
  37. ->setMethods(array('quote', 'getConnection'))
  38. ->getMock();
  39. $this->sql = 'SELECT * :place FROM :place AND :new';
  40. $this->stmt = new MySQLiStatement($this->driver, $this->sql);
  41. }
  42. }
  43. public function testBindParam()
  44. {
  45. $val = $this->getMockBuilder('DbExpr')
  46. ->disableOriginalConstructor()
  47. ->getMock();
  48. $this->assertFalse($this->stmt->bindParam('var', $val));
  49. $this->assertTrue($this->stmt->bindParam('place', $val));
  50. }
  51. /**
  52. * @expectedException Exception
  53. * @expectedExceptionMessage Placeholder must be an array or string
  54. * @TODO: change Exception Message 'Placeholder must be an array or string' - no arrays available
  55. */
  56. public function testBindParamExceptionParam()
  57. {
  58. $val = 1;
  59. $this->stmt->bindParam(array(), $val);
  60. }
  61. /**
  62. * @expectedException Exception
  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->assertEquals('SELECT * place_val FROM place_val AND new_val', $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->assertEquals('PLAIN SQL', $result);
  99. }
  100. /**
  101. * @runInSeparateProcess
  102. */
  103. public function testFetchNoResult()
  104. {
  105. if (!defined('DEBUG')) {
  106. define('DEBUG', false);
  107. }
  108. $this->assertFalse($this->stmt->fetch());
  109. }
  110. /**
  111. * @runInSeparateProcess
  112. * @expectedException Exception
  113. * @expectedExceptionMessage ERROR
  114. */
  115. public function testDriverExecuteNoResult()
  116. {
  117. if (!defined('DEBUG')) {
  118. define('DEBUG', false);
  119. }
  120. $this->setDriverGetConnectionWrongResultMethod();
  121. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  122. }
  123. /**
  124. * @runInSeparateProcess
  125. */
  126. public function testFetch()
  127. {
  128. if (!defined('DEBUG')) {
  129. define('DEBUG', false);
  130. }
  131. $this->setDriverGetConnectionMethod();
  132. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  133. $this->assertEquals('OBJECT', $this->stmt->fetch());
  134. $this->assertEquals('ARRAY', $this->stmt->fetch(Db::FETCH_NUM));
  135. $this->assertEquals('ASSOC', $this->stmt->fetch(Db::FETCH_ASSOC));
  136. $this->assertEquals('ARRAY', $this->stmt->fetch(Db::FETCH_BOTH));
  137. }
  138. /**
  139. * @runInSeparateProcess
  140. */
  141. public function testFetchObject()
  142. {
  143. if (!defined('DEBUG')) {
  144. define('DEBUG', false);
  145. }
  146. $this->setDriverGetConnectionMethod();
  147. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  148. $this->assertEquals('OBJECT', $this->stmt->fetchObject());
  149. }
  150. /**
  151. * @runInSeparateProcess
  152. */
  153. public function testFetchPairs()
  154. {
  155. if (!defined('DEBUG')) {
  156. define('DEBUG', false);
  157. }
  158. $resultMock = $this->getMockBuilder('mysqli_result')
  159. ->disableOriginalConstructor()
  160. ->setMethods(array('fetch_array', 'close'))
  161. ->setMockClassName('Mysqli_Result_Mock')
  162. ->getMock();
  163. $resultMock
  164. ->expects($this->at(0))
  165. ->method('fetch_array')
  166. ->will($this->returnValue(array('pair', 'value')));
  167. $resultMock
  168. ->expects($this->at(1))
  169. ->method('fetch_array')
  170. ->will($this->returnValue(false));
  171. $resultMock
  172. ->expects($this->any())
  173. ->method('close')
  174. ->will($this->returnValue(TRUE));
  175. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  176. $mysqliMock
  177. ->expects($this->any())
  178. ->method('query')
  179. ->with($this->anything())
  180. ->will($this->returnValue($resultMock));
  181. $this->driver
  182. ->expects($this->any())
  183. ->method('getConnection')
  184. ->will($this->returnValue($mysqliMock));
  185. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  186. $this->assertEquals(array('pair' => 'value'), $this->stmt->fetchPairs());
  187. }
  188. /**
  189. * @runInSeparateProcess
  190. */
  191. public function testFetchWithDebug()
  192. {
  193. if (!defined('DEBUG')) {
  194. define('DEBUG', true);
  195. }
  196. $this->setDriverGetConnectionMethod();
  197. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  198. $this->assertEquals('OBJECT', $this->stmt->fetch());
  199. }
  200. /**
  201. * @runInSeparateProcess
  202. */
  203. public function testClose()
  204. {
  205. if (!defined('DEBUG')) {
  206. define('DEBUG', false);
  207. }
  208. $this->assertAttributeEquals(null, 'result', $this->stmt);
  209. $this->setDriverGetConnectionMethod();
  210. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  211. $this->assertAttributeNotEquals(null, 'result', $this->stmt);
  212. $this->stmt->close();
  213. $this->assertAttributeEquals(null, 'result', $this->stmt);
  214. }
  215. public function testAffectedRows()
  216. {
  217. $mysqliMock = $this->getMockBuilder('MysqliDrvr');
  218. $mysqliMock->affected_rows = 'AFFECTED_ROWS';
  219. $this->driver
  220. ->expects($this->any())
  221. ->method('getConnection')
  222. ->will($this->returnValue($mysqliMock));
  223. $this->assertEquals('AFFECTED_ROWS', $this->stmt->affectedRows());
  224. }
  225. public function testNumRowsNoResult()
  226. {
  227. $this->assertFalse($this->stmt->numRows());
  228. }
  229. /**
  230. * @runInSeparateProcess
  231. * @expectedException Exception
  232. * @TODO: exception just for code coverage - could not mock mysqli properties
  233. */
  234. public function testNumRows()
  235. {
  236. if (!defined('DEBUG')) {
  237. define('DEBUG', false);
  238. }
  239. $this->setDriverGetConnectionMethod();
  240. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  241. $this->assertNull($this->stmt->numRows());
  242. }
  243. /**
  244. * @expectedException Exception
  245. * @expectedExceptionMessage Invalid fetch mode
  246. * @runInSeparateProcess
  247. */
  248. public function testFetchInvalidMode()
  249. {
  250. if (!defined('DEBUG')) {
  251. define('DEBUG', false);
  252. }
  253. $this->setDriverGetConnectionMethod();
  254. $this->stmt->execute(array('place' => 'place_val', 'new' => 'new_val'));
  255. $this->stmt->fetch(324);
  256. }
  257. private function setDriverGetConnectionMethod()
  258. {
  259. $resultMock = $this->getMockBuilder('mysqli_result')
  260. ->disableOriginalConstructor()
  261. ->setMethods(array('fetch_object', 'fetch_array', 'fetch_assoc', 'close'))
  262. ->setMockClassName('Mysqli_Result_Mock')
  263. ->getMock();
  264. $resultMock
  265. ->expects($this->any())
  266. ->method('fetch_object')
  267. ->will($this->returnValue('OBJECT'));
  268. $resultMock
  269. ->expects($this->any())
  270. ->method('fetch_array')
  271. ->will($this->returnValue('ARRAY'));
  272. $resultMock
  273. ->expects($this->any())
  274. ->method('fetch_assoc')
  275. ->will($this->returnValue('ASSOC'));
  276. $resultMock
  277. ->expects($this->any())
  278. ->method('close')
  279. ->will($this->returnValue(TRUE));
  280. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  281. $mysqliMock
  282. ->expects($this->any())
  283. ->method('query')
  284. ->with($this->anything())
  285. ->will($this->returnValue($resultMock));
  286. $this->driver
  287. ->expects($this->any())
  288. ->method('getConnection')
  289. ->will($this->returnValue($mysqliMock));
  290. return $this;
  291. }
  292. private function setDriverGetConnectionWrongResultMethod()
  293. {
  294. $mysqliMock = $this->getMock('MysqliDrvr', array('query'));
  295. $mysqliMock
  296. ->expects($this->any())
  297. ->method('query')
  298. ->with($this->anything())
  299. ->will($this->returnValue(false));
  300. $mysqliMock->error = 'ERROR';
  301. $mysqliMock->errno = 0;
  302. $this->driver
  303. ->expects($this->any())
  304. ->method('getConnection')
  305. ->will($this->returnValue($mysqliMock));
  306. return $this;
  307. }
  308. public function driverQuote($val)
  309. {
  310. return $val;
  311. }
  312. public function dbStatementAssemble($val)
  313. {
  314. return $val;
  315. }
  316. }