jaroslavtyc/drd-plus-rolls-on

View on GitHub
tests/RollsOn/QualityAndSuccess/ExtendedRollOnSuccessTest.php

Summary

Maintainability
A
35 mins
Test Coverage
<?php declare(strict_types=1);

namespace DrdPlus\Tests\RollsOn\QualityAndSuccess;

use Granam\DiceRolls\Roll;
use DrdPlus\RollsOn\QualityAndSuccess\BasicRollOnSuccess;
use DrdPlus\RollsOn\QualityAndSuccess\ExtendedRollOnSuccess;
use DrdPlus\RollsOn\QualityAndSuccess\RollOnQuality;
use DrdPlus\RollsOn\QualityAndSuccess\SimpleRollOnSuccess;
use Granam\TestWithMockery\TestWithMockery;

class ExtendedRollOnSuccessTest extends TestWithMockery
{
    /**
     * @test
     * @dataProvider provideSimpleRollsOnSuccessAndResult
     * @param RollOnQuality $expectedRollOnQuality
     * @param array $simpleRollsOnSuccess
     * @param string $expectedResultCode
     * @param bool $expectingSuccess
     */
    public function I_can_use_it(RollOnQuality $expectedRollOnQuality, array $simpleRollsOnSuccess, string $expectedResultCode, bool $expectingSuccess)
    {
        $extendedRollOnSuccessReflection = new \ReflectionClass(ExtendedRollOnSuccess::class);
        /** @var ExtendedRollOnSuccess $extendedRollOnSuccess */
        $extendedRollOnSuccess = $extendedRollOnSuccessReflection->newInstanceArgs($simpleRollsOnSuccess);

        self::assertSame($expectedRollOnQuality, $extendedRollOnSuccess->getRollOnQuality());
        self::assertSame($expectedResultCode, $extendedRollOnSuccess->getResult());
        self::assertSame($expectedResultCode, (string)$extendedRollOnSuccess);
        if ($expectingSuccess) {
            self::assertFalse($extendedRollOnSuccess->isFailure());
            self::assertTrue($extendedRollOnSuccess->isSuccess());
        } else {
            self::assertTrue($extendedRollOnSuccess->isFailure());
            self::assertFalse($extendedRollOnSuccess->isSuccess());
        }
    }

    public function provideSimpleRollsOnSuccessAndResult()
    {
        return [
            [ // from single simple roll on success
                $rollOnQuality = $this->createRollOnQuality(5 /* roll value */),
                [
                    $this->createSimpleRollOnSuccess(9 /* difficulty */, $rollOnQuality, false /* unsuccessful */, 'what happened?'),
                ],
                'what happened?', /* result code */
                false /* expecting failure */
            ],
            [ // from simple roll on success and basic roll on success (which is simple roll also)
                $rollOnQuality = $this->createRollOnQuality(3 /* roll value */),
                [
                    $this->createSimpleRollOnSuccess(2 /* difficulty */, $rollOnQuality),
                    $this->createBasicRollOnSuccess(5 /* difficulty */, $rollOnQuality, true /* is successful */, 'hurray'),
                ],
                'hurray',
                true /* expecting success */
            ],
            [ // from more than three simple rolls on success with two successful and non-sequential difficulty
                $rollOnQuality = $this->createRollOnQuality(2 /* roll value */),
                [
                    $this->createSimpleRollOnSuccess(5 /* difficulty */, $rollOnQuality),
                    $this->createSimpleRollOnSuccess(1 /* difficulty */, $rollOnQuality, true /* success */, 'success'),
                    $this->createSimpleRollOnSuccess(3 /* difficulty */, $rollOnQuality),
                    $this->createSimpleRollOnSuccess(2 /* difficulty */, $rollOnQuality, true /* success */, 'better success'),
                ],
                'better success',
                true /* expecting success */
            ],
            [ // from more than three simple rolls on success without success at all and non-sequential difficulty
                $rollOnQuality = $this->createRollOnQuality(2 /* roll value */),
                [
                    $this->createSimpleRollOnSuccess(5 /* difficulty */, $rollOnQuality, false, 'I failed against 5'),
                    $this->createSimpleRollOnSuccess(1 /* difficulty */, $rollOnQuality, false, 'I failed against 1'),
                    $this->createSimpleRollOnSuccess(3 /* difficulty */, $rollOnQuality, false, 'I failed against 3'),
                    $this->createSimpleRollOnSuccess(2 /* difficulty */, $rollOnQuality, false, 'I failed against 2'),
                ],
                'I failed against 1', // the lowest difficulty is used as a result
                false /* expecting failure */
            ],
        ];
    }

    /**
     * @param $difficulty
     * @param RollOnQuality $rollOnQuality
     * @param $isSuccess
     * @param $resultValue
     * @return \Mockery\MockInterface|SimpleRollOnSuccess
     */
    private function createSimpleRollOnSuccess($difficulty, RollOnQuality $rollOnQuality, $isSuccess = false, $resultValue = 'foo')
    {
        return $this->createRollOnSuccess(SimpleRollOnSuccess::class, $difficulty, $rollOnQuality, $isSuccess, $resultValue);
    }

    private function createRollOnSuccess($class, $difficulty, RollOnQuality $rollOnQuality, $isSuccess, $resultValue)
    {
        $rollOnSuccess = $this->mockery($class);
        $rollOnSuccess->shouldReceive('getDifficulty')
            ->andReturn($difficulty);
        $rollOnSuccess->shouldReceive('isSuccess')
            ->andReturn($isSuccess);
        $rollOnSuccess->shouldReceive('getResult')
            ->andReturn($resultValue);
        $rollOnSuccess->shouldReceive('getRollOnQuality')
            ->andReturn($rollOnQuality);

        return $rollOnSuccess;
    }

    /**
     * @param $value
     * @param $rollValue
     * @param array $rolledNumbers
     * @return \Mockery\MockInterface|RollOnQuality
     */
    private function createRollOnQuality($value, int $rollValue = 999, array $rolledNumbers = ['some', 'rolled', 'numbers'])
    {
        $rollOnQuality = $this->mockery(RollOnQuality::class);
        $rollOnQuality->shouldReceive('getPreconditionsSum')
            ->andReturn(123);
        $rollOnQuality->shouldReceive('getValue')
            ->andReturn($value);
        $rollOnQuality->shouldReceive('getRoll')
            ->andReturn($roll = $this->mockery(Roll::class));
        $roll->shouldReceive('getValue')
            ->andReturn($rollValue);
        $roll->shouldReceive('getRolledNumbers')
            ->andReturn($rolledNumbers);

        return $rollOnQuality;
    }

    /**
     * @param $difficulty
     * @param RollOnQuality $rollOnQuality
     * @param bool $isSuccess
     * @param string $resultValue
     * @return \Mockery\MockInterface|BasicRollOnSuccess
     */
    private function createBasicRollOnSuccess($difficulty, RollOnQuality $rollOnQuality, $isSuccess = false, $resultValue = 'foo')
    {
        return $this->createRollOnSuccess(BasicRollOnSuccess::class, $difficulty, $rollOnQuality, $isSuccess, $resultValue);
    }

    /**
     * @test
     */
    public function I_can_create_it_only_from_simple_rolls_on_success()
    {
        $this->expectException(\DrdPlus\RollsOn\QualityAndSuccess\Exceptions\ExpectedSimpleRollsOnSuccessOnly::class);
        $rollOnQuality = $this->createRollOnQuality(123);

        new ExtendedRollOnSuccess(
            $this->createSimpleRollOnSuccess(1, $rollOnQuality),
            $this->createBasicRollOnSuccess(2, $rollOnQuality),
            $this->createSimpleRollOnSuccess(3, $rollOnQuality),
            new ExtendedRollOnSuccess($this->createSimpleRollOnSuccess(23, $rollOnQuality))
        );
    }

    /**
     * @test
     */
    public function I_can_use_only_unique_difficulties()
    {
        $this->expectException(\DrdPlus\RollsOn\QualityAndSuccess\Exceptions\EveryDifficultyShouldBeUnique::class);
        $rollOnQuality = $this->createRollOnQuality(123);

        new ExtendedRollOnSuccess(
            $this->createSimpleRollOnSuccess(1, $rollOnQuality),
            $this->createBasicRollOnSuccess(1, $rollOnQuality)
        );
    }

    /**
     * @test
     */
    public function I_can_use_only_unique_success_codes()
    {
        $this->expectException(\DrdPlus\RollsOn\QualityAndSuccess\Exceptions\EverySuccessCodeShouldBeUnique::class);
        $rollOnQuality = $this->createRollOnQuality(1);

        new ExtendedRollOnSuccess(
            $this->createSimpleRollOnSuccess(1, $rollOnQuality, true, 'success'),
            $this->createBasicRollOnSuccess(2, $rollOnQuality, true, 'success')
        );
    }

    /**
     * @test
     */
    public function I_can_use_non_unique_success_codes_if_no_success_happens_on_them()
    {
        $rollOnQuality = $this->createRollOnQuality(1);

        $extendedRollOnSuccess = new ExtendedRollOnSuccess(
            $this->createSimpleRollOnSuccess(1, $rollOnQuality, true, 'success'),
            $this->createBasicRollOnSuccess(2, $rollOnQuality, false /* failure for this roll */, 'success' /* code used only on success */)
        );
        self::assertTrue($extendedRollOnSuccess->isSuccess());
    }

    /**
     * @test
     */
    public function I_can_use_different_instances_with_same_values_of_rolls_on_quality()
    {
        $firstRollOnQuality = $this->createRollOnQuality(1);
        $similarRollOnQuality = $this->createRollOnQuality(1);
        $extendedRollOnSuccess = new ExtendedRollOnSuccess(
            $this->createSimpleRollOnSuccess(1, $firstRollOnQuality),
            $this->createBasicRollOnSuccess(2, $similarRollOnQuality)
        );
        self::assertEquals($similarRollOnQuality, $extendedRollOnSuccess->getRollOnQuality());
    }

    /**
     * @test
     * @dataProvider provideSimpleRollsWithDifferentRollsOnQuality
     * @param SimpleRollOnSuccess $firstSimpleRoll
     * @param SimpleRollOnSuccess $secondSimpleRoll
     */
    public function I_can_not_use_different_rolls_on_quality(SimpleRollOnSuccess $firstSimpleRoll, SimpleRollOnSuccess $secondSimpleRoll)
    {
        $this->expectException(\DrdPlus\RollsOn\QualityAndSuccess\Exceptions\RollOnQualityHasToBeTheSame::class);
        new ExtendedRollOnSuccess($firstSimpleRoll, $secondSimpleRoll);
    }

    public function provideSimpleRollsWithDifferentRollsOnQuality()
    {
        return [
            [ // different roll on quality value
                $this->createSimpleRollOnSuccess(5, $this->createRollOnQuality(1)),
                $this->createSimpleRollOnSuccess(9, $this->createRollOnQuality(2)),
            ],
            [ // different roll on quality roll value
                $this->createSimpleRollOnSuccess(5, $this->createRollOnQuality(1, 1)),
                $this->createSimpleRollOnSuccess(9, $this->createRollOnQuality(1, 2)),
            ],
            [ // different roll on quality rolled numbers
                $this->createSimpleRollOnSuccess(5, $this->createRollOnQuality(1, 2, [1, 2])),
                $this->createSimpleRollOnSuccess(9, $this->createRollOnQuality(1, 2, [1, 3])),
            ],
        ];
    }
}