class-wp-test-stream.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <?php
  2. /**
  3. * Class WP_Test_Stream.
  4. *
  5. * An in-memory streamWrapper implementation for testing streams. Writes to a
  6. * stream URL like "protocol://bucket/foo" will be stored in the static
  7. * variable WP_Test_Stream::$data['bucket']['/foo'].
  8. *
  9. * Creating a directory at "protocol://bucket/foo" will store the string
  10. * 'DIRECTORY' to the static variable WP_Test_Stream::$data['bucket']['/foo/']
  11. * (note the trailing slash).
  12. *
  13. * This class can be used to test that code works with basic read/write streams,
  14. * as such, operations such as seeking are not supported.
  15. *
  16. * This class does not register itself as a stream handler: test fixtures
  17. * should make the appropriate call to stream_wrapper_register().
  18. */
  19. class WP_Test_Stream {
  20. const FILE_MODE = 0100666;
  21. const DIRECTORY_MODE = 040777;
  22. /**
  23. * In-memory storage for files and directories simulated by this wrapper.
  24. */
  25. static $data = array();
  26. var $position;
  27. var $file;
  28. var $bucket;
  29. var $data_ref;
  30. /**
  31. * Initializes internal state for reading the given URL.
  32. *
  33. * @param string $url A URL of the form "protocol://bucket/path".
  34. */
  35. private function open( $url ) {
  36. $components = array_merge(
  37. array(
  38. 'host' => '',
  39. 'path' => '',
  40. ),
  41. parse_url( $url )
  42. );
  43. $this->bucket = $components['host'];
  44. $this->file = $components['path'] ? $components['path'] : '/';
  45. if ( empty( $this->bucket ) ) {
  46. trigger_error( 'Cannot use an empty bucket name', E_USER_ERROR );
  47. }
  48. if ( ! isset( WP_Test_Stream::$data[ $this->bucket ] ) ) {
  49. WP_Test_Stream::$data[ $this->bucket ] = array();
  50. }
  51. $this->data_ref =& WP_Test_Stream::$data[ $this->bucket ][ $this->file ];
  52. $this->position = 0;
  53. }
  54. /**
  55. * Opens a URL.
  56. *
  57. * @see streamWrapper::stream_open
  58. */
  59. function stream_open( $path, $mode, $options, &$opened_path ) {
  60. $this->open( $path );
  61. return true;
  62. }
  63. /**
  64. * Reads from a stream.
  65. *
  66. * @see streamWrapper::stream_read
  67. */
  68. function stream_read( $count ) {
  69. if ( ! isset( $this->data_ref ) ) {
  70. return '';
  71. }
  72. $ret = substr( $this->data_ref, $this->position, $count );
  73. $this->position += strlen( $ret );
  74. return $ret;
  75. }
  76. /**
  77. * Writes to a stream.
  78. *
  79. * @see streamWrapper::stream_write
  80. */
  81. function stream_write( $data ) {
  82. if ( ! isset( $this->data_ref ) ) {
  83. $this->data_ref = '';
  84. }
  85. $left = substr( $this->data_ref, 0, $this->position );
  86. $right = substr( $this->data_ref, $this->position + strlen( $data ) );
  87. WP_Test_Stream::$data[ $this->bucket ][ $this->file ] = $left . $data . $right;
  88. $this->position += strlen( $data );
  89. return strlen( $data );
  90. }
  91. /**
  92. * Retrieves the current position of a stream.
  93. *
  94. * @see streamWrapper::stream_tell
  95. */
  96. function stream_tell() {
  97. return $this->position;
  98. }
  99. /**
  100. * Tests for end-of-file.
  101. *
  102. * @see streamWrapper::stream_eof
  103. */
  104. function stream_eof() {
  105. if ( ! isset( $this->data_ref ) ) {
  106. return true;
  107. }
  108. return $this->position >= strlen( $this->data_ref );
  109. }
  110. /**
  111. * Change stream metadata.
  112. *
  113. * @see streamWrapper::stream_metadata
  114. */
  115. function stream_metadata( $path, $option, $var ) {
  116. $this->open( $path );
  117. if ( STREAM_META_TOUCH === $option ) {
  118. if ( ! isset( $this->data_ref ) ) {
  119. $this->data_ref = '';
  120. }
  121. return true;
  122. }
  123. return false;
  124. }
  125. /**
  126. * Creates a directory.
  127. *
  128. * @see streamWrapper::mkdir
  129. */
  130. function mkdir( $path, $mode, $options ) {
  131. $this->open( $path );
  132. $plainfile = rtrim( $this->file, '/' );
  133. if ( isset( WP_Test_Stream::$data[ $this->bucket ][ $file ] ) ) {
  134. return false;
  135. }
  136. $dir_ref = & $this->get_directory_ref();
  137. $dir_ref = 'DIRECTORY';
  138. return true;
  139. }
  140. /**
  141. * Creates a file metadata object, with defaults.
  142. *
  143. * @param array $stats Partial file metadata.
  144. * @return array Complete file metadata.
  145. */
  146. private function make_stat( $stats ) {
  147. $defaults = array(
  148. 'dev' => 0,
  149. 'ino' => 0,
  150. 'mode' => 0,
  151. 'nlink' => 0,
  152. 'uid' => 0,
  153. 'gid' => 0,
  154. 'rdev' => 0,
  155. 'size' => 0,
  156. 'atime' => 0,
  157. 'mtime' => 0,
  158. 'ctime' => 0,
  159. 'blksize' => 0,
  160. 'blocks' => 0,
  161. );
  162. return array_merge( $defaults, $stats );
  163. }
  164. /**
  165. * Retrieves information about a file.
  166. *
  167. * @see streamWrapper::stream_stat
  168. */
  169. public function stream_stat() {
  170. $dir_ref = & $this->get_directory_ref();
  171. if ( substr( $this->file, -1 ) === '/' || isset( $dir_ref ) ) {
  172. return $this->make_stat(
  173. array(
  174. 'mode' => WP_Test_Stream::DIRECTORY_MODE,
  175. )
  176. );
  177. }
  178. if ( ! isset( $this->data_ref ) ) {
  179. return false;
  180. }
  181. return $this->make_stat(
  182. array(
  183. 'size' => strlen( $this->data_ref ),
  184. 'mode' => WP_Test_Stream::FILE_MODE,
  185. )
  186. );
  187. }
  188. /**
  189. * Retrieves information about a file.
  190. *
  191. * @see streamWrapper::url_stat
  192. */
  193. public function url_stat( $path, $flags ) {
  194. $this->open( $path );
  195. return $this->stream_stat();
  196. }
  197. /**
  198. * Deletes a file.
  199. *
  200. * @see streamWrapper::unlink
  201. */
  202. public function unlink( $path ) {
  203. if ( ! isset( $this->data_ref ) ) {
  204. return false;
  205. }
  206. unset( WP_Test_Stream::$data[ $this->bucket ][ $this->file ] );
  207. return true;
  208. }
  209. /**
  210. * Interprets this stream's path as a directory, and returns the entry.
  211. *
  212. * @return A reference to the data entry for the directory.
  213. */
  214. private function &get_directory_ref() {
  215. return WP_Test_Stream::$data[ $this->bucket ][ rtrim( $this->file, '/' ) . '/' ];
  216. }
  217. }