1
0

MapperTestUtility.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. /**
  3. * ownCloud - App Framework
  4. *
  5. * @author Bernhard Posselt
  6. * @copyright 2012 Bernhard Posselt dev@bernhard-posselt.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace Test\AppFramework\Db;
  23. use OCP\DB\IPreparedStatement;
  24. use OCP\DB\IResult;
  25. /**
  26. * Simple utility class for testing mappers
  27. */
  28. abstract class MapperTestUtility extends \Test\TestCase {
  29. protected $db;
  30. private $statement;
  31. private $queryAt;
  32. private $prepareAt;
  33. private $fetchAt;
  34. private $iterators;
  35. /**
  36. * Run this function before the actual test to either set or initialize the
  37. * db. After this the db can be accessed by using $this->db
  38. */
  39. protected function setUp(): void {
  40. parent::setUp();
  41. $this->db = $this->getMockBuilder(
  42. '\OCP\IDBConnection')
  43. ->disableOriginalConstructor()
  44. ->getMock();
  45. $this->statement = $this->createMock(IPreparedStatement::class);
  46. $this->queryAt = 0;
  47. $this->prepareAt = 0;
  48. $this->iterators = [];
  49. $this->fetchAt = 0;
  50. }
  51. /**
  52. * Checks if an array is associative
  53. * @param array $array
  54. * @return bool true if associative
  55. */
  56. private function isAssocArray(array $array) {
  57. return array_values($array) !== $array;
  58. }
  59. /**
  60. * Returns the correct PDO constant based on the value type
  61. * @param $value
  62. * @return int PDO constant
  63. */
  64. private function getPDOType($value) {
  65. switch (gettype($value)) {
  66. case 'integer':
  67. return \PDO::PARAM_INT;
  68. case 'boolean':
  69. return \PDO::PARAM_BOOL;
  70. default:
  71. return \PDO::PARAM_STR;
  72. }
  73. }
  74. /**
  75. * Create mocks and set expected results for database queries
  76. * @param string $sql the sql query that you expect to receive
  77. * @param array $arguments the expected arguments for the prepare query
  78. * method
  79. * @param array $returnRows the rows that should be returned for the result
  80. * of the database query. If not provided, it wont be assumed that fetch
  81. * will be called on the result
  82. */
  83. protected function setMapperResult($sql, $arguments = [], $returnRows = [],
  84. $limit = null, $offset = null, $expectClose = false) {
  85. if ($limit === null && $offset === null) {
  86. $this->db->expects($this->at($this->prepareAt))
  87. ->method('prepare')
  88. ->with($this->equalTo($sql))
  89. ->will(($this->returnValue($this->statement)));
  90. } elseif ($limit !== null && $offset === null) {
  91. $this->db->expects($this->at($this->prepareAt))
  92. ->method('prepare')
  93. ->with($this->equalTo($sql), $this->equalTo($limit))
  94. ->will(($this->returnValue($this->statement)));
  95. } elseif ($limit === null && $offset !== null) {
  96. $this->db->expects($this->at($this->prepareAt))
  97. ->method('prepare')
  98. ->with($this->equalTo($sql),
  99. $this->equalTo(null),
  100. $this->equalTo($offset))
  101. ->will(($this->returnValue($this->statement)));
  102. } else {
  103. $this->db->expects($this->at($this->prepareAt))
  104. ->method('prepare')
  105. ->with($this->equalTo($sql),
  106. $this->equalTo($limit),
  107. $this->equalTo($offset))
  108. ->will(($this->returnValue($this->statement)));
  109. }
  110. $this->iterators[] = new ArgumentIterator($returnRows);
  111. $iterators = $this->iterators;
  112. $fetchAt = $this->fetchAt;
  113. $this->statement->expects($this->any())
  114. ->method('fetch')
  115. ->willReturnCallback(
  116. function () use ($iterators, $fetchAt) {
  117. $iterator = $iterators[$fetchAt];
  118. $result = $iterator->next();
  119. if ($result === false) {
  120. $fetchAt++;
  121. }
  122. $this->queryAt++;
  123. return $result;
  124. }
  125. );
  126. if ($this->isAssocArray($arguments)) {
  127. foreach ($arguments as $key => $argument) {
  128. $pdoConstant = $this->getPDOType($argument);
  129. $this->statement->expects($this->at($this->queryAt))
  130. ->method('bindValue')
  131. ->with($this->equalTo($key),
  132. $this->equalTo($argument),
  133. $this->equalTo($pdoConstant));
  134. $this->queryAt++;
  135. }
  136. } else {
  137. $index = 1;
  138. foreach ($arguments as $argument) {
  139. $pdoConstant = $this->getPDOType($argument);
  140. $this->statement->expects($this->at($this->queryAt))
  141. ->method('bindValue')
  142. ->with($this->equalTo($index),
  143. $this->equalTo($argument),
  144. $this->equalTo($pdoConstant));
  145. $index++;
  146. $this->queryAt++;
  147. }
  148. }
  149. $this->statement->expects($this->at($this->queryAt))
  150. ->method('execute')
  151. ->willReturnCallback(function ($sql, $p = null, $o = null, $s = null) {
  152. return $this->createMock(IResult::class);
  153. });
  154. $this->queryAt++;
  155. if ($expectClose) {
  156. $closing = $this->at($this->queryAt);
  157. } else {
  158. $closing = $this->any();
  159. }
  160. $this->statement->expects($closing)->method('closeCursor');
  161. $this->queryAt++;
  162. $this->prepareAt++;
  163. $this->fetchAt++;
  164. }
  165. }
  166. class ArgumentIterator {
  167. private $arguments;
  168. public function __construct($arguments) {
  169. $this->arguments = $arguments;
  170. }
  171. public function next() {
  172. $result = array_shift($this->arguments);
  173. if ($result === null) {
  174. return false;
  175. } else {
  176. return $result;
  177. }
  178. }
  179. }