v2 / vlib / io / buffered_writer_test.v
232 lines · 198 sloc · 5.0 KB · 5a2b1ad8de04313d6089be9dc8d26ae2ae2bd6f2
Raw
1import io
2import rand
3
4fn small_amount() int {
5 return int(rand.u8()) + 1
6}
7
8struct ArrayWriter {
9pub mut:
10 result []u8
11}
12
13// implement io.Writer
14fn (mut aw ArrayWriter) write(buf []u8) !int {
15 len := buf.len
16 mut res := 0
17 for i := 0; i < len; i++ {
18 aw.result << buf[i]
19 res++
20 }
21 return res
22}
23
24struct ChunkedArrayWriter {
25 chunk int
26pub mut:
27 result []u8
28}
29
30fn (mut cw ChunkedArrayWriter) write(buf []u8) !int {
31 if buf.len == 0 {
32 return 0
33 }
34 n := if buf.len < cw.chunk { buf.len } else { cw.chunk }
35 for i := 0; i < n; i++ {
36 cw.result << buf[i]
37 }
38 return n
39}
40
41struct FailOnceChunkedWriter {
42 chunk int
43pub mut:
44 result []u8
45mut:
46 writes int
47}
48
49fn (mut fw FailOnceChunkedWriter) write(buf []u8) !int {
50 if fw.writes == 1 {
51 fw.writes++
52 return error('forced write failure')
53 }
54 fw.writes++
55 n := if buf.len < fw.chunk { buf.len } else { fw.chunk }
56 for i := 0; i < n; i++ {
57 fw.result << buf[i]
58 }
59 return n
60}
61
62struct ZeroProgressWriter {}
63
64fn (mut w ZeroProgressWriter) write(buf []u8) !int {
65 return 0
66}
67
68// write less than max bytes, returns number of bytes written
69// data is written in chunks.
70fn write_random_data(mut aw ArrayWriter, mut bw io.BufferedWriter, max int) !int {
71 less_than_max := max - 255 // guarantee 1 full u8 less than max
72 mut total := 0
73 for total < less_than_max {
74 r := rand.u8()
75 d := rand.bytes(r)!
76 w := bw.write(d)!
77 total += w
78 }
79 return total
80}
81
82fn test_flush() {
83 mut aw := ArrayWriter{}
84 max := 65536
85 mut bw := io.new_buffered_writer(writer: &aw, cap: max)!
86
87 // write less data than buffer capacity, the underlying writer should receive no data.
88 written := write_random_data(mut aw, mut bw, 65536)!
89 assert written == bw.buffered()
90 assert aw.result.len == 0
91
92 bw.flush()!
93 assert aw.result.len == written
94 assert bw.buffered() == 0
95 assert bw.available() == max
96}
97
98fn test_write() {
99 mut aw := ArrayWriter{}
100 max := 65536
101 mut bw := io.new_buffered_writer(writer: &aw, cap: max)!
102
103 // write less data than buffer capacity, the underlying writer should receive no data.
104 written := write_random_data(mut aw, mut bw, 65536)!
105
106 // now exceed buffer capacity by a little
107 little := small_amount()
108 excess := bw.available() + little
109 excess_data := rand.bytes(excess)!
110 w := bw.write(excess_data)!
111 assert bw.buffered() == little
112 assert bw.available() == max - little
113 assert aw.result.len == max
114}
115
116fn test_write_big() {
117 mut aw := ArrayWriter{}
118 max := 65536
119 mut bw := io.new_buffered_writer(writer: &aw, cap: max)!
120
121 more_than_max := max + small_amount()
122 big_source := rand.bytes(more_than_max)!
123 w := bw.write(big_source)!
124 assert w == more_than_max
125 assert bw.buffered() == 0
126 assert bw.available() == max
127 assert aw.result.len == more_than_max
128}
129
130// create_data returns an array with `n` elements plus `\n` as last character.
131fn create_data(n int) []u8 {
132 mut res := []u8{}
133 for i := 0; i < n; i++ {
134 res << `X`
135 }
136 res << `\n`
137 return res
138}
139
140fn test_simple_write() {
141 mut aw := ArrayWriter{}
142 mut bw := io.new_buffered_writer(writer: &aw, cap: 10)!
143 mut data := create_data(6)
144 w1 := bw.write(data)!
145
146 // add data to buffer, less than cap
147 // data is written to buffer, not to underlying writer.
148 assert w1 == 7 // 6*x + \n
149 assert bw.buffered() == 7
150 assert aw.result.len == 0
151
152 // add more data, exceed cap
153 // data is flushed to underlying writer when buffer is full, then more data is written to buffer.
154 w2 := bw.write(data)!
155 assert w2 == 7
156 assert bw.buffered() == 4
157 assert aw.result.len == 10
158
159 // exceed cap immediately
160 // all data is written without buffering
161 aw.result = []u8{}
162 data = create_data(33)
163 bw.reset()
164 w3 := bw.write(data)!
165 assert bw.buffered() == 0
166 assert aw.result.len == 34 // 33*x + \n
167}
168
169fn test_simple_flush() {
170 mut aw := ArrayWriter{}
171 mut bw := io.new_buffered_writer(writer: &aw, cap: 10)!
172 data := create_data(6)
173 w := bw.write(data)!
174
175 assert w == 7 // 6*x + \n
176 assert bw.buffered() == 7
177
178 bw.flush()!
179 assert bw.buffered() == 0
180 assert aw.result.len == 7
181}
182
183fn test_flush_handles_partial_writes() {
184 mut cw := ChunkedArrayWriter{
185 chunk: 2
186 }
187 mut bw := io.new_buffered_writer(writer: &cw, cap: 8)!
188 data := 'abcdefg'.bytes()
189
190 written := bw.write(data)!
191 assert written == data.len
192 assert bw.buffered() == data.len
193 assert cw.result.len == 0
194
195 bw.flush()!
196 assert bw.buffered() == 0
197 assert cw.result == data
198}
199
200fn test_flush_preserves_unwritten_data_on_error() {
201 mut fw := FailOnceChunkedWriter{
202 chunk: 3
203 }
204 mut bw := io.new_buffered_writer(writer: &fw, cap: 8)!
205 data := 'abcdefg'.bytes()
206 _ = bw.write(data)!
207
208 if _ := bw.flush() {
209 assert false
210 } else {
211 assert err.msg() == 'forced write failure'
212 }
213 assert fw.result == 'abc'.bytes()
214 assert bw.buffered() == 4
215 assert bw.buf[..bw.buffered()] == 'defg'.bytes()
216
217 bw.flush()!
218 assert bw.buffered() == 0
219 assert fw.result == data
220}
221
222fn test_write_returns_error_for_zero_progress_writes() {
223 mut zw := ZeroProgressWriter{}
224 mut bw := io.new_buffered_writer(writer: &zw, cap: 4)!
225
226 if _ := bw.write('12345'.bytes()) {
227 assert false
228 } else {
229 assert err.msg() == 'writer returned an invalid number of bytes while writing'
230 }
231 assert bw.buffered() == 0
232}
233