Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.36% covered (warning)
89.36%
42 / 47
70.59% covered (warning)
70.59%
12 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
StringStream
89.36% covered (warning)
89.36%
42 / 47
70.59% covered (warning)
70.59%
12 / 17
30.01
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 copyToStream
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 close
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 detach
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSize
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 tell
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 eof
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isSeekable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 seek
92.86% covered (success)
92.86%
13 / 14
0.00% covered (danger)
0.00%
0 / 1
7.02
 rewind
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isWritable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 write
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 isReadable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 read
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
 getContents
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 getMetadata
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Rest;
4
5use InvalidArgumentException;
6
7/**
8 * A stream class which uses a string as the underlying storage. Surprisingly,
9 * Guzzle does not appear to have one of these. BufferStream does not do what
10 * we want.
11 *
12 * The normal use of this class should be to first write to the stream, then
13 * rewind, then read back the whole buffer with getContents().
14 *
15 * Seeking is supported, however seeking past the end of the string does not
16 * fill with null bytes as in a real file, it throws an exception instead.
17 */
18class StringStream implements CopyableStreamInterface {
19
20    /** @var string */
21    private $contents;
22    /** @var int */
23    private $offset = 0;
24
25    /**
26     * Construct a StringStream with the given contents.
27     *
28     * The offset will start at 0, ready for reading. If appending to the
29     * given string is desired, you should first seek to the end.
30     *
31     * @param string $contents
32     */
33    public function __construct( $contents = '' ) {
34        $this->contents = $contents;
35    }
36
37    public function copyToStream( $stream ) {
38        fwrite( $stream, $this->getContents() );
39    }
40
41    public function __toString() {
42        return $this->contents;
43    }
44
45    public function close() {
46    }
47
48    public function detach() {
49        return null;
50    }
51
52    public function getSize() {
53        return strlen( $this->contents );
54    }
55
56    public function tell() {
57        return $this->offset;
58    }
59
60    public function eof() {
61        return $this->offset >= strlen( $this->contents );
62    }
63
64    public function isSeekable() {
65        return true;
66    }
67
68    public function seek( $offset, $whence = SEEK_SET ) {
69        switch ( $whence ) {
70            case SEEK_SET:
71                $this->offset = $offset;
72                break;
73
74            case SEEK_CUR:
75                $this->offset += $offset;
76                break;
77
78            case SEEK_END:
79                $this->offset = strlen( $this->contents ) + $offset;
80                break;
81
82            default:
83                throw new InvalidArgumentException( "Invalid value for \$whence" );
84        }
85        if ( $this->offset > strlen( $this->contents ) ) {
86            throw new InvalidArgumentException( "Cannot seek beyond the end of a StringStream" );
87        }
88        if ( $this->offset < 0 ) {
89            throw new InvalidArgumentException( "Cannot seek before the start of a StringStream" );
90        }
91    }
92
93    public function rewind() {
94        $this->offset = 0;
95    }
96
97    public function isWritable() {
98        return true;
99    }
100
101    public function write( $string ) {
102        if ( $this->offset === strlen( $this->contents ) ) {
103            $this->contents .= $string;
104        } else {
105            $this->contents = substr_replace( $this->contents, $string,
106                $this->offset, strlen( $string ) );
107        }
108        $this->offset += strlen( $string );
109        return strlen( $string );
110    }
111
112    public function isReadable() {
113        return true;
114    }
115
116    public function read( $length ) {
117        if ( $this->offset === 0 && $length >= strlen( $this->contents ) ) {
118            $ret = $this->contents;
119        } elseif ( $this->offset >= strlen( $this->contents ) ) {
120            $ret = '';
121        } else {
122            $ret = substr( $this->contents, $this->offset, $length );
123        }
124        $this->offset += strlen( $ret );
125        return $ret;
126    }
127
128    public function getContents() {
129        if ( $this->offset === 0 ) {
130            $ret = $this->contents;
131        } elseif ( $this->offset >= strlen( $this->contents ) ) {
132            $ret = '';
133        } else {
134            $ret = substr( $this->contents, $this->offset );
135        }
136        $this->offset = strlen( $this->contents );
137        return $ret;
138    }
139
140    public function getMetadata( $key = null ) {
141        return null;
142    }
143}