v / vlib / compress / zstd / zstd_test.v
364 lines · 309 sloc · 10.33 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1module zstd
2
3import os
4
5const samples_folder = os.join_path(os.dir(@FILE), 'samples')
6
7fn s(fname string) string {
8 return os.join_path(samples_folder, fname)
9}
10
11fn test_zstd() {
12 assert version_number() >= 10505
13
14 uncompressed := 'Hello world!'.repeat(10000)
15 compressed := compress(uncompressed.bytes())!
16 decompressed := decompress(compressed)!
17 assert decompressed == uncompressed.bytes()
18}
19
20fn test_zstd_deferent_compression_level() {
21 uncompressed := 'Hello world!'.repeat(10000)
22
23 compressed_1000 := compress(uncompressed.bytes(), compression_level: 1000)!
24 decompressed_1000 := decompress(compressed_1000)!
25 assert decompressed_1000 == uncompressed.bytes()
26
27 compressed_0 := compress(uncompressed.bytes(), compression_level: 0)!
28 decompressed_0 := decompress(compressed_0)!
29 assert decompressed_0 == uncompressed.bytes()
30
31 compressed_1 := compress(uncompressed.bytes(), compression_level: 1)!
32 decompressed_1 := decompress(compressed_1)!
33 assert decompressed_1 == uncompressed.bytes()
34
35 compressed_15 := compress(uncompressed.bytes(), compression_level: 15)!
36 decompressed_15 := decompress(compressed_15)!
37 assert decompressed_15 == uncompressed.bytes()
38}
39
40fn test_zstd_nb_threads() {
41 uncompressed := 'Hello world!'.repeat(10000)
42
43 compressed_0 := compress(uncompressed.bytes(), nb_threads: 0)!
44 decompressed_0 := decompress(compressed_0)!
45 assert decompressed_0 == uncompressed.bytes()
46
47 compressed_1 := compress(uncompressed.bytes(), nb_threads: 1)!
48 decompressed_1 := decompress(compressed_1)!
49 assert decompressed_1 == uncompressed.bytes()
50
51 compressed_15 := compress(uncompressed.bytes(), nb_threads: 15)!
52 decompressed_15 := decompress(compressed_15)!
53 assert decompressed_15 == uncompressed.bytes()
54}
55
56fn test_zstd_checksum_flag() {
57 uncompressed := 'Hello world!'.repeat(10000)
58
59 compressed_true := compress(uncompressed.bytes(), checksum_flag: true)!
60 decompressed_true := decompress(compressed_true)!
61 assert decompressed_true == uncompressed.bytes()
62
63 compressed_false := compress(uncompressed.bytes(), checksum_flag: false)!
64 decompressed_false := decompress(compressed_false)!
65 assert decompressed_false == uncompressed.bytes()
66}
67
68fn test_zstd_deferent_strategy() {
69 uncompressed := 'Hello world!'.repeat(10000)
70
71 compressed_default := compress(uncompressed.bytes(), strategy: .default)!
72 decompressed_default := decompress(compressed_default)!
73 assert decompressed_default == uncompressed.bytes()
74
75 compressed_fast := compress(uncompressed.bytes(), strategy: .fast)!
76 decompressed_fast := decompress(compressed_fast)!
77 assert decompressed_fast == uncompressed.bytes()
78
79 compressed_dfast := compress(uncompressed.bytes(), strategy: .dfast)!
80 decompressed_dfast := decompress(compressed_dfast)!
81 assert decompressed_dfast == uncompressed.bytes()
82
83 compressed_greedy := compress(uncompressed.bytes(), strategy: .greedy)!
84 decompressed_greedy := decompress(compressed_greedy)!
85 assert decompressed_greedy == uncompressed.bytes()
86
87 compressed_lazy := compress(uncompressed.bytes(), strategy: .lazy)!
88 decompressed_lazy := decompress(compressed_lazy)!
89 assert decompressed_lazy == uncompressed.bytes()
90
91 compressed_lazy2 := compress(uncompressed.bytes(), strategy: .lazy2)!
92 decompressed_lazy2 := decompress(compressed_lazy2)!
93 assert decompressed_lazy2 == uncompressed.bytes()
94
95 compressed_btlazy2 := compress(uncompressed.bytes(), strategy: .btlazy2)!
96 decompressed_btlazy2 := decompress(compressed_btlazy2)!
97 assert decompressed_btlazy2 == uncompressed.bytes()
98
99 compressed_btopt := compress(uncompressed.bytes(), strategy: .btopt)!
100 decompressed_btopt := decompress(compressed_btopt)!
101 assert decompressed_btopt == uncompressed.bytes()
102
103 compressed_btultra := compress(uncompressed.bytes(), strategy: .btultra)!
104 decompressed_btultra := decompress(compressed_btultra)!
105 assert decompressed_btultra == uncompressed.bytes()
106
107 compressed_btultra2 := compress(uncompressed.bytes(), strategy: .btultra2)!
108 decompressed_btultra2 := decompress(compressed_btultra2)!
109 assert decompressed_btultra2 == uncompressed.bytes()
110}
111
112fn compress_file(fname string, oname string, params CompressParams) ! {
113 mut fin := os.open_file(fname, 'rb')!
114 mut fout := os.open_file(oname, 'wb')!
115 defer {
116 fin.close()
117 fout.close()
118 }
119
120 mut buf_in := []u8{len: buf_in_size}
121 mut buf_out := []u8{len: buf_out_size}
122
123 mut cctx := new_cctx(params)!
124 defer {
125 cctx.free_cctx()
126 }
127
128 mut last_chunk := false
129 mut input := &InBuffer{
130 src: buf_in.data
131 size: 0
132 pos: 0
133 }
134 mut output := &OutBuffer{
135 dst: buf_out.data
136 size: 0
137 pos: 0
138 }
139 for !last_chunk {
140 read_len := fin.read(mut buf_in)!
141 last_chunk = read_len < buf_in_size
142 mode := if last_chunk {
143 EndDirective.end
144 } else {
145 EndDirective.continue
146 }
147
148 mut finished := false
149 input.src = buf_in.data
150 input.size = usize(read_len)
151 input.pos = 0
152 for !finished {
153 output.dst = buf_out.data
154 output.size = buf_out_size
155 output.pos = 0
156 remaining := cctx.compress_stream2(output, input, mode)!
157 fout.write(buf_out[..int(output.pos)])!
158 finished = if last_chunk { remaining == 0 } else { input.pos == input.size }
159 }
160
161 if input.pos != input.size {
162 return error('Impossible: zstd only returns 0 when the input is completely consumed!')
163 }
164 }
165}
166
167fn decompress_file(fname string, oname string, params DecompressParams) ! {
168 mut fin := os.open_file(fname, 'rb')!
169 mut fout := os.open_file(oname, 'wb')!
170 defer {
171 fin.close()
172 fout.close()
173 }
174
175 mut buf_in := []u8{len: buf_in_size}
176 mut buf_out := []u8{len: buf_out_size}
177
178 mut dctx := new_dctx(params)!
179 defer {
180 dctx.free_dctx()
181 }
182
183 mut input := &InBuffer{
184 src: buf_in.data
185 size: 0
186 pos: 0
187 }
188 mut output := &OutBuffer{
189 dst: buf_out.data
190 size: 0
191 pos: 0
192 }
193
194 mut last_ret := usize(0)
195 for {
196 read_len := fin.read(mut buf_in)!
197 input.src = buf_in.data
198 input.size = usize(read_len)
199 input.pos = 0
200 for input.pos < input.size {
201 output.dst = buf_out.data
202 output.size = buf_out_size
203 output.pos = 0
204 ret := dctx.decompress_stream(output, input)!
205 fout.write(buf_out[..int(output.pos)])!
206 last_ret = ret
207 }
208 if read_len < buf_in.len {
209 break
210 }
211 }
212 if last_ret != 0 {
213 /* The last return value from DecompressStream did not end on a
214 * frame, but we reached the end of the file! We assume this is an
215 * error, and the input was truncated.
216 */
217 return error('EOF before end of stream: ${last_ret}')
218 }
219}
220
221// zstd stream mode test
222fn test_zstd_stream() {
223 decompress_file(s('readme_level_19.zst'), s('tmp_file1'))!
224 compress_file(s('tmp_file1'), s('tmp_file.zstd'),
225 compression_level: 6
226 nb_threads: 1
227 checksum_flag: true
228 )!
229 decompress_file(s('tmp_file.zstd'), s('tmp_file2'))!
230 file1 := os.read_file(s('tmp_file1'))!
231 assert file1.contains('## Acknowledgement')
232 assert file1.contains('## Troubleshooting')
233 file2 := os.read_file(s('tmp_file2'))!
234 assert file1 == file2
235 os.rm(s('tmp_file1'))!
236 os.rm(s('tmp_file2'))!
237 os.rm(s('tmp_file.zstd'))!
238}
239
240// store_array compress an `array`'s data, and store it to file `fname`.
241// extra compression parameters can be set by `params`
242// WARNING: Because struct padding, some data in struct may be marked unused.
243// So, when `store_array`, it will cause memory fsanitize fail with 'use-of-uninitialized-value'.
244// It can be safely ignored.
245// For example, following struct may cause memory fsanitize fail:
246// struct MemoryTrace {
247// operation u8
248// address u64
249// size u8
250// }
251// By changing it into following , you can pass the memory fsanitize check :
252// struct MemoryTrace {
253// operation u64
254// address u64
255// size u64
256// }
257struct MemoryTrace {
258 operation u64
259 address u64
260 size u64
261}
262
263fn store_array_test(fname string) ! {
264 // Create a big array
265 mut store_memory_trace := []MemoryTrace{cap: 1000}
266 for i in 0 .. 1000 {
267 store_memory_trace << MemoryTrace{
268 operation: u64(`L`)
269 address: u64(i)
270 size: u8(i % 8)
271 }
272 }
273 store_array[MemoryTrace](fname, store_memory_trace, compression_level: 8)!
274}
275
276fn load_array_test(fname string) ! {
277 load_memory_trace := load_array[MemoryTrace](fname)!
278 for i in 0 .. 1000 {
279 assert load_memory_trace[i].operation == `L`
280 assert load_memory_trace[i].address == i
281 assert load_memory_trace[i].size == u8(i % 8)
282 }
283}
284
285fn test_zstd_store_load_array() {
286 store_array_test(s('mem_trace.zstd'))!
287 load_array_test(s('mem_trace.zstd'))!
288 os.rm(s('mem_trace.zstd'))!
289}
290
291fn assert_decompress_error(data []u8, reason string) ! {
292 decompress(data) or {
293 assert err.msg() == reason
294 return
295 }
296 return error('did not error')
297}
298
299fn test_zstd_invalid_too_small() {
300 assert_decompress_error([]u8{},
301 'An error occurred (e.g. invalid magic number, srcSize too small)')!
302}
303
304fn test_zstd_invalid_magic_numbers() {
305 assert_decompress_error([]u8{len: 100},
306 'An error occurred (e.g. invalid magic number, srcSize too small)')!
307}
308
309fn test_zstd_invalid_compression() {
310 mut data := []u8{len: 100}
311 data[0] = 0x1f
312 data[1] = 0x8b
313 assert_decompress_error(data,
314 'An error occurred (e.g. invalid magic number, srcSize too small)')!
315}
316
317fn test_zstd_with_corruption1() {
318 uncompressed := 'Hello world!'
319 mut compressed := compress(uncompressed.bytes())!
320 compressed[5] = u8(0x7A)
321 assert_decompress_error(compressed, 'Data corruption detected')!
322}
323
324fn test_zstd_with_corruption2() {
325 uncompressed := 'Hello world!'
326 mut compressed := compress(uncompressed.bytes())!
327 compressed[6] = u8(0x7A)
328 assert_decompress_error(compressed, 'Destination buffer is too small')!
329}
330
331fn test_zstd_with_corruption3() {
332 uncompressed := 'Hello world!'
333 mut compressed := compress(uncompressed.bytes())!
334 compressed[7] = u8(0x7A)
335 assert_decompress_error(compressed, 'Src size is incorrect')!
336}
337
338fn test_zstd_with_corruption4() {
339 uncompressed := 'Hello world!'
340 mut compressed := compress(uncompressed.bytes())!
341 compressed[8] = u8(0x7A)
342 assert_decompress_error(compressed, 'Src size is incorrect')!
343}
344
345fn test_zstd_with_corruption5() {
346 uncompressed := 'Hello world!'
347 mut compressed := compress(uncompressed.bytes())!
348 compressed[9] = u8(0x7A)
349 assert_decompress_error(compressed, "Restored data doesn't match checksum")!
350}
351
352fn test_zstd_with_corruption6() {
353 uncompressed := 'Hello world!'
354 mut compressed := compress(uncompressed.bytes())!
355 compressed[10] = u8(0x7A)
356 assert_decompress_error(compressed, "Restored data doesn't match checksum")!
357}
358
359fn test_zstd_with_corruption7() {
360 uncompressed := 'Hello world!'
361 mut compressed := compress(uncompressed.bytes())!
362 compressed[compressed.len - 1] += 1
363 assert_decompress_error(compressed, "Restored data doesn't match checksum")!
364}
365