1#!/bin/bash
2#
3# Copyright 2008 Google Inc.
4# Author: Lincoln Smith
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#      http:#www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18# This script tests the correctness of the vcdiff command-line executable.
19# If you add a new test here, please add the same test to the Windows script
20# vsprojects/vcdiff_test.bat.
21#
22# The caller should set the environment variable $srcdir to the root directory
23# of the open-vcdiff package.  ($srcdir is automatically provided by Automake
24# when this script is run by "make check".)
25
26# Find input files
27VCDIFF=./vcdiff
28# These options are only needed for the encoder;
29# the decoder will recognize the interleaved and checksum formats
30# without needing to specify any options.
31VCD_OPTIONS="-interleaved -checksum"
32DICTIONARY_FILE=$srcdir/testdata/configure.ac.v0.1
33TARGET_FILE=$srcdir/testdata/configure.ac.v0.2
34TEST_TMPDIR=${TMPDIR-/tmp}
35DELTA_FILE=$TEST_TMPDIR/configure.ac.vcdiff
36OUTPUT_TARGET_FILE=$TEST_TMPDIR/configure.ac.output
37MALICIOUS_ENCODING=$srcdir/testdata/allocates_4gb.vcdiff
38
39# vcdiff with no arguments shows usage information & error result
40$VCDIFF \
41&& { echo "vcdiff with no arguments should fail, but succeeded"; \
42     exit 1; }
43echo "Test 1 ok";
44
45# vcdiff with three arguments but without "encode" or "decode"
46# shows usage information & error result
47$VCDIFF $VCD_OPTIONS \
48        -dictionary $DICTIONARY_FILE -target $TARGET_FILE -delta $DELTA_FILE \
49&& { echo "vcdiff without operation argument should fail, but succeeded"; \
50     exit 1; }
51echo "Test 2 ok";
52
53# vcdiff with all three arguments.  Verify that output file matches target file
54$VCDIFF $VCD_OPTIONS \
55        encode -dictionary $DICTIONARY_FILE \
56               -target $TARGET_FILE \
57               -delta $DELTA_FILE \
58|| { echo "Encode with three arguments failed"; \
59     exit 1; }
60$VCDIFF decode -dictionary $DICTIONARY_FILE \
61               -delta $DELTA_FILE \
62               -target $OUTPUT_TARGET_FILE \
63|| { echo "Decode with three arguments failed"; \
64     exit 1; }
65cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
66|| { echo "Decoded target does not match original"; \
67     exit 1; }
68echo "Test 3 ok";
69
70rm $DELTA_FILE
71rm $OUTPUT_TARGET_FILE
72
73# vcdiff using stdin/stdout.  Verify that output file matches target file
74{ $VCDIFF $VCD_OPTIONS \
75          encode -dictionary $DICTIONARY_FILE \
76                 < $TARGET_FILE \
77                 > $DELTA_FILE; } \
78|| { echo "Encode using stdin/stdout failed"; \
79     exit 1; }
80{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
81                 < $DELTA_FILE \
82                 > $OUTPUT_TARGET_FILE; } \
83|| { echo "Decode using stdin/stdout failed"; \
84     exit 1; }
85cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
86|| { echo "Decoded target does not match original"; \
87     exit 1; }
88echo "Test 4 ok";
89
90rm $DELTA_FILE
91rm $OUTPUT_TARGET_FILE
92
93# vcdiff with mixed stdin/stdout.
94{ $VCDIFF $VCD_OPTIONS \
95          encode -dictionary $DICTIONARY_FILE \
96                 -target $TARGET_FILE \
97                 > $DELTA_FILE; } \
98|| { echo "Encode with mixed arguments failed"; \
99     exit 1; }
100{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
101                 -delta $DELTA_FILE \
102                 > $OUTPUT_TARGET_FILE; } \
103|| { echo "Decode with mixed arguments failed"; \
104     exit 1; }
105cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
106|| { echo "Decoded target does not match original"; \
107     exit 1; }
108echo "Test 5 ok";
109
110rm $DELTA_FILE
111rm $OUTPUT_TARGET_FILE
112
113{ $VCDIFF $VCD_OPTIONS \
114          encode -dictionary $DICTIONARY_FILE \
115                 < $TARGET_FILE \
116                 -delta $DELTA_FILE; } \
117|| { echo "Encode with mixed arguments failed"; \
118     exit 1; }
119{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
120                 < $DELTA_FILE \
121                 -target $OUTPUT_TARGET_FILE; } \
122|| { echo "Decode with mixed arguments failed"; \
123     exit 1; }
124cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
125|| { echo "Decoded target does not match original"; \
126     exit 1; }
127echo "Test 6 ok";
128
129rm $OUTPUT_TARGET_FILE
130# Don't remove $DELTA_FILE; use it for the next test
131
132# If using the wrong dictionary, and dictionary is smaller than the original
133# dictionary, vcdiff will spot the mistake and return an error.  (It can't
134# detect the case where the wrong dictionary is larger than the right one.)
135$VCDIFF decode -dictionary $TARGET_FILE \
136               -delta $DELTA_FILE \
137               -target $OUTPUT_TARGET_FILE \
138&& { echo "Decode using larger dictionary should fail, but succeeded"; \
139     exit 1; }
140echo "Test 7 ok";
141
142rm $DELTA_FILE
143rm $OUTPUT_TARGET_FILE
144
145# "vcdiff test" with all three arguments.
146$VCDIFF $VCD_OPTIONS \
147        test -dictionary $DICTIONARY_FILE \
148             -target $TARGET_FILE \
149             -delta $DELTA_FILE \
150|| { echo "vcdiff test with three arguments failed"; \
151     exit 1; }
152echo "Test 8 ok";
153
154rm $DELTA_FILE
155
156# Dictionary file not found.
157$VCDIFF $VCD_OPTIONS \
158        encode -dictionary $TEST_TMPDIR/nonexistent_file \
159               -target $TARGET_FILE \
160               -delta $DELTA_FILE \
161&& { echo "vcdiff with missing dictionary file should fail, but succeeded"; \
162     exit 1; }
163echo "Test 9 ok";
164
165# Target file not found.
166$VCDIFF $VCD_OPTIONS \
167        encode -dictionary $DICTIONARY_FILE \
168               -target $TEST_TMPDIR/nonexistent_file \
169               -delta $DELTA_FILE \
170&& { echo "vcdiff with missing target file should fail, but succeeded"; \
171     exit 1; }
172echo "Test 10 ok";
173
174# Delta file not found.
175$VCDIFF decode -dictionary $DICTIONARY_FILE \
176               -delta $TEST_TMPDIR/nonexistent_file \
177               -target $OUTPUT_TARGET_FILE \
178&& { echo "vcdiff with missing delta file should fail, but succeeded"; \
179     exit 1; }
180echo "Test 11 ok";
181
182# Try traversing an infinite loop of symbolic links.
183ln -s $TEST_TMPDIR/infinite_loop1 $TEST_TMPDIR/infinite_loop2
184ln -s $TEST_TMPDIR/infinite_loop2 $TEST_TMPDIR/infinite_loop1
185$VCDIFF $VCD_OPTIONS \
186        encode -dictionary $TEST_TMPDIR/infinite_loop1 \
187               -target $TEST_TMPDIR/infinite_loop2 \
188               -delta $DELTA_FILE \
189&& { echo "vcdiff with symbolic link loop should fail, but succeeded"; \
190     exit 1; }
191echo "Test 12 ok";
192
193rm $TEST_TMPDIR/infinite_loop1 $TEST_TMPDIR/infinite_loop2
194
195# Test using -stats flag
196$VCDIFF $VCD_OPTIONS \
197        encode -dictionary $DICTIONARY_FILE \
198               -target $TARGET_FILE \
199               -delta $DELTA_FILE \
200               -stats \
201|| { echo "Encode with -stats failed"; \
202     exit 1; }
203$VCDIFF -stats \
204        decode -dictionary $DICTIONARY_FILE \
205               -delta $DELTA_FILE \
206               -target $OUTPUT_TARGET_FILE \
207|| { echo "Decode with -stats failed"; \
208     exit 1; }
209cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
210|| { echo "Decoded target does not match original"; \
211     exit 1; }
212echo "Test 13 ok";
213
214rm $DELTA_FILE
215rm $OUTPUT_TARGET_FILE
216
217# Using /dev/null as dictionary should work, but (because dictionary is empty)
218# it will not produce a small delta file.
219$VCDIFF $VCD_OPTIONS \
220        test -dictionary /dev/null \
221             -target $TARGET_FILE \
222             -delta $DELTA_FILE \
223             -stats \
224|| { echo "vcdiff test with /dev/null as dictionary failed"; \
225     exit 1; }
226echo "Test 14 ok";
227
228rm $DELTA_FILE
229
230# Using /dev/kmem as dictionary or target should produce an error
231# (permission denied, or too large, or special file type)
232$VCDIFF $VCD_OPTIONS \
233        encode -dictionary /dev/kmem \
234               -target $TARGET_FILE \
235               -delta $DELTA_FILE \
236&& { echo "vcdiff with /dev/kmem as dictionary should fail, but succeeded"; \
237     exit 1; }
238echo "Test 15 ok";
239
240$VCDIFF $VCD_OPTIONS \
241        encode -dictionary $DICTIONARY_FILE \
242               -target /dev/kmem \
243               -delta $DELTA_FILE \
244&& { echo "vcdiff with /dev/kmem as target should fail, but succeeded"; \
245     exit 1; }
246echo "Test 16 ok";
247
248# Decode using something that isn't a delta file
249$VCDIFF decode -dictionary $DICTIONARY_FILE \
250               -delta /etc/fstab \
251               -target $OUTPUT_TARGET_FILE \
252&& { echo "vcdiff with invalid delta file should fail, but succeeded"; \
253     exit 1; }
254echo "Test 17 ok";
255
256$VCDIFF $VCD_OPTIONS \
257        encode -target $TARGET_FILE \
258               -delta $DELTA_FILE \
259               -dictionary \
260&& { echo "-dictionary option with no file name should fail, but succeeded"; \
261     exit 1; }
262echo "Test 18 ok";
263
264$VCDIFF $VCD_OPTIONS \
265        encode -dictionary $DICTIONARY_FILE \
266               -delta $DELTA_FILE \
267               -target \
268&& { echo "-target option with no file name should fail, but succeeded"; \
269     exit 1; }
270echo "Test 19 ok";
271
272$VCDIFF $VCD_OPTIONS \
273        encode -dictionary $DICTIONARY_FILE \
274               -target $TARGET_FILE \
275               -delta \
276&& { echo "-delta option with no file name should fail, but succeeded"; \
277     exit 1; }
278echo "Test 20 ok";
279
280$VCDIFF $VCD_OPTIONS \
281        encode -dictionary $DICTIONARY_FILE \
282               -target $TARGET_FILE \
283               -delta $DELTA_FILE \
284               -buffersize \
285&& { echo "-buffersize option with no argument should fail, but succeeded"; \
286     exit 1; }
287echo "Test 21 ok";
288
289# Using -buffersize=1 should still work.
290$VCDIFF $VCD_OPTIONS \
291        test -dictionary $DICTIONARY_FILE \
292             -target $TARGET_FILE \
293             -delta $DELTA_FILE \
294             -buffersize 1 \
295             -stats \
296|| { echo "vcdiff test with -buffersize=1 failed"; \
297     exit 1; }
298echo "Test 22 ok";
299
300rm $DELTA_FILE
301
302# Using -buffersize=1 with stdin/stdout means that vcdiff
303# will create a separate target window for each byte read.
304{ $VCDIFF encode -dictionary $DICTIONARY_FILE \
305                 -buffersize 1 \
306                 -stats \
307                 < $TARGET_FILE \
308                 > $DELTA_FILE; } \
309|| { echo "Encode using stdin/stdout with -buffersize=1 failed"; \
310     exit 1; }
311{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
312                 -buffersize 1 \
313                 -stats \
314                 < $DELTA_FILE \
315                 > $OUTPUT_TARGET_FILE; } \
316|| { echo "Decode using stdin/stdout with -buffersize=1 failed"; \
317     exit 1; }
318cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
319|| { echo "Decoded target does not match original with -buffersize=1"; \
320     exit 1; }
321echo "Test 23 ok";
322
323rm $DELTA_FILE
324rm $OUTPUT_TARGET_FILE
325
326# Using -buffersize=0 should fail.
327$VCDIFF $VCD_OPTIONS \
328        test -dictionary $DICTIONARY_FILE \
329             -target $TARGET_FILE \
330             -delta $DELTA_FILE \
331             -buffersize 0 \
332&& { echo "vcdiff test with -buffersize=0 should fail, but succeeded"; \
333     exit 1; }
334echo "Test 24 ok";
335
336rm $DELTA_FILE
337
338# Using -buffersize=128M (larger than default maximum) should still work.
339$VCDIFF $VCD_OPTIONS \
340        test -dictionary $DICTIONARY_FILE \
341             -target $TARGET_FILE \
342             -delta $DELTA_FILE \
343             -buffersize 134217728 \
344             -stats \
345|| { echo "vcdiff test with -buffersize=128M failed"; \
346     exit 1; }
347echo "Test 25 ok";
348
349rm $DELTA_FILE
350
351$VCDIFF $VCD_OPTIONS \
352        test -dictionary $DICTIONARY_FILE \
353             -target $TARGET_FILE \
354             -delta $DELTA_FILE \
355             -froobish \
356&& { echo "vdiff test with unrecognized option should fail, but succeeded"; \
357     exit 1; }
358echo "Test 26 ok";
359
360$VCDIFF $VCD_OPTIONS \
361        encode -target $TARGET_FILE \
362               -delta $DELTA_FILE \
363&& { echo "encode with no dictionary option should fail, but succeeded"; \
364     exit 1; }
365echo "Test 27 ok";
366
367$VCDIFF decode -target $TARGET_FILE \
368               -delta $DELTA_FILE \
369&& { echo "decode with no dictionary option should fail, but succeeded"; \
370     exit 1; }
371echo "Test 28 ok";
372
373# Remove -interleaved and -checksum options
374{ $VCDIFF encode -dictionary $DICTIONARY_FILE \
375                 < $TARGET_FILE \
376                 > $DELTA_FILE; } \
377|| { echo "Encode without -interleaved and -checksum options failed"; \
378     exit 1; }
379{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
380                 < $DELTA_FILE \
381                 > $OUTPUT_TARGET_FILE; } \
382|| { echo "Decode non-interleaved output failed"; \
383     exit 1; }
384cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
385|| { echo "Decoded target does not match original with -interleaved"; \
386     exit 1; }
387echo "Test 29 ok";
388
389# -target_matches option
390{ $VCDIFF encode -dictionary $DICTIONARY_FILE \
391                 -target_matches \
392                 -stats \
393                 < $TARGET_FILE \
394                 > $DELTA_FILE; } \
395|| { echo "Encode with -target_matches option failed"; \
396     exit 1; }
397# The decode operation ignores the -target_matches option.
398{ $VCDIFF decode -dictionary $DICTIONARY_FILE \
399                 < $DELTA_FILE \
400                 > $OUTPUT_TARGET_FILE; } \
401|| { echo "Decode output failed with -target_matches"; \
402     exit 1; }
403cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
404|| { echo "Decoded target does not match original with -target_matches"; \
405     exit 1; }
406echo "Test 30 ok";
407
408rm $DELTA_FILE
409rm $OUTPUT_TARGET_FILE
410
411$VCDIFF $VCD_OPTIONS \
412        dencode -dictionary $DICTIONARY_FILE \
413                -target $TARGET_FILE \
414                -delta $DELTA_FILE \
415&& { echo "vdiff with unrecognized action should fail, but succeeded"; \
416     exit 1; }
417echo "Test 31 ok";
418
419$VCDIFF $VCD_OPTIONS \
420        test -dictionary $DICTIONARY_FILE \
421             -target $TARGET_FILE \
422&& { echo "vdiff test without delta option should fail, but succeeded"; \
423     exit 1; }
424echo "Test 32 ok";
425
426$VCDIFF $VCD_OPTIONS \
427        test -dictionary $DICTIONARY_FILE \
428             -delta $DELTA_FILE \
429&& { echo "vdiff test without target option should fail, but succeeded"; \
430     exit 1; }
431echo "Test 33 ok";
432
433# open-vcdiff bug 8 (http://code.google.com/p/open-vcdiff/issues/detail?id=8)
434# A malicious encoding that tries to produce a 4GB target file made up of 64
435# windows, each window having a size of 64MB.
436# Limit memory usage to 256MB per process, so the test doesn't take forever
437# to run out of memory.
438OLD_ULIMIT=$(ulimit -v)
439echo "Old ulimit: $OLD_ULIMIT"
440ulimit -S -v 262144
441echo "New ulimit: $(ulimit -v)"
442
443$VCDIFF $VCD_OPTIONS \
444    decode -dictionary $DICTIONARY_FILE \
445           -delta $MALICIOUS_ENCODING \
446           -target /dev/null \
447           -max_target_file_size=65536 \
448&& { echo "Decoding malicious file should fail, but succeeded"; \
449     exit 1; }
450echo "Test 34 ok";
451
452$VCDIFF $VCD_OPTIONS \
453    decode -dictionary $DICTIONARY_FILE \
454           -delta $MALICIOUS_ENCODING \
455           -target /dev/null \
456           -max_target_window_size=65536 \
457&& { echo "Decoding malicious file should fail, but succeeded"; \
458     exit 1; }
459echo "Test 35 ok";
460
461ulimit -S -v $OLD_ULIMIT
462
463# Decoding a small target with the -max_target_file_size option should succeed.
464$VCDIFF $VCD_OPTIONS \
465        test -dictionary $DICTIONARY_FILE \
466             -target $TARGET_FILE \
467             -delta $DELTA_FILE \
468             -max_target_file_size=65536 \
469|| { echo "vcdiff test with -max_target_file_size failed"; \
470     exit 1; }
471echo "Test 36 ok";
472
473# Decoding a small target with -max_target_window_size option should succeed.
474$VCDIFF $VCD_OPTIONS \
475        test -dictionary $DICTIONARY_FILE \
476             -target $TARGET_FILE \
477             -delta $DELTA_FILE \
478             -max_target_window_size=65536 \
479|| { echo "vcdiff test with -max_target_window_size failed"; \
480     exit 1; }
481echo "Test 37 ok";
482
483rm $DELTA_FILE
484
485# Test using -allow_vcd_target=false
486$VCDIFF $VCD_OPTIONS \
487        encode -dictionary $DICTIONARY_FILE \
488               -target $TARGET_FILE \
489               -delta $DELTA_FILE \
490               -allow_vcd_target=false \
491|| { echo "Encode with -allow_vcd_target=false failed"; \
492     exit 1; }
493$VCDIFF $VCD_OPTIONS \
494        decode -dictionary $DICTIONARY_FILE \
495               -delta $DELTA_FILE \
496               -target $OUTPUT_TARGET_FILE \
497               -allow_vcd_target=false \
498|| { echo "Decode with -allow_vcd_target=false failed"; \
499     exit 1; }
500cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
501|| { echo "Decoded target does not match original"; \
502     exit 1; }
503echo "Test 38 ok";
504
505rm $DELTA_FILE
506rm $OUTPUT_TARGET_FILE
507
508# Test using -allow_vcd_target=true
509$VCDIFF $VCD_OPTIONS \
510        encode -dictionary $DICTIONARY_FILE \
511               -target $TARGET_FILE \
512               -delta $DELTA_FILE \
513               -allow_vcd_target=true \
514|| { echo "Encode with -allow_vcd_target=true failed"; \
515     exit 1; }
516$VCDIFF $VCD_OPTIONS \
517        decode -dictionary $DICTIONARY_FILE \
518               -delta $DELTA_FILE \
519               -target $OUTPUT_TARGET_FILE \
520               -allow_vcd_target=true \
521|| { echo "Decode with -allow_vcd_target=true failed"; \
522     exit 1; }
523cmp $TARGET_FILE $OUTPUT_TARGET_FILE \
524|| { echo "Decoded target does not match original"; \
525     exit 1; }
526echo "Test 39 ok";
527
528echo "PASS"
529