<?php declare(strict_types=1);

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Test\Policy;

use Composer\Policy\IgnorePackageRule;
use Composer\Policy\ListPolicyConfig;
use Composer\Policy\MalwarePolicyConfig;
use Composer\Semver\Constraint\MatchAllConstraint;
use Composer\Semver\VersionParser;
use Composer\Test\TestCase;

class MalwarePolicyConfigTest extends TestCase
{
    /**
     * @return iterable<array<mixed>>
     */
    public static function defaultProvider(): iterable
    {
        yield [[]];
        yield [['malware' => true]];
        yield [['malware' => []]];
    }

    /**
     * @dataProvider defaultProvider
     * @param array<mixed> $policyConfig
     */
    public function testDefaultConfig(array $policyConfig): void
    {
        $this->assertEquals(
            new MalwarePolicyConfig(true, ListPolicyConfig::AUDIT_FAIL, MalwarePolicyConfig::BLOCK_SCOPE_ALL, [], []),
            MalwarePolicyConfig::fromRawConfig($policyConfig, new VersionParser())
        );
    }

    public function testFromRawConfig(): void
    {
        $rawConfig = [
            'malware' => [
                'block' => false,
                'block-scope' => 'update',
                'audit' => 'report',
                'ignore' => [
                    'acme/malware' => 'flagged by mistake',
                    'acme/malware2' => ['constraint' => '1.0'],
                ],
                'ignore-source' => ['untrusted']
            ],
        ];
        $this->assertEquals(
            new MalwarePolicyConfig(false, ListPolicyConfig::AUDIT_REPORT, MalwarePolicyConfig::BLOCK_SCOPE_UPDATE, [
                'acme/malware' => [new IgnorePackageRule('acme/malware', new MatchAllConstraint(), 'flagged by mistake')],
                'acme/malware2' => [new IgnorePackageRule('acme/malware2', (new VersionParser())->parseConstraints('1.0'))],
            ], ['untrusted']),
            MalwarePolicyConfig::fromRawConfig($rawConfig, new VersionParser())
        );
    }

    public function testShouldBlockReturnsFalseWhenBlockIsOff(): void
    {
        $malware = new MalwarePolicyConfig(false, ListPolicyConfig::AUDIT_FAIL, MalwarePolicyConfig::BLOCK_SCOPE_ALL, [], []);

        self::assertFalse($malware->shouldBlock(ListPolicyConfig::BLOCK_SCOPE_UPDATE));
        self::assertFalse($malware->shouldBlock(ListPolicyConfig::BLOCK_SCOPE_INSTALL));
    }

    /**
     * @return iterable<string, array{0: ListPolicyConfig::BLOCK_SCOPE_*, 1: ListPolicyConfig::BLOCK_SCOPE_*, 2: bool}>
     */
    public static function shouldBlockMatrixProvider(): iterable
    {
        // [configured block-scope, query scope, expected]
        yield 'all + update' => [ListPolicyConfig::BLOCK_SCOPE_ALL, ListPolicyConfig::BLOCK_SCOPE_UPDATE, true];
        yield 'all + install' => [ListPolicyConfig::BLOCK_SCOPE_ALL, ListPolicyConfig::BLOCK_SCOPE_INSTALL, true];
        yield 'update + update' => [ListPolicyConfig::BLOCK_SCOPE_UPDATE, ListPolicyConfig::BLOCK_SCOPE_UPDATE, true];
        yield 'update + install' => [ListPolicyConfig::BLOCK_SCOPE_UPDATE, ListPolicyConfig::BLOCK_SCOPE_INSTALL, false];
        yield 'install + update' => [ListPolicyConfig::BLOCK_SCOPE_INSTALL, ListPolicyConfig::BLOCK_SCOPE_UPDATE, false];
        yield 'install + install' => [ListPolicyConfig::BLOCK_SCOPE_INSTALL, ListPolicyConfig::BLOCK_SCOPE_INSTALL, true];
    }

    /**
     * @dataProvider shouldBlockMatrixProvider
     * @param ListPolicyConfig::BLOCK_SCOPE_* $configuredScope
     * @param ListPolicyConfig::BLOCK_SCOPE_* $queryScope
     */
    public function testShouldBlockHonoursConfiguredBlockScope(string $configuredScope, string $queryScope, bool $expected): void
    {
        $malware = new MalwarePolicyConfig(true, ListPolicyConfig::AUDIT_FAIL, $configuredScope, [], []);

        self::assertSame($expected, $malware->shouldBlock($queryScope));
    }
}
