PageRenderTime 46ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/mock/streams/fs/file/controller.php

https://github.com/Hywan/atoum
PHP | 479 lines | 383 code | 96 blank | 0 comment | 61 complexity | 91e7a4b3c5542c48d7f1a12e235811c8 MD5 | raw file
  1. <?php
  2. namespace mageekguy\atoum\mock\streams\fs\file;
  3. use mageekguy\atoum\exceptions;
  4. use mageekguy\atoum\mock\streams\fs;
  5. class controller extends fs\controller
  6. {
  7. protected $exists = true;
  8. protected $read = false;
  9. protected $write = false;
  10. protected $eof = false;
  11. protected $pointer = 0;
  12. protected $offset = null;
  13. protected $append = false;
  14. protected $contents = '';
  15. public function __construct($path)
  16. {
  17. parent::__construct($path);
  18. $this->setPermissions('644');
  19. }
  20. public function __set($method, $value)
  21. {
  22. switch ($method = static::mapMethod($method)) {
  23. case 'mkdir':
  24. case 'rmdir':
  25. case 'dir_closedir':
  26. case 'dir_opendir':
  27. case 'dir_readdir':
  28. case 'dir_rewinddir':
  29. throw new exceptions\logic\invalidArgument('Unable to override streamWrapper::' . $method . '() for file');
  30. default:
  31. return parent::__set($method, $value);
  32. }
  33. }
  34. public function duplicate()
  35. {
  36. $controller = parent::duplicate();
  37. $controller->contents = & $this->contents;
  38. return $controller;
  39. }
  40. public function setPermissions($permissions)
  41. {
  42. return parent::setPermissions(0100000 | octdec($permissions));
  43. }
  44. public function getPointer()
  45. {
  46. return $this->pointer;
  47. }
  48. public function setContents($contents)
  49. {
  50. $this->contents = $contents;
  51. return $this->setStat('size', strlen($this->contents));
  52. }
  53. public function getContents()
  54. {
  55. return $this->contents;
  56. }
  57. public function contains($contents)
  58. {
  59. return $this
  60. ->setContents($contents)
  61. ->setPointer(0)
  62. ;
  63. }
  64. public function isEmpty()
  65. {
  66. return $this->contains('');
  67. }
  68. public function stream_open($path, $mode, $options, & $openedPath = null)
  69. {
  70. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  71. return $this->invoke(__FUNCTION__, func_get_args());
  72. } else {
  73. $this->addCall(__FUNCTION__, func_get_args());
  74. $this->offset = null;
  75. $this->append = false;
  76. $isOpened = false;
  77. $reportErrors = ($options & STREAM_REPORT_ERRORS) == STREAM_REPORT_ERRORS;
  78. if (self::checkOpenMode($mode) === false) {
  79. if ($reportErrors === true) {
  80. trigger_error('Operation timed out', E_USER_WARNING);
  81. }
  82. } else {
  83. $this->setOpenMode($mode);
  84. switch (true) {
  85. case $this->read === true && $this->write === false:
  86. $isOpened = $this->checkIfReadable();
  87. break;
  88. case $this->read === false && $this->write === true:
  89. $isOpened = $this->checkIfWritable();
  90. break;
  91. default:
  92. $isOpened = $this->checkIfReadable() && $this->checkIfWritable();
  93. }
  94. if ($isOpened === false) {
  95. if ($reportErrors === true) {
  96. trigger_error('Permission denied', E_USER_WARNING);
  97. }
  98. } else {
  99. switch (self::getRawOpenMode($mode)) {
  100. case 'w':
  101. $this->exists = true;
  102. $this->truncate(0);
  103. $this->seek(0);
  104. break;
  105. case 'r':
  106. $isOpened = $this->exists;
  107. if ($isOpened === true) {
  108. $this->seek(0);
  109. } elseif ($reportErrors === true) {
  110. trigger_error('No such file or directory', E_USER_WARNING);
  111. }
  112. break;
  113. case 'c':
  114. $this->exists = true;
  115. $this->seek(0);
  116. break;
  117. case 'x':
  118. if ($this->exists === false) {
  119. $this->seek(0);
  120. } else {
  121. $isOpened = false;
  122. if ($reportErrors === true) {
  123. trigger_error('File exists', E_USER_WARNING);
  124. }
  125. }
  126. break;
  127. case 'a':
  128. $this->exists = true;
  129. if ($this->read === true) {
  130. $this->seek(0);
  131. } else {
  132. $this->seek(0, SEEK_END);
  133. $this->offset = $this->pointer;
  134. }
  135. $this->append = true;
  136. break;
  137. }
  138. }
  139. }
  140. $openedPath = null;
  141. if ($isOpened === true && ($options & STREAM_USE_PATH)) {
  142. $openedPath = $this->getPath();
  143. }
  144. return $isOpened;
  145. }
  146. }
  147. public function stream_seek($offset, $whence = SEEK_SET)
  148. {
  149. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  150. return $this->invoke(__FUNCTION__, func_get_args());
  151. } else {
  152. $this->addCall(__FUNCTION__, func_get_args());
  153. return $this->seek($offset, $whence);
  154. }
  155. }
  156. public function stream_eof()
  157. {
  158. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  159. return $this->invoke(__FUNCTION__, func_get_args());
  160. } else {
  161. $this->addCall(__FUNCTION__, []);
  162. return $this->eof;
  163. }
  164. }
  165. public function stream_tell()
  166. {
  167. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  168. return $this->invoke(__FUNCTION__, []);
  169. } else {
  170. $this->addCall(__FUNCTION__, []);
  171. return ($this->offset === null ? $this->pointer : $this->pointer - $this->offset);
  172. }
  173. }
  174. public function stream_read($count)
  175. {
  176. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  177. return $this->invoke(__FUNCTION__, func_get_args());
  178. } else {
  179. $this->addCall(__FUNCTION__, func_get_args());
  180. $data = '';
  181. $this->eof = ($this->pointer < 0 || $this->pointer >= $this->stat['size']);
  182. if ($this->read === true && $this->pointer >= 0 && $this->eof === false) {
  183. $data = substr($this->contents, $this->pointer, $count) ?: '';
  184. $this->movePointer(strlen($data) ?: $count);
  185. }
  186. return $data;
  187. }
  188. }
  189. public function stream_write($data)
  190. {
  191. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  192. return $this->invoke(__FUNCTION__, func_get_args());
  193. } else {
  194. $this->addCall(__FUNCTION__, func_get_args());
  195. $bytesWrited = 0;
  196. if ($this->write === true) {
  197. $contents = $this->getContents();
  198. if ($this->append === true) {
  199. if ($contents !== '') {
  200. $contents .= PHP_EOL;
  201. $this->movePointer(1);
  202. }
  203. $this->append = false;
  204. }
  205. $this
  206. ->setContents($contents . $data)
  207. ->movePointer($bytesWrited = strlen($data))
  208. ;
  209. }
  210. return $bytesWrited;
  211. }
  212. }
  213. public function stream_flush()
  214. {
  215. return true;
  216. }
  217. public function stream_metadata($path, $option, $value)
  218. {
  219. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  220. return $this->invoke(__FUNCTION__, func_get_args());
  221. } else {
  222. $this->addCall(__FUNCTION__, func_get_args());
  223. switch ($option) {
  224. case STREAM_META_TOUCH:
  225. case STREAM_META_OWNER_NAME:
  226. case STREAM_META_OWNER:
  227. case STREAM_META_GROUP_NAME:
  228. case STREAM_META_GROUP:
  229. return true;
  230. case STREAM_META_ACCESS:
  231. $this->setPermissions($value);
  232. return true;
  233. default:
  234. return false;
  235. }
  236. }
  237. }
  238. public function stream_truncate($newSize)
  239. {
  240. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  241. return $this->invoke(__FUNCTION__, func_get_args());
  242. } else {
  243. $this->addCall(__FUNCTION__, func_get_args());
  244. return $this->truncate($newSize);
  245. }
  246. }
  247. public function stream_lock($mode)
  248. {
  249. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  250. return $this->invoke(__FUNCTION__, func_get_args());
  251. } else {
  252. $this->addCall(__FUNCTION__, func_get_args());
  253. return true;
  254. }
  255. }
  256. public function stream_close()
  257. {
  258. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  259. return $this->invoke(__FUNCTION__, []);
  260. } else {
  261. $this->addCall(__FUNCTION__, []);
  262. return true;
  263. }
  264. }
  265. public function unlink($path)
  266. {
  267. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  268. return $this->invoke(__FUNCTION__, func_get_args());
  269. } else {
  270. $this->addCall(__FUNCTION__, func_get_args());
  271. if ($this->exists === false || $this->checkIfWritable() === false) {
  272. return false;
  273. } else {
  274. $this->exists = false;
  275. return true;
  276. }
  277. }
  278. }
  279. public function rename($from, $to)
  280. {
  281. if ($this->nextCallIsOverloaded(__FUNCTION__) === true) {
  282. return $this->invoke(__FUNCTION__, func_get_args());
  283. } else {
  284. $this->addCall(__FUNCTION__, func_get_args());
  285. $this->setPath($to);
  286. return true;
  287. }
  288. }
  289. public function mkdir($path, $mode, $options)
  290. {
  291. return false;
  292. }
  293. public function dir_opendir($path, $options)
  294. {
  295. return false;
  296. }
  297. public function dir_readdir()
  298. {
  299. return false;
  300. }
  301. public function dir_rewinddir()
  302. {
  303. return false;
  304. }
  305. public function dir_closedir()
  306. {
  307. return false;
  308. }
  309. public function rmdir($path, $options)
  310. {
  311. return false;
  312. }
  313. protected function truncate($newSize)
  314. {
  315. $this->setContents(str_pad(substr($this->contents, 0, $newSize), $newSize, "\0"));
  316. return true;
  317. }
  318. protected function seek($offset, $whence = SEEK_SET)
  319. {
  320. switch ($whence) {
  321. case SEEK_CUR:
  322. $offset = $this->pointer + $offset;
  323. break;
  324. case SEEK_END:
  325. $offset = strlen($this->getContents()) + $offset;
  326. }
  327. if ($this->offset !== null && $offset < $this->offset) {
  328. $offset = $this->offset;
  329. }
  330. $this->setPointer($offset);
  331. return true;
  332. }
  333. protected function setOpenMode($mode)
  334. {
  335. $this->read = false;
  336. $this->write = false;
  337. switch (str_replace(['b', 't'], '', $mode)) {
  338. case 'r':
  339. case 'x':
  340. $this->read = true;
  341. break;
  342. case 'w':
  343. case 'a':
  344. case 'c':
  345. $this->write = true;
  346. break;
  347. case 'r+':
  348. case 'x+':
  349. case 'w+':
  350. case 'a+':
  351. case 'c+':
  352. $this->read = $this->write = true;
  353. }
  354. return $this;
  355. }
  356. protected function setPointer($pointer)
  357. {
  358. $this->pointer = $pointer;
  359. $this->eof = false;
  360. return $this;
  361. }
  362. protected function movePointer($offset)
  363. {
  364. return $this->setPointer($this->pointer + $offset);
  365. }
  366. protected static function getRawOpenMode($mode)
  367. {
  368. return str_replace(['b', 't', '+'], '', $mode);
  369. }
  370. protected static function checkOpenMode($mode)
  371. {
  372. switch (self::getRawOpenMode($mode)) {
  373. case 'r':
  374. case 'w':
  375. case 'a':
  376. case 'x':
  377. case 'c':
  378. return true;
  379. default:
  380. return false;
  381. }
  382. }
  383. }