v2 / vlib / archive / tar / reader_test.v
219 lines · 189 sloc · 6.42 KB · ddd65517af83dae651d7df90d5bd6b685a77feae
Raw
1@[has_globals]
2module tar
3
4import os
5
6fn testsuite_begin() {
7 os.chdir(@VMODROOT) or {}
8}
9
10const testdata = 'vlib/archive/tar/testdata'
11
12__global (
13 test_chunk_blocks [][]u8
14)
15
16fn collect_test_block(block []u8) !ReadResult {
17 test_chunk_blocks << block.clone()
18 return .continue
19}
20
21// files copied from golang: https://github.com/golang/go/blob/master/src/archive/tar/testdata/file-and-dir.tar
22fn test_golang_testdata() {
23 // [ ] dir | 0 bytes | folder
24 // [ ] small.txt | 5 bytes | file
25 r1 := new_test_reader('file-and-dir.tar', false)!
26 assert r1.dirs[0] == 'dir/'
27 assert r1.files['small.txt'] == 5
28 assert r1.data['small.txt'] == 'Kilts'.bytes()
29 assert r1.other[0] == 'block:4 special:blank_1 continue'
30 assert r1.other[1] == 'block:5 special:blank_2 end_archive'
31
32 // [ ] small.txt | 5 bytes | file
33 // [ ] small2.txt | 11 bytes | file
34 r2 := new_test_reader('gnu.tar', false)!
35 assert r2.dirs.len == 0
36 assert r2.files['small.txt'] == 5
37 assert r2.files['small2.txt'] == 11
38 assert r2.data['small.txt'] == 'Kilts'.bytes()
39 assert r2.data['small2.txt'] == 'Google.com\n'.bytes()
40
41 // [ ] h1<?><?><?><?>bye | 0 bytes
42 r3 := new_test_reader('gnu-not-utf8.tar', false)!
43 r3_filename := [u8(`h`), `i`, 0x80, 0x81, 0x82, 0x83, `b`, `y`, `e`].bytestr()
44 r3_file_len := r3.files[r3_filename] or { assert false, 'file not found: ${r3_filename}' }
45 assert r3_file_len == 0
46 assert r3.other.len == 2
47
48 // [ ] 0123456789 | 0 bytes
49 r4 := new_test_reader('gnu-long-nul.tar', false)!
50 assert r4.dirs.len == 0
51 r4_filename := '0123456789'
52 r4_file_len := r4.files[r4_filename] or {
53 assert false, 'file ${r4_filename} not found in ${r4.files.keys()}'
54 }
55 assert r4_file_len == 0
56 assert r4.other[0] == 'block:1 special:long_name size:161'
57 assert r4.other[1] == 'block:2 special:long_name data_part:161'
58
59 // [ ] ☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹ | 0 bytes
60 r5 := new_test_reader('gnu-utf8.tar', false)!
61 r5_filename := '☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹☺☻☹'
62 r5_file_len := r5.files[r5_filename] or { assert false, 'file not found: ${r5_filename}' }
63 assert r5_file_len == 0
64 assert r5.other[0] == 'block:1 special:long_name size:163'
65 assert r5.other[1] == 'block:2 special:long_name data_part:163'
66}
67
68fn test_long_long_short() {
69 // test long path (human) substitute another long path (chimp) then a normal path (cat)
70 r1 := new_test_reader_gz('life.tar.gz', false)!
71
72 mammal := 'life/Animalia/Chordata/Mammalia'
73 human := '${mammal}/Primates_Haplorhini_Simiiformes/Hominidae_Homininae_Hominini/Homo/Homo sapiens.txt'
74 chimp := '${mammal}/Primates_Haplorhini_Simiiformes/Hominidae_Homininae_Hominini/Pan/Pan troglodytes.txt'
75 cat := '${mammal}/Carnivora_Feliformia/Felidae_Felinae/Felis/Felis catus.txt'
76 assert human.len > 100
77 assert chimp.len > 100
78 assert cat.len <= 100
79 assert r1.files[human] == 35
80 assert r1.files[chimp] == 40
81 assert r1.files[cat] == 33
82 assert r1.texts[human] == 'https://en.wikipedia.org/wiki/Human'
83 assert r1.texts[chimp] == 'https://en.wikipedia.org/wiki/Chimpanzee'
84 assert r1.texts[cat] == 'https://en.wikipedia.org/wiki/Cat'
85}
86
87@[heap]
88struct ChunksCollector {
89mut:
90 blocks [][]u8
91}
92
93fn test_chunks_reader_keeps_pending_bytes_between_chunks() {
94 mut collector := &ChunksCollector{}
95 read_block := fn [mut collector] (block []u8) !ReadResult {
96 collector.blocks << block.clone()
97 return .continue
98 }
99
100 mut block1 := []u8{len: 512}
101 mut block2 := []u8{len: 512}
102 for i in 0 .. 512 {
103 block1[i] = u8((i * 3) % 251)
104 block2[i] = u8((i * 7) % 251)
105 }
106
107 mut data := []u8{}
108 data << block1
109 data << block2
110
111 mut chunks := ChunksReader{
112 read_block_fn: read_block
113 }
114
115 assert chunks.read_blocks(data[..700]) == .continue
116 assert collector.blocks.len == 1
117 assert collector.blocks[0] == block1
118 assert chunks.pending == 188
119
120 assert chunks.read_blocks(data[700..900]) == .continue
121 assert collector.blocks.len == 1
122 assert chunks.pending == 388
123
124 assert chunks.read_blocks(data[900..]) == .continue
125 assert collector.blocks.len == 2
126 assert collector.blocks[1] == block2
127 assert chunks.pending == 0
128}
129
130struct TestReader {
131 debug bool
132mut:
133 dirs []string
134 files map[string]u64
135 data map[string][]u8
136 texts map[string]string
137 other []string
138
139 last_file string
140 last_data []u8
141}
142
143// new_test_reader reads files *.tar
144fn new_test_reader(tar_file string, debug bool) !&TestReader {
145 mut reader := &TestReader{
146 debug: debug
147 }
148 read_tar_file('${testdata}/${tar_file}', reader)!
149 return reader
150}
151
152// new_test_reader_gz reads files *.tar.gz
153fn new_test_reader_gz(tar_gz_file string, debug bool) !&TestReader {
154 mut reader := &TestReader{
155 debug: debug
156 }
157 read_tar_gz_file('${testdata}/${tar_gz_file}', reader)!
158 return reader
159}
160
161fn (mut t TestReader) dir_block(mut read Read, size u64) {
162 t.dirs << read.get_path()
163 if t.debug {
164 println('DIR #${read.get_block_number()} ${read.get_path()}')
165 }
166}
167
168fn (mut t TestReader) file_block(mut read Read, size u64) {
169 t.last_file = read.get_path()
170 t.files[t.last_file] = size
171 if t.debug {
172 println('FILE #${read.get_block_number()} ${read.get_path()}')
173 }
174}
175
176fn (mut t TestReader) data_block(mut read Read, data []u8, pending int) {
177 path := read.get_path()
178 if t.debug {
179 println('DATA #${read.get_block_number()} ${path}')
180 }
181 if t.last_file == path {
182 t.last_data << data
183 if pending == 0 {
184 t.data[t.last_file] = t.last_data.clone()
185 t.texts[path] = t.last_data.bytestr()
186 if t.debug {
187 println('TEXT #${read.get_block_number()} ${t.last_data.bytestr()}')
188 }
189 t.last_file = ''
190 t.last_data.clear()
191 }
192 }
193}
194
195fn (mut t TestReader) other_block(mut read Read, details string) {
196 t.other << 'block:${read.block_number} special:${read.special} ${details}'
197 if t.debug {
198 println('OTHER #${read.get_block_number()} special:${read.special} ${details}')
199 }
200}
201
202fn test_chunks_reader_moves_pending_bytes_in_order() {
203 mut all := []u8{len: 1024}
204 for i := 0; i < all.len; i++ {
205 all[i] = u8(i % 251)
206 }
207
208 test_chunk_blocks = [][]u8{}
209 mut chunk_reader := ChunksReader{
210 read_block_fn: collect_test_block
211 }
212 assert chunk_reader.read_blocks(all[0..700]) == .continue
213 assert chunk_reader.pending == 188
214 assert chunk_reader.read_blocks(all[700..]) == .continue
215 assert chunk_reader.pending == 0
216 assert test_chunk_blocks.len == 2
217 assert test_chunk_blocks[0] == all[0..512]
218 assert test_chunk_blocks[1] == all[512..]
219}
220