set -u
. "$TESTSDIR"/test.inc

# First test if finding the binaries works properly...

testrun - --lunzip=NONE --unxz=NONE __dumpuncompressors 3<<EOF
stdout
*=.gz: built-in + '/bin/gunzip'
*=.bz2: built-in + '/bin/bunzip2'
*=.lzma: built-in + '/usr/bin/unlzma'
*=.xz: built-in
*=.lz: not supported (install lzip or use --lunzip to tell where lunzip is).
EOF

testrun - --lunzip=NONE --gunzip=NONE --bunzip2=NONE --unlzma=NONE --unxz=NONE __dumpuncompressors 3<<EOF
stdout
*=.gz: built-in
*=.bz2: built-in
*=.lzma: built-in
*=.xz: built-in
*=.lz: not supported (install lzip or use --lunzip to tell where lunzip is).
EOF

testrun - --lunzip=NONE --gunzip=false --bunzip2=false --unlzma=false --unxz=NONE __dumpuncompressors 3<<EOF
stdout
*=.gz: built-in + '/bin/false'
*=.bz2: built-in + '/bin/false'
*=.lzma: built-in + '/bin/false'
*=.xz: built-in
*=.lz: not supported (install lzip or use --lunzip to tell where lunzip is).
EOF

touch fakeg fakeb fakel fakexz fakelz

testrun - --lunzip=./fakelz --gunzip=./fakeg --bunzip2=./fakeb --unlzma=./fakel --unxz=./fakexz __dumpuncompressors 3<<EOF
stdout
*=.gz: built-in
*=.bz2: built-in
*=.lzma: built-in
*=.xz: built-in
*=.lz: not supported (install lzip or use --lunzip to tell where lunzip is).
EOF

chmod u+x fakeg fakeb fakel fakexz fakelz

testrun - --lunzip=./fakelz --gunzip=./fakeg --bunzip2=./fakeb --unlzma=./fakel --unxz=./fakexz __dumpuncompressors 3<<EOF
stdout
*=.gz: built-in + './fakeg'
*=.bz2: built-in + './fakeb'
*=.lzma: built-in + './fakel'
*=.xz: built-in + './fakexz'
*=.lz: './fakelz'
EOF

rm fakeg fakeb fakel fakexz fakelz

# Then test the builtin formats and the external one...

echo "start" > testfile
dd if=/dev/zero bs=1024 count=1024 >> testfile
echo "" >> testfile
echo "middle" >> testfile
dd if=/dev/zero bs=1024 count=1024 >> testfile
echo "" >> testfile
echo "end" >> testfile

echo "Ohm" > smallfile

echo gzip -c testfile \> testfile.gz
gzip -c testfile > testfile.gz
echo bzip2 -c testfile \> testfile.bz2
bzip2 -c testfile > testfile.bz2
echo lzma -c testfile \> testfile.lzma
lzma -c testfile > testfile.lzma
echo xz -c testfile \> testfile.xz
xz -c testfile > testfile.xz

echo gzip -c smallfile \> smallfile.gz
gzip -c smallfile > smallfile.gz
echo bzip2 -c smallfile \> smallfile.bz2
bzip2 -c smallfile > smallfile.bz2
echo lzma -c smallfile \> smallfile.lzma
lzma -c smallfile > smallfile.lzma
echo xz -c smallfile \> smallfile.xz
xz -c smallfile > smallfile.xz

echo gzip -c \< /dev/null \> emptyfile.gz
gzip -c < /dev/null > emptyfile.gz
echo bzip2 -c \< /dev/null \> emptyfile.bz2
bzip2 -c < /dev/null > emptyfile.bz2
echo lzma -c \< /dev/null \> emptyfile.lzma
lzma -c < /dev/null > emptyfile.lzma
echo xz -c \< /dev/null \> emptyfile.xz
xz -c < /dev/null > emptyfile.xz

testrun - --lunzip /bin/cat __uncompress .lz notexists.lz notexists.lz.uncompressed 3<<EOF
-v2*=Uncompress 'notexists.lz' into 'notexists.lz.uncompressed' using '/bin/cat'...
*=Error 2 opening notexists.lz: No such file or directory
-v0*=There have been errors!
returns 254
EOF

if test -x /usr/bin/lzip ; then
# uncompression message is different as this is no builtin.
echo lzip -c testfile \> testfile.lz
lzip -c testfile > testfile.lz
echo lzip -c smallfile \> smallfile.lz
lzip -c smallfile > smallfile.lz
testrun - __uncompress .lz testfile.lz testfile.lz.uncompressed 3<<EOF
-v2*=Uncompress 'testfile.lz' into 'testfile.lz.uncompressed' using '/usr/bin/lunzip'...
EOF
dodiff testfile testfile.lz.uncompressed
rm *.uncompressed
testrun - __uncompress .lz smallfile.lz smallfile.lz.uncompressed 3<<EOF
-v2*=Uncompress 'smallfile.lz' into 'smallfile.lz.uncompressed' using '/usr/bin/lunzip'...
EOF
dodiff smallfile smallfile.lz.uncompressed
rm *.uncompressed
fi

for ext in gz bz2 lzma xz ; do
	testrun - __uncompress .${ext} testfile.${ext} testfile.${ext}.uncompressed 3<<EOF
-v2*=Uncompress 'testfile.${ext}' into 'testfile.${ext}.uncompressed'...
EOF
	dodiff testfile testfile.${ext}.uncompressed
	rm *.uncompressed

	testrun - __uncompress .${ext} smallfile.${ext} smallfile.${ext}.uncompressed 3<<EOF
-v2*=Uncompress 'smallfile.${ext}' into 'smallfile.${ext}.uncompressed'...
EOF
	dodiff smallfile smallfile.${ext}.uncompressed
	rm *.uncompressed
done

# unlzma does not support concatenated files, so we do neither.
for ext in gz bz2 xz ; do
	cat testfile.${ext} emptyfile.${ext} > concatenatedtestfile.${ext}
	testrun - __uncompress .${ext} concatenatedtestfile.${ext} concatenatedtestfile.${ext}.uncompressed 3<<EOF
-v2*=Uncompress 'concatenatedtestfile.${ext}' into 'concatenatedtestfile.${ext}.uncompressed'...
EOF
	dodiff testfile concatenatedtestfile.${ext}.uncompressed
	rm concatenated*

	cat testfile testfile > concatenatedtestfile
	cat testfile.${ext} testfile.${ext} > concatenatedtestfile.${ext}
	testrun - __uncompress .${ext} concatenatedtestfile.${ext} concatenatedtestfile.${ext}.uncompressed 3<<EOF
-v2*=Uncompress 'concatenatedtestfile.${ext}' into 'concatenatedtestfile.${ext}.uncompressed'...
EOF
	dodiff concatenatedtestfile concatenatedtestfile.${ext}.uncompressed
	rm concatenated*
done

# Test for trailing garbage detection
for ext in gz bz2 lzma ; do
	cat testfile.${ext} smallfile > invalidtestfile.${ext}
	testrun - __uncompress .${ext} invalidtestfile.${ext} invalidtestfile.${ext}.uncompressed 3<<EOF
stderr
-v2*=Uncompress 'invalidtestfile.${ext}' into 'invalidtestfile.${ext}.uncompressed'...
*=Error reading from invalidtestfile.${ext}: Trailing garbage after compressed data!
-v0*=There have been errors!
returns 255
EOF
	dodo test ! -e invalidtestfile.${ext}.uncompressed
	rm invalid*
done

# .xz does not see the trailing stuff, but an end of file while reading the header:
cat testfile.xz smallfile > invalidtestfile.xz
testrun - __uncompress .xz invalidtestfile.xz invalidtestfile.xz.uncompressed 3<<EOF
stderr
-v2*=Uncompress 'invalidtestfile.xz' into 'invalidtestfile.xz.uncompressed'...
*=Error 10 decompressing lzma data
*=Error reading from invalidtestfile.xz: Uncompression error!
-v0*=There have been errors!
returns 255
EOF
dodo test ! -e invalidtestfile.xz.uncompressed
rm invalid*

touch fake.lz
testrun - --lunzip=false __uncompress .lz fake.lz fake.lz.uncompressed 3<<EOF
-v2*=Uncompress 'fake.lz' into 'fake.lz.uncompressed' using '/bin/false'...
*='/bin/false' < fake.lz > fake.lz.uncompressed exited with errorcode 1!
-v0*=There have been errors!
returns 255
EOF
dodo test ! -e fake.lz.uncompressed


# Now check for compressed parts of an .a file:

cat > control <<EOF
Package: fake
Version: fake
Architecture: all
EOF

# looks like control.tar.lzma is not possible because the name is too
# long for the old ar format dpkg-deb needs...
echo tar -cf - ./control \| bzip2 \> control.tar.bz2
tar -cf - ./control | bzip2 > control.tar.bz2
echo tar -cf - testfile\* \| lzma \> data.tar.lzma
tar -cf - testfile* | lzma > data.tar.lzma
echo tar -cf - testfile\* \| bzip2 \> data.tar.bz2
tar -cf - testfile* | bzip2 > data.tar.bz2
echo tar -cf - testfile\* \| gzip \> data.tar.gz
tar -cf - testfile* | gzip > data.tar.gz
echo tar -cf - testfile\* \| xz \> data.tar.xz
tar -cf - testfile* | xz > data.tar.xz
echo 2.0 > debian-binary
datatestlist="gz bz2 lzma xz"
for ext in $datatestlist ; do
	dodo ar qcfS fake_${ext}.deb debian-binary control.tar.bz2 data.tar.${ext}
	# one .deb with trailing garbage at the end of the data tar:
	echo "trailing garbage" >> data.tar.${ext}
	dodo ar qcfS fake_${ext}_t.deb debian-binary control.tar.bz2 data.tar.${ext}
	# and one .deb where the the length is correct but the .ar header differs
	cp fake_${ext}_t.deb fake_${ext}_w.deb
	origlength=$(stat -c '%s' fake_${ext}.deb)
	newlength=$(stat -c '%s' fake_${ext}_w.deb)
	if test $((origlength + 18)) -eq $((newlength)) ; then
		# new length is 17 + one padding, so original did not have padding:
		truncate -s "$origlength" fake_${ext}_w.deb
	else
		# also remove the padding byte:
		truncate -s "$((origlength - 1))" fake_${ext}_w.deb
	fi
done
rm debian-binary control *.tar.*

# TODO: there could be a problem here with .deb files that have data after the
# ./control file in data.tar and using an external uncompressor.
# But how to test this when there is no way to trigger it in the default built?

testrun - __extractcontrol fake_gz.deb 3<<EOF
stdout
*=Package: fake
*=Version: fake
*=Architecture: all
*=
EOF
for ext in $datatestlist ; do
testrun - __extractfilelist fake_${ext}.deb 3<<EOF
stdout
*=/testfile
*=/testfile.bz2
*=/testfile.gz
*=/testfile.lzma
=/testfile.xz
=/testfile.lz
EOF
	if test $ext = xz ; then
testrun - __extractfilelist fake_${ext}_t.deb 3<<EOF
stderr
*=Error 9 decompressing lzma data
*=Error reading data.tar from fake_xz_t.deb: Uncompression error
-v0*=There have been errors!
return 255
EOF
	else
testrun - __extractfilelist fake_${ext}_t.deb 3<<EOF
stderr
*=Error reading data.tar from fake_${ext}_t.deb: Trailing garbage after compressed data
-v0*=There have been errors!
return 255
EOF
	fi
	if test $ext = xz ; then
		: # xz has too large blocks to trigger this (tar is done before this is read)
	else
testrun - __extractfilelist fake_${ext}_w.deb 3<<EOF
*=Error reading data.tar from fake_${ext}_w.deb: Compressed data of unexpected length
-v0*=There have been errors!
return 255
EOF
	fi
done

rm fake_*.deb

for compressor in lz lzma ; do
case $compressor in
	lz)
		compressor_program=lzip
		uncompressor=lunzip
	;;
	lzma)
		compressor_program=lzma
		uncompressor=""
	;;
esac
export uncompressor
if ! test -x /usr/bin/$compressor_program ; then
	echo "SKIPPING $compressor because /usr/bin/$compressor_program is missing!"
	continue
fi

# Now check extracting Section/Priority from an .dsc
mkdir debian
cat > debian/control <<EOF
Package: fake
Maintainer: Me
Section: admin
Priority: extra

Package: abinary
Architecture: all
EOF
echo generating fake dirs
for n in $(seq 100000) ; do echo "/$n"  ; done > debian/dirs
dd if=/dev/zero of=debian/zzz bs=1024 count=4096
tar -cf - debian | $compressor_program > fake_1-1.debian.tar.$compressor
mkdir fake-1
mkdir fake-1.orig
cp -al debian fake-1/debian
cp -al debian fake-1.orig/debian
sed -e 's/1/2/' fake-1/debian/dirs > fake-1/debian.dirs.new
mv fake-1/debian.dirs.new fake-1/debian/dirs
diff -ruN fake-1.orig fake-1 | $compressor_program > fake_1-1.diff.$compressor
rm -r debian

# .debian.tar and .diff usually do not happen at the same time, but easier testing...
cat > fake_1-1.dsc << EOF
Format: 3.0
Source: fake
Binary: abinary
Architecture: all
Version: 17
Maintainer: Me
Files:
 $(mdandsize fake_1-1.diff.${compressor}) fake_1-1.diff.${compressor}
 $(mdandsize fake_1-1.debian.tar.${compressor}) fake_1-1.debian.tar.${compressor}
 00000000000000000000000000000000 0 fake_1.orig.tar.${compressor}
EOF

testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
stdout
*=Section: admin
*=Priority: extra
EOF

# It would be nice to damage the .lzma file here, but that has a problem:
# A random damage to the file will usually lead to some garbage output
# before lzma realizes the error.
# Once reprepro sees the garbage (which will usually not be a valid diff)
# it will decide it is a format it does not understand and abort further
# reading giving up.
# This is a race condition with one of the following results:
#   reprepro is much faster: no error output (as unknown format is no error,
#                                             but only no success)
#   reprepro a bit faster: unlzma can still output an error, but not
#                          is terminated by reprepro before issuing an error code.
#   unlzma is faster: reprepro will see an child returning with error...
#
# Thus we can only fake a damaged file by replacing the uncompressor:

if test -n "${uncompressor}" ; then
testrun - --${uncompressor}=brokenuncompressor.sh __extractsourcesection fake_1-1.dsc 3<<EOF
returns 255
*=brokenuncompressor.sh: claiming broken archive
*=Error reading from ./fake_1-1.diff.${compressor}: $TESTSDIR/brokenuncompressor.sh exited with code 1!
-v0*=There have been errors!
stdout
EOF
fi

mv fake_1-1.debian.tar.${compressor} save.tar.${compressor}

# a missing file is no error, but no success either...
testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
stdout
EOF

cp save.tar.${compressor} fake_1.orig.tar.${compressor}
# a missing file is no error, but no success either (and not reading further files)
testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
stdout
EOF

dodo mkdir debian
dodo touch debian/test
echo tar -cf - debian \| ${compressor_program} \> fake_1-1.debian.tar.${compressor}
tar -cf - debian | ${compressor_program} > fake_1-1.debian.tar.${compressor}
rm -r debian

testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
stdout
*=Section: admin
*=Priority: extra
EOF

if test -n "${uncompressor}" ; then
touch breakon2nd
testrun - --${uncompressor}=brokenuncompressor.sh __extractsourcesection fake_1-1.dsc 3<<EOF
returns 255
*=brokenuncompressor.sh: claiming broken archive
*=Error reading from ./fake_1-1.debian.tar.${compressor}: $TESTSDIR/brokenuncompressor.sh exited with code 1!
-v0*=There have been errors!
stdout
EOF

testrun - --${uncompressor}=brokenuncompressor.sh __extractsourcesection fake_1-1.dsc 3<<EOF
returns 255
*=brokenuncompressor.sh: claiming broken archive
*=Error reading from ./fake_1-1.diff.${compressor}: $TESTSDIR/brokenuncompressor.sh exited with code 1!
-v0*=There have been errors!
stdout
EOF
fi


# sadly different output depending on libarchive version....
# dd if=/dev/zero of=fake_1-1.debian.tar.lzma bs=5 count=1
# 
# testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
# returns 255
# *=/usr/bin/unlzma: Read error
# *=Error 84 trying to extract control information from ./fake_1-1.debian.tar.${compressor}:
# *=Empty input file: Invalid or incomplete multibyte or wide character
# -v0*=There have been errors!
# stdout
# EOF

mv save.tar.${compressor} fake_1-1.debian.tar.${compressor}
rm fake_1.orig.tar.${compressor}

# now check only partial reading of the .diff
# (i.e. diff containing a control):
rm fake-1/debian/control
cat > fake-1/debian/control <<EOF
Package: fake
Maintainer: MeToo
Section: base
Priority: required

Package: abinary
Architecture: all
EOF
cat > fake-1/debian/aaaaa <<EOF
also test debian/control not being the first file...
EOF
diff -ruN fake-1.orig fake-1 | ${compressor_program} > fake_1-1.diff.${compressor}
rm -r fake-1 fake-1.orig


cat > fake_1-1.dsc << EOF
Format: 3.0
Source: fake
Binary: abinary
Architecture: all
Version: 17
Maintainer: Me
Files:
 $(mdandsize fake_1-1.diff.${compressor}) fake_1-1.diff.${compressor}
 $(mdandsize fake_1-1.debian.tar.${compressor}) fake_1-1.debian.tar.${compressor}
 00000000000000000000000000000000 0 fake_1.orig.tar.${compressor}
EOF

testrun - __extractsourcesection fake_1-1.dsc 3<<EOF
stdout
*=Section: base
*=Priority: required
EOF

if test -n "$uncompressor" ; then
testrun - --${uncompressor}=false __extractsourcesection fake_1-1.dsc 3<<EOF
returns 255
*=Error reading from ./fake_1-1.diff.${compressor}: /bin/false exited with code 1!
-v0*=There have been errors!
stdout
EOF
fi

done

rm testfile* smallfile* emptyfile*

cat > fake_1-2.diff <<EOF
--- bla/Makefile
+++ bla/Makefile
@@ -1000,1 +1000,1 @@
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
--- bla/debian/control
+++ bla/debian/control
@@ -0,0 +1,10 @@
+Source: fake
+Section: sssss
+# new-fangled comment
+Priority: ppp
+Homepage: gopher://never-never-land/
+
EOF
dodo gzip fake_1-2.diff

cat > fake_1-2.dsc << EOF
Format: 3.0
Source: fake
Binary: abinary
Architecture: all
Version: 17
Maintainer: Me
Files:
 $(mdandsize fake_1-2.diff.gz) fake_1-2.diff.gz
 00000000000000000000000000000000 0 fake_1.orig.tar.gz
EOF

testrun - __extractsourcesection fake_1-2.dsc 3<<EOF
stdout
*=Section: sssss
*=Priority: ppp
EOF

rm fake*
testsuccess
