<commit_before><?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\Core\Service\Tag;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Entity\Tag;
use Shlinkio\Shlink\Core\Exception\TagConflictException;
use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
use Shlinkio\Shlink\Core\Repository\TagRepository;
use Shlinkio\Shlink\Core\Tag\TagService;

class TagServiceTest extends TestCase
{
    private TagService $service;
    private ObjectProphecy $em;

    public function setUp(): void
    {
        $this->em = $this->prophesize(EntityManagerInterface::class);
        $this->service = new TagService($this->em->reveal());
    }

    /** @test */
    public function listTagsDelegatesOnRepository(): void
    {
        $expected = [new Tag('foo'), new Tag('bar')];

        $repo = $this->prophesize(EntityRepository::class);
        $find = $repo->findBy(Argument::cetera())->willReturn($expected);
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());

        $result = $this->service->listTags();

        $this->assertEquals($expected, $result);
        $find->shouldHaveBeenCalled();
        $getRepo->shouldHaveBeenCalled();
    }

    /** @test */
    public function deleteTagsDelegatesOnRepository(): void
    {
        $repo = $this->prophesize(TagRepository::class);
        $delete = $repo->deleteByName(['foo', 'bar'])->willReturn(4);
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());

        $this->service->deleteTags(['foo', 'bar']);

        $delete->shouldHaveBeenCalled();
        $getRepo->shouldHaveBeenCalled();
    }

    /** @test */
    public function createTagsPersistsEntities(): void
    {
        $repo = $this->prophesize(TagRepository::class);
        $find = $repo->findOneBy(Argument::cetera())->willReturn(new Tag('foo'));
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());
        $persist = $this->em->persist(Argument::type(Tag::class))->willReturn(null);
        $flush = $this->em->flush()->willReturn(null);

        $result = $this->service->createTags(['foo', 'bar']);

        $this->assertCount(2, $result);
        $find->shouldHaveBeenCalled();
        $getRepo->shouldHaveBeenCalled();
        $persist->shouldHaveBeenCalledTimes(2);
        $flush->shouldHaveBeenCalled();
    }

    /** @test */
    public function renameInvalidTagThrowsException(): void
    {
        $repo = $this->prophesize(TagRepository::class);
        $find = $repo->findOneBy(Argument::cetera())->willReturn(null);
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());

        $find->shouldBeCalled();
        $getRepo->shouldBeCalled();
        $this->expectException(TagNotFoundException::class);

        $this->service->renameTag('foo', 'bar');
    }

    /**
     * @test
     * @dataProvider provideValidRenames
     */
    public function renameValidTagChangesItsName(string $oldName, string $newName, int $count): void
    {
        $expected = new Tag('foo');

        $repo = $this->prophesize(TagRepository::class);
        $find = $repo->findOneBy(Argument::cetera())->willReturn($expected);
        $countTags = $repo->count(Argument::cetera())->willReturn($count);
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());
        $flush = $this->em->flush()->willReturn(null);

        $tag = $this->service->renameTag($oldName, $newName);

        $this->assertSame($expected, $tag);
        $this->assertEquals($newName, (string) $tag);
        $find->shouldHaveBeenCalled();
        $getRepo->shouldHaveBeenCalled();
        $flush->shouldHaveBeenCalled();
        $countTags->shouldHaveBeenCalledTimes($count > 0 ? 0 : 1);
    }

    public function provideValidRenames(): iterable
    {
        yield 'same names' => ['foo', 'foo', 1];
        yield 'different names names' => ['foo', 'bar', 0];
    }

    /** @test */
    public function renameTagToAnExistingNameThrowsException(): void
    {
        $repo = $this->prophesize(TagRepository::class);
        $find = $repo->findOneBy(Argument::cetera())->willReturn(new Tag('foo'));
        $countTags = $repo->count(Argument::cetera())->willReturn(1);
        $getRepo = $this->em->getRepository(Tag::class)->willReturn($repo->reveal());
        $flush = $this->em->flush(Argument::any())->willReturn(null);

        $find->shouldBeCalled();
        $getRepo->shouldBeCalled();
        $countTags->shouldBeCalled();
        $flush->shouldNotBeCalled();
        $this->expectException(TagConflictException::class);

        $this->service->renameTag('foo', 'bar');
    }
}
<commit_msg>Updated TagServiceTest<commit_after><?php

declare(strict_types=1);

namespace ShlinkioTest\Shlink\Core\Service\Tag;

use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Entity\Tag;
use Shlinkio\Shlink\Core\Exception\TagConflictException;
use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
use Shlinkio\Shlink\Core\Repository\TagRepository;
use Shlinkio\Shlink\Core\Tag\Model\TagInfo;
use Shlinkio\Shlink\Core\Tag\TagService;

class TagServiceTest extends TestCase
{
    private TagService $service;
    private ObjectProphecy $em;
    private ObjectProphecy $repo;

    public function setUp(): void
    {
        $this->em = $this->prophesize(EntityManagerInterface::class);
        $this->repo = $this->prophesize(TagRepository::class);
        $this->em->getRepository(Tag::class)->willReturn($this->repo->reveal())->shouldBeCalled();

        $this->service = new TagService($this->em->reveal());
    }

    /** @test */
    public function listTagsDelegatesOnRepository(): void
    {
        $expected = [new Tag('foo'), new Tag('bar')];

        $find = $this->repo->findBy(Argument::cetera())->willReturn($expected);

        $result = $this->service->listTags();

        $this->assertEquals($expected, $result);
        $find->shouldHaveBeenCalled();
    }

    /** @test */
    public function tagsInfoDelegatesOnRepository(): void
    {
        $expected = [new TagInfo(new Tag('foo'), 1, 1), new TagInfo(new Tag('bar'), 3, 10)];

        $find = $this->repo->findTagsWithInfo()->willReturn($expected);

        $result = $this->service->tagsInfo();

        $this->assertEquals($expected, $result);
        $find->shouldHaveBeenCalled();
    }

    /** @test */
    public function deleteTagsDelegatesOnRepository(): void
    {
        $delete = $this->repo->deleteByName(['foo', 'bar'])->willReturn(4);

        $this->service->deleteTags(['foo', 'bar']);

        $delete->shouldHaveBeenCalled();
    }

    /** @test */
    public function createTagsPersistsEntities(): void
    {
        $find = $this->repo->findOneBy(Argument::cetera())->willReturn(new Tag('foo'));
        $persist = $this->em->persist(Argument::type(Tag::class))->willReturn(null);
        $flush = $this->em->flush()->willReturn(null);

        $result = $this->service->createTags(['foo', 'bar']);

        $this->assertCount(2, $result);
        $find->shouldHaveBeenCalled();
        $persist->shouldHaveBeenCalledTimes(2);
        $flush->shouldHaveBeenCalled();
    }

    /** @test */
    public function renameInvalidTagThrowsException(): void
    {
        $find = $this->repo->findOneBy(Argument::cetera())->willReturn(null);

        $find->shouldBeCalled();
        $this->expectException(TagNotFoundException::class);

        $this->service->renameTag('foo', 'bar');
    }

    /**
     * @test
     * @dataProvider provideValidRenames
     */
    public function renameValidTagChangesItsName(string $oldName, string $newName, int $count): void
    {
        $expected = new Tag('foo');

        $find = $this->repo->findOneBy(Argument::cetera())->willReturn($expected);
        $countTags = $this->repo->count(Argument::cetera())->willReturn($count);
        $flush = $this->em->flush()->willReturn(null);

        $tag = $this->service->renameTag($oldName, $newName);

        $this->assertSame($expected, $tag);
        $this->assertEquals($newName, (string) $tag);
        $find->shouldHaveBeenCalled();
        $flush->shouldHaveBeenCalled();
        $countTags->shouldHaveBeenCalledTimes($count > 0 ? 0 : 1);
    }

    public function provideValidRenames(): iterable
    {
        yield 'same names' => ['foo', 'foo', 1];
        yield 'different names names' => ['foo', 'bar', 0];
    }

    /** @test */
    public function renameTagToAnExistingNameThrowsException(): void
    {
        $find = $this->repo->findOneBy(Argument::cetera())->willReturn(new Tag('foo'));
        $countTags = $this->repo->count(Argument::cetera())->willReturn(1);
        $flush = $this->em->flush(Argument::any())->willReturn(null);

        $find->shouldBeCalled();
        $countTags->shouldBeCalled();
        $flush->shouldNotBeCalled();
        $this->expectException(TagConflictException::class);

        $this->service->renameTag('foo', 'bar');
    }
}

{'fraction_non_alphanumeric': 0.1766179995641752, 'fraction_numerical': 0.002723904990193942, 'mean_word_length': 3.473196881091618, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 194, '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': '2394468', 'n_tokens_mistral': 2808, 'n_tokens_neox': 2769, 'n_words': 404}