<?php declare(strict_types=1);

namespace Newland\Toubiz\Sync\Neos\Tests\Unit\ErrorHandling;

use Neos\Flow\Tests\FunctionalTestCase;
use Newland\Toubiz\Sync\Neos\Tests\Unit\ErrorHandling\Fixtures\ExampleModel;
use Newland\Toubiz\Sync\Neos\ErrorHandling\DoctrineAnnotationBasedValidator;

class DoctrineAnnotationBasedValidatorTest extends FunctionalTestCase
{

    /** @dataProvider provideInvalidFloats */
    public function testAddsSimpleValidationForFloats($invalidValue): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('float')->hasErrors());

        $model->float = $invalidValue;
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertTrue($result->forProperty('float')->hasErrors());
    }

    public function provideInvalidFloats(): array
    {
        return [
            [ 'foo' ],
            [ '' ],
            [ null ],
            [ [ 'some' => 'array' ] ],
            [ new ExampleModel() ],
            [ false ],
        ];
    }

    /** @dataProvider provideInvalidIntegers */
    public function testAddsSimpleValidationForIntegers($invalidValue): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('int')->hasErrors());

        $model->int = $invalidValue;
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertTrue($result->forProperty('int')->hasErrors());
    }

    public function provideInvalidIntegers(): array
    {
        return [
            [ 'foo' ],
            [ '' ],
            [ null ],
            [ [ 'some' => 'array' ] ],
            [ new ExampleModel() ],
            [ false ],
        ];
    }

    /** @dataProvider provideInvalidStrings */
    public function testAddsSimpleValidationForStrings($invalid): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('stringWithoutLength')->hasErrors());

        $model->stringWithoutLength = $invalid;
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertTrue($result->forProperty('stringWithoutLength')->hasErrors());
    }

    public function provideInvalidStrings(): array
    {
        return [
            [ 42 ],
            [ 0 ],
            [ null ],
            [ [ 'some' => 'array' ] ],
            [ new ExampleModel() ],
            [ false ],
        ];
    }

    public function testStringsDefaultTo255CharsLong(): void
    {
        $model = new ExampleModel();
        $model->stringWithoutLength = str_repeat('.', 256);
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertTrue($result->forProperty('stringWithoutLength')->hasErrors());
    }

    /** @dataProvider provideInvalidStrings */
    public function testAddsSimpleValidationForTexts($invalid): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('text')->hasErrors());

        $model->text = $invalid;
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertTrue($result->forProperty('text')->hasErrors());
    }

    public function testRespectsNullableFields(): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('nullableInt')->hasErrors());

        $model->nullableInt = null;
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('nullableInt')->hasErrors());
    }

    public function testDoesNotValidateIfAnnotationForNoValidationFound(): void
    {
        $model = new ExampleModel();
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('int')->hasErrors());

        $model->intButNotValidated = [ 'some' => 'array' ];
        $result = (new DoctrineAnnotationBasedValidator())->validate($model);
        $this->assertFalse($result->forProperty('int')->hasErrors());
    }

}
