<commit_before><?php

declare(strict_types=1);

/*
 * Copyright (c) the Contributors as noted in the AUTHORS file.
 *
 * This file is part of the Park-Manager project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

namespace ParkManager\Bundle\UserBundle\Tests\Action;

use ParkManager\Component\Security\Token\SplitToken;
use ParkManager\Component\User\Model\UserId;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * @internal
 * @group functional
 */
abstract class ConfirmPasswordResetActionTestCase extends WebTestCase
{
    /**
     * @test
     * @slowThreshold 2000 This uses Argon password hashing
     */
    public function its_accessible_by_anonymous()
    {
        $client = self::createClient();

        $repository = $client->getContainer()->get($this->getRepositoryServiceId());
        $user = $repository->get(UserId::fromString($this->getUserId()));
        $token = SplitToken::generate($this->getUserId());
        // First reset then set a new token.
        $user->confirmPasswordReset(SplitToken::fromString('<KEY>'), 'wrong');
        $user->setPasswordResetToken($token->toValueHolder(new \DateTimeImmutable('+ 10 minutes')));
        $user->changePassword('<PASSWORD>');
        $repository->save($user);

        $crawler = $client->request('GET', $this->getEntryUri($token->token()));
        HttpResponseAssertions::assertRequestWasSuccessful($client);

        $form = $crawler->selectButton('button.change_password')->form();
        $form->setValues([
            $this->getFormName().'[password][first]' => '<PASSWORD>',
            $this->getFormName().'[password][second]' => '<PASSWORD>',
        ]);

        $client->submit($form);
        HttpResponseAssertions::assertRequestWasRedirected($client, $this->getLoginUri());

        // Now let's try to login with the new password.
        $crawler = $client->request('GET', $this->getLoginUri());

        $form = $crawler->selectButton('button.login')->form();
        $form->setValues([
            '_email' => $user->email(),
            '_password' => '<PASSWORD>',
        ]);

        $client->submit($form);
        HttpResponseAssertions::assertRequestWasRedirected($client, $this->getOnSuccessUri());

        $token = $client->getContainer()->get('security.token_storage')->getToken();
        self::assertNotNull($token);
        self::assertTrue($token->isAuthenticated());
    }

    /** @test */
    public function it_gives_not_found_on_invalid_token()
    {
        $client = self::createClient();
        $client->request('GET', $this->getEntryUri('foo-bar-no-car'));

        HttpResponseAssertions::assertRequestStatus($client, 404);
        self::assertContains('password_reset.error.invalid_token', $client->getResponse()->getContent());
    }

    /** @test */
    public function it_gives_not_found_when_no_results_were_found()
    {
        $client = self::createClient();
        $client->request('GET', $this->getEntryUri('H46VaCeI-DtDoW7i_ZhtTzx39ObsQJjADCUbQhSMw1cn3sHQamoDfFY3'));

        HttpResponseAssertions::assertRequestStatus($client, 404);
        self::assertContains('password_reset.error.no_token', $client->getResponse()->getContent());
    }

    protected function getFormName(): string
    {
        return 'confirm_user_password_reset';
    }

    abstract protected function getRepositoryServiceId(): string;

    abstract protected function getEntryUri(string $token): string;

    abstract protected function getLoginUri(): string;

    abstract protected function getUserId(): string;

    abstract protected function getOnSuccessUri(): string;
}<commit_msg>Clean-up tests<commit_after><?php

declare(strict_types=1);

/*
 * Copyright (c) the Contributors as noted in the AUTHORS file.
 *
 * This file is part of the Park-Manager project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

namespace ParkManager\Bundle\UserBundle\Tests\Action;

use ParkManager\Component\Security\Token\SplitToken;
use ParkManager\Component\User\Model\User;
use ParkManager\Component\User\Model\UserId;
use Symfony\Bundle\FrameworkBundle\Client;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * @internal
 * @group functional
 */
abstract class ConfirmPasswordResetActionTestCase extends WebTestCase
{
    /**
     * @test
     * @slowThreshold 2000 This uses Argon password hashing
     */
    public function its_accessible_by_anonymous()
    {
        $client = self::createClient();
        $token = SplitToken::generate($this->getUserId());
        $user = $this->givenUserExistsAndHasToken($client, $token);

        $crawler = $client->request('GET', $this->getEntryUri($token->token()));
        HttpResponseAssertions::assertRequestWasSuccessful($client);

        $form = $crawler->selectButton('button.change_password')->form();
        $form->setValues([
            $this->getFormName().'[password][first]' => '<PASSWORD>',
            $this->getFormName().'[password][second]' => '<PASSWORD>',
        ]);

        $client->submit($form);
        HttpResponseAssertions::assertRequestWasRedirected($client, $this->getLoginUri());

        // Now let's try to login with the new password.
        $crawler = $client->request('GET', $this->getLoginUri());

        $form = $crawler->selectButton('button.login')->form();
        $form->setValues([
            '_email' => $user->email(),
            '_password' => '<PASSWORD>',
        ]);

        $client->submit($form);
        HttpResponseAssertions::assertRequestWasRedirected($client, $this->getOnSuccessUri());

        $token = $client->getContainer()->get('security.token_storage')->getToken();
        self::assertNotNull($token);
        self::assertTrue($token->isAuthenticated());
    }

    /** @test */
    public function it_gives_not_found_on_invalid_token()
    {
        $client = self::createClient();
        $client->request('GET', $this->getEntryUri('foo-bar-no-car'));

        HttpResponseAssertions::assertRequestStatus($client, 404);
        self::assertContains('password_reset.error.invalid_token', $client->getResponse()->getContent());
    }

    /** @test */
    public function it_gives_not_found_when_no_results_were_found()
    {
        $client = self::createClient();
        $client->request('GET', $this->getEntryUri('H46VaCeI-DtDoW7i_ZhtTzx39ObsQJjADCUbQhSMw1cn3sHQamoDfFY3'));

        HttpResponseAssertions::assertRequestStatus($client, 404);
        self::assertContains('password_reset.error.no_token', $client->getResponse()->getContent());
    }

    protected function getFormName(): string
    {
        return 'confirm_user_password_reset';
    }

    abstract protected function getRepositoryServiceId(): string;

    abstract protected function getEntryUri(string $token): string;

    abstract protected function getLoginUri(): string;

    abstract protected function getUserId(): string;

    abstract protected function getOnSuccessUri(): string;

    private function givenUserExistsAndHasToken(Client $client, SplitToken $token): User
    {
        $repository = $client->getContainer()->get($this->getRepositoryServiceId());
        /** @var User $user */
        $user = $repository->get(UserId::fromString($this->getUserId()));
        // First reset (with an invalid token to ensure a new token is accepted)
        // then set a new token.
        $user->confirmPasswordReset(
            SplitToken::fromString('<KEY>'),
            'wrong'
        );
        $user->setPasswordResetToken($token->toValueHolder(new \DateTimeImmutable('+ 10 minutes')));
        $user->changePassword('<PASSWORD>');
        $repository->save($user);

        return $user;
    }
}
{'fraction_non_alphanumeric': 0.14704034183737588, 'fraction_numerical': 0.006283775292195551, 'mean_word_length': 3.563073394495413, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 104, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1794908', 'n_tokens_mistral': 2284, 'n_tokens_neox': 2198, 'n_words': 432}