# SPDX-License-Identifier: GPL-2.0-or-later

package Amavis::UnpackersTest;

use Test::Most;
use base 'Test::Class';

use File::Slurp;
use File::Spec;
use File::Temp;
use MIME::Base64;

use constant LZIP_FOOBAR => decode_base64 'TFpJUAEMADMb7MRiQgQlX///2LkAAJUf9p4GAAAAAAAAACoAAAAAAAAA';
use constant XZ_FOOBAR   => decode_base64(<<~EOD);
    /Td6WFoAAATm1rRGAgAhARYAAAB0L+WjAQAFZm9vYmFy
    AAAAHrBkBGxCSlMAAR4GwS+kHR+2830BAAAAAARZWg==
    EOD

sub find_external_program {
    my $prog = shift;
    for my $path (qw[/bin /usr/bin /sbin /usr/sbin]) {
        my $exc = File::Spec->join($path, $prog);
        return $exc if -x $exc;
    }
    return
}

sub class { 'Amavis::Unpackers' }

sub startup : Tests(startup => 3) {
  my $test = shift;
  use_ok $test->class;
  use_ok 'Amavis::Unpackers::Part';

  ok Amavis::Unpackers::Part::init(Amavis::Unpackers::NewFilename->new(undef, 2**20)), 'init Unpackers';

  $Amavis::Conf::file = find_external_program('file');

  { # copied from Amavis.pm, essential for mapping correctly. :/
      # convert arrayref to Amavis::Lookup::RE object, the Amavis::Lookup::RE module
      # was not yet available during BEGIN phase
      $Amavis::Conf::map_full_type_to_short_type_re =
        Amavis::Lookup::RE->new(@$Amavis::Conf::map_full_type_to_short_type_re);
  }

}

sub lzip : Tests(4) {

    my $lzip = find_external_program('lzip');

    SKIP: {
        skip ('lzip not found', 1) unless $lzip;
        skip ('file not found', 1) unless $Amavis::Conf::file;

        local $ENV{PATH} = '/';
        my $tempdir = File::Temp->newdir('test-directory-tmp-XXXXX', CLEANUP => 1, TMPDIR => 1);
        mkdir (my $partsdir = File::Spec->join($tempdir->dirname, 'parts'));

        my @name_declared = (
            {
                parent => 'foobar.lzip',
                child  => 'foobar.lzip',
            },{
                parent => 'foobar.lz',
                child  => 'foobar',
            }
        );

        for my $name_declared (@name_declared) {
            my $part = Amavis::Unpackers::Part->new($partsdir);
            write_file($part->full_name, LZIP_FOOBAR);
            $part->exists(1);
            $part->name_declared($name_declared->{parent});
            Amavis::Unpackers::determine_file_types($tempdir, [$part]);
            Amavis::Unpackers::do_uncompress($part, $tempdir->dirname, "$lzip -d");
            is $part->children->[0]->name_declared, $name_declared->{child}, "child's name_declared is correct";
            my $unpacked = eval {read_file $part->children->[0]->full_name};
            is $unpacked, 'foobar', 'unpacked correctly';
        }
        chdir '/'; # Make sure not to be in $tempdir so that File::Temp cleanup would fail
    }
}

sub xz : Tests(3) {

    my $xz = find_external_program('xz');

    SKIP: {
        skip ('xz not found', 1) unless $xz;
        skip ('file not found', 1) unless $Amavis::Conf::file;

        local $ENV{PATH} = '/';
        my $tempdir = File::Temp->newdir('test-directory-tmp-XXXXX', CLEANUP => 1, TMPDIR => 1);
        mkdir (my $partsdir = File::Spec->join($tempdir->dirname, 'parts'));

        my $part = Amavis::Unpackers::Part->new($partsdir);
        write_file($part->full_name, XZ_FOOBAR);
        $part->exists(1);
        $part->name_declared('foobar.xz');
        Amavis::Unpackers::determine_file_types($tempdir, [$part]);
        is $part->type_short, 'xz', 'short_type is correct';

        Amavis::Unpackers::do_uncompress($part, $tempdir->dirname, "$xz -dc");
        is $part->children->[0]->name_declared, 'foobar', "child's name_declared is correct";
        my $unpacked = eval {read_file $part->children->[0]->full_name};
        is $unpacked, 'foobar', 'unpacked correctly';
        chdir '/'; # Make sure not to be in $tempdir so that File::Temp cleanup would fail
    }
}


1;
