xref: /sqlite-3.40.0/test/zipfile.test (revision cfaffad6)
1# 2017 December 9
2#
3# The author disclaims copyright to this source code.  In place of
4# a legal notice, here is a blessing:
5#
6#    May you do good and not evil.
7#    May you find forgiveness for yourself and forgive others.
8#    May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15set testprefix zipfile
16
17ifcapable !vtab {
18  finish_test; return
19}
20if {[catch {load_static_extension db zipfile} error]} {
21  puts "Skipping zipfile tests, hit load error: $error"
22  finish_test; return
23}
24
25proc readfile {f} {
26  set fd [open $f]
27  fconfigure $fd -translation binary -encoding binary
28  set data [read $fd]
29  close $fd
30  set data
31}
32
33if {$::tcl_platform(platform)=="unix" && [catch {exec unzip}]==0} {
34  set ::UNZIP 1
35  load_static_extension db fileio
36  proc do_unzip {file} {
37    forcedelete test_unzip
38    file mkdir test_unzip
39    exec unzip -d test_unzip $file
40
41    set res [db eval {
42      SELECT replace(name,'test_unzip/',''),mode,mtime,data
43      FROM fsdir('test_unzip')
44      WHERE name!='test_unzip'
45      ORDER BY name
46    }]
47    set res
48  }
49}
50
51
52# The argument is a blob (not a hex string) containing a zip archive.
53# This proc removes the extended timestamp fields from the archive
54# and returns the result.
55#
56proc remove_timestamps {blob} {
57  set hex [binary encode hex $blob]
58  set hex [string map {55540500 00000500} $hex]
59  binary decode hex $hex
60}
61
62
63# Argument $file is the name of a zip archive on disk. This function
64# executes test cases to check that the results of each of the following
65# are the same:
66#
67#         SELECT * FROM zipfile($file)
68#         SELECT * FROM zipfile( readfile($file) )
69#         SELECT * FROM zipfile(
70#           (SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file))
71#         )
72#
73proc do_zipfile_blob_test {tn file} {
74
75  db func r readfile
76  set q1 {SELECT name,mode,mtime,method,quote(data) FROM zipfile($file)}
77  set q2 {SELECT name,mode,mtime,method,quote(data) FROM zipfile( r($file) )}
78  set q3 {SELECT name,mode,mtime,method,quote(data) FROM zipfile(
79    ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
80  )}
81
82
83  set r1 [db eval $q1]
84  set r2 [db eval $q2]
85  set r3 [db eval $q3]
86  #puts $r1
87  #puts $r2
88  #puts $r3
89
90  uplevel [list do_test $tn.1 [list set {} $r2] $r1]
91  uplevel [list do_test $tn.2 [list set {} $r3] $r1]
92}
93
94# Argument $file is a zip file on disk. This command runs tests to:
95#
96#   1. Unpack the archive with unix command [unzip] and compare the
97#      results to reading the same archive using the zipfile() table
98#      valued function.
99#
100#   2. Creates a new archive with the same contents using the zipfile()
101#      aggregate function as follows:
102#
103#      SELECT writefile('test_unzip.zip',
104#          ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
105#      );
106#
107#      Then tests that unpacking the new archive using [unzip] produces
108#      the same results as in (1).
109#
110proc do_unzip_test {tn file} {
111  if {[info vars ::UNZIP]==""} { return }
112  db func sss strip_slash
113
114  db eval {
115    SELECT writefile('test_unzip.zip',
116        ( SELECT zipfile(name,mode,mtime,data,method) FROM zipfile($file) )
117    );
118  }
119
120  set r1 [db eval {
121    SELECT sss(name),mode,mtime,data FROM zipfile($file) ORDER BY name
122  }]
123  set r2 [do_unzip $file]
124  set r3 [do_unzip test_unzip.zip]
125
126  uplevel [list do_test $tn.1 [list set {} $r2] $r1]
127  uplevel [list do_test $tn.2 [list set {} $r3] $r1]
128}
129proc strip_slash {in} { regsub {/$} $in {} }
130
131proc do_zip_tests {tn file} {
132  uplevel do_zipfile_blob_test $tn.1 $file
133  uplevel do_unzip_test $tn.2 $file
134}
135
136forcedelete test.zip
137do_execsql_test 1.0 {
138  CREATE VIRTUAL TABLE temp.zz USING zipfile('test.zip');
139  PRAGMA table_info(zz);
140} {
141  0 name {} 1 {} 1
142  1 mode {} 0 {} 0
143  2 mtime {} 0 {} 0
144  3 sz {} 0 {} 0
145  4 rawdata {} 0 {} 0
146  5 data {} 0 {} 0
147  6 method {} 0 {} 0
148}
149
150do_catchsql_test 1.1.0.1 {
151  INSERT INTO zz(name, mode, mtime, sz, rawdata, method)
152  VALUES('f.txt', '-rw-r--r--', 1000000000, 5, 'abcde', 0);
153} {1 {constraint failed}}
154do_catchsql_test 1.1.0.1 {
155  INSERT INTO zz(name, mtime, sz, rawdata, method)
156  VALUES('g.txt', 1000000002, 5, '12345', 0);
157} {1 {constraint failed}}
158
159do_execsql_test 1.1.1 {
160  INSERT INTO zz(name, mode, mtime, data, method)
161  VALUES('f.txt', '-rw-r--r--', 1000000000, 'abcde', 0);
162}
163do_execsql_test 1.1.2 {
164  INSERT INTO zz(name, mode, mtime, data, method)
165  VALUES('g.txt', NULL, 1000000002, '12345', 0);
166}
167
168do_execsql_test 1.2 {
169  SELECT name, mtime, data FROM zipfile('test.zip')
170} {
171  f.txt 1000000000 abcde
172  g.txt 1000000002 12345
173}
174do_zip_tests 1.2a test.zip
175
176do_execsql_test 1.3 {
177  INSERT INTO zz(name, mode, mtime, data) VALUES('h.txt',
178    '-rw-r--r--', 1000000004, 'aaaaaaaaaabbbbbbbbbb'
179  );
180}
181do_zip_tests 1.3a test.zip
182
183do_execsql_test 1.4 {
184  SELECT name, mtime, data, method FROM zipfile('test.zip');
185} {
186  f.txt 1000000000 abcde 0
187  g.txt 1000000002 12345 0
188  h.txt 1000000004 aaaaaaaaaabbbbbbbbbb 8
189}
190
191ifcapable json1 {
192  do_execsql_test 1.4.1 {
193    SELECT name, json_extract( zipfile_cds(z) , '$.crc32')!=0
194    FROM zipfile('test.zip');
195  } {
196    f.txt 1
197    g.txt 1
198    h.txt 1
199  }
200}
201
202do_execsql_test 1.5.1 {
203  BEGIN;
204    INSERT INTO zz(name, mode, mtime, data, method)
205    VALUES('i.txt', '-rw-r--r--', 1000000006, 'zxcvb', 0);
206    SELECT name FROM zz;
207  COMMIT;
208} {f.txt g.txt h.txt i.txt}
209do_execsql_test 1.5.2 {
210  SELECT name FROM zz;
211} {f.txt g.txt h.txt i.txt}
212do_execsql_test 1.5.3 {
213  SELECT data FROM zz WHERE name='i.txt';
214} {zxcvb}
215
216do_execsql_test 1.6.0 {
217  DELETE FROM zz WHERE name='g.txt';
218  SELECT name FROM zz;
219} {f.txt h.txt i.txt}
220
221do_execsql_test 1.6.1 {
222  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
223} {
224  f.txt 33188 1000000000 abcde 0
225  h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
226  i.txt 33188 1000000006 zxcvb 0
227}
228do_zip_tests 1.6.1a test.zip
229
230do_execsql_test 1.6.2 {
231  UPDATE zz SET mtime=4 WHERE name='i.txt';
232  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
233} {
234  f.txt 33188 1000000000 abcde 0
235  h.txt 33188 1000000004 aaaaaaaaaabbbbbbbbbb 8
236  i.txt 33188 4 zxcvb 0
237}
238
239do_execsql_test 1.6.3 {
240  UPDATE zz SET mode='-rw-r--r-x' WHERE name='h.txt';
241  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
242} {
243  f.txt 33188 1000000000 abcde 0
244  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
245  i.txt 33188 4 zxcvb 0
246}
247do_zip_tests 1.6.3a test.zip
248
249do_execsql_test 1.6.4 {
250  UPDATE zz SET name = 'blue.txt' WHERE name='f.txt';
251  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
252} {
253  blue.txt 33188 1000000000 abcde 0
254  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
255  i.txt 33188 4 zxcvb 0
256}
257do_zip_tests 1.6.4a test.zip
258
259do_execsql_test 1.6.5 {
260  UPDATE zz SET data = 'edcba' WHERE name='blue.txt';
261  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
262} {
263  blue.txt 33188 1000000000 edcba 0
264  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
265  i.txt 33188 4 zxcvb 0
266}
267
268do_execsql_test 1.6.6 {
269  UPDATE zz SET mode=NULL, data = NULL WHERE name='blue.txt';
270  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
271} {
272  blue.txt/ 16877 1000000000 {} 0
273  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
274  i.txt 33188 4 zxcvb 0
275}
276
277do_catchsql_test 1.6.7 {
278  UPDATE zz SET data=NULL WHERE name='i.txt'
279} {1 {constraint failed}}
280do_execsql_test 1.6.8 {
281  SELECT name, mode, mtime, data, method FROM zipfile('test.zip');
282} {
283  blue.txt/ 16877 1000000000 {} 0
284  h.txt 33189 1000000004 aaaaaaaaaabbbbbbbbbb 8
285  i.txt 33188 4 zxcvb 0
286}
287
288#-------------------------------------------------------------------------
289db close
290forcedelete test.zip
291reset_db
292load_static_extension db fileio
293load_static_extension db zipfile
294do_execsql_test 2.1 {
295  CREATE VIRTUAL TABLE zzz USING zipfile('test.zip');
296  INSERT INTO zzz(name, mode) VALUES('dirname', 'drwxr-xr-x');
297  SELECT name, mode, data FROM zzz;
298} {dirname/ 16877 {}}
299do_execsql_test 2.2 {
300  INSERT INTO zzz(name, data) VALUES('dirname2', NULL);
301  INSERT INTO zzz(name, data) VALUES('dirname2/file1.txt', 'abcdefghijklmnop');
302  SELECT name, mode, data FROM zzz;
303} {
304  dirname/ 16877 {}
305  dirname2/ 16877 {}
306  dirname2/file1.txt 33188 abcdefghijklmnop
307}
308
309do_catchsql_test 2.3 {
310  UPDATE zzz SET name = 'dirname3' WHERE name = 'dirname/';
311} {0 {}}
312do_execsql_test 2.4 {
313  SELECT name, mode, data FROM zzz;
314} {
315  dirname3/ 16877 {}
316  dirname2/ 16877 {}
317  dirname2/file1.txt 33188 abcdefghijklmnop
318}
319do_zip_tests 2.4a test.zip
320
321# If on unix, check that the [unzip] utility can unpack our archive.
322#
323if {$::tcl_platform(platform)=="unix"} {
324  do_test 2.5.1 {
325    forcedelete dirname
326    forcedelete dirname2
327    set rc [catch { exec unzip test.zip > /dev/null } msg]
328    list $rc $msg
329  } {0 {}}
330  do_test 2.5.2 { file isdir dirname3 } 1
331  do_test 2.5.3 { file isdir dirname2 } 1
332  do_test 2.5.4 { file isdir dirname2/file1.txt } 0
333  do_test 2.5.5 {
334    set fd [open dirname2/file1.txt]
335    set data [read $fd]
336    close $fd
337    set data
338  } {abcdefghijklmnop}
339}
340
341#-------------------------------------------------------------------------
342reset_db
343forcedelete test.zip
344load_static_extension db zipfile
345
346do_execsql_test 3.0 {
347  CREATE VIRTUAL TABLE temp.x1 USING zipfile('test.zip');
348  INSERT INTO x1(name, data) VALUES('dir1/', NULL);
349  INSERT INTO x1(name, data) VALUES('file1', '1234');
350  INSERT INTO x1(name, data) VALUES('dir1/file2', '5678');
351}
352foreach {tn fname} {
353  1 dir1
354  2 file1
355  3 dir1/file2
356} {
357  do_catchsql_test 3.1.$tn.0 {
358    INSERT INTO x1(name, data) VALUES($fname, NULL);
359  } {1 {constraint failed}}
360  do_catchsql_test 3.1.$tn.1 {
361    INSERT INTO x1(name, data) VALUES($fname || '/', NULL);
362  } {1 {constraint failed}}
363  do_catchsql_test 3.1.$tn.2 {
364    INSERT INTO x1(name, data) VALUES($fname, 'abcd');
365  } {1 {constraint failed}}
366}
367
368do_catchsql_test 3.2 {
369  SELECT rowid FROM x1
370} {1 {no such column: rowid}}
371
372#-------------------------------------------------------------------------
373# Test some error conditions.
374#
375do_catchsql_test 4.1 {
376  CREATE VIRTUAL TABLE yyy USING zipfile();
377} {1 {zipfile constructor requires one argument}}
378do_catchsql_test 4.2 {
379  CREATE VIRTUAL TABLE yyy USING zipfile('test.zip', 'test.zip');
380} {1 {zipfile constructor requires one argument}}
381
382#--------------------------------------------------------------------------
383
384db func rt remove_timestamps
385do_execsql_test 5.0 {
386  WITH c(name,mtime,data) AS (
387    SELECT 'a.txt', 946684800, 'abc'
388  )
389  SELECT name,mtime,data FROM zipfile(
390    ( SELECT rt( zipfile(name,NULL,mtime,data) ) FROM c )
391  )
392} {
393  a.txt 946684800 abc
394}
395
396if {[info vars ::UNZIP]!=""} {
397ifcapable datetime {
398  load_static_extension db fileio
399  forcedelete test1.zip test2.zip
400  do_test 6.0 {
401    execsql {
402      WITH c(name,mtime,data) AS (
403        SELECT 'a.txt', 946684800, 'abc' UNION ALL
404        SELECT 'b.txt', 1000000000, 'abc' UNION ALL
405        SELECT 'c.txt', 1111111000, 'abc'
406      )
407      SELECT writefile('test1.zip', rt( zipfile(name, NULL, mtime, data) ) ),
408             writefile('test2.zip',   ( zipfile(name, NULL, mtime, data) ) )
409      FROM c;
410    }
411    forcedelete test_unzip
412    file mkdir test_unzip
413    exec unzip -d test_unzip test1.zip
414
415    db eval {
416      SELECT name, strftime('%s', mtime, 'unixepoch', 'localtime')
417      FROM fsdir('test_unzip') WHERE name!='test_unzip'
418      ORDER BY name
419    }
420  } [list {*}{
421    test_unzip/a.txt 946684800
422    test_unzip/b.txt 1000000000
423    test_unzip/c.txt 1111111000
424  }]
425
426  do_test 6.1 {
427    forcedelete test_unzip
428    file mkdir test_unzip
429    exec unzip -d test_unzip test2.zip
430
431    db eval {
432      SELECT name, mtime
433      FROM fsdir('test_unzip') WHERE name!='test_unzip'
434      ORDER BY name
435    }
436  } [list {*}{
437    test_unzip/a.txt 946684800
438    test_unzip/b.txt 1000000000
439    test_unzip/c.txt 1111111000
440  }]
441}
442}
443
444
445finish_test
446
447