Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for and refactor publication field type validation rules #765

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
23e28b8
Create PublicationFieldTypeValidationRulesTest.php
caendesilva Dec 19, 2022
d90dcc9
Link to the unit test
caendesilva Dec 19, 2022
158d1f7
Add testing helper to make a publication type
caendesilva Dec 19, 2022
7967aa6
Revert "Add testing helper to make a publication type"
caendesilva Dec 19, 2022
230cf4f
Implement the unit test
caendesilva Dec 19, 2022
790485b
Test with image files
caendesilva Dec 19, 2022
bd3a62b
Null coalesce to empty collection
caendesilva Dec 19, 2022
537bd98
Add code review comments
caendesilva Dec 19, 2022
0161c3a
Remove default switch case that's impossible to reach due to enum
caendesilva Dec 19, 2022
dbc9230
Update skipped test
caendesilva Dec 19, 2022
85d2745
Rename local variable doBetween to useRange
caendesilva Dec 19, 2022
e9d0448
Apply fixes from StyleCI
StyleCIBot Dec 19, 2022
584a3a4
Resolve fixme
caendesilva Dec 20, 2022
2fb82a7
Merge branch 'publications-feature' into test-and-refactor-publicatio…
caendesilva Dec 20, 2022
a49c40a
Merge branch 'master' into test-and-refactor-publication-validation-r…
caendesilva Dec 20, 2022
64ead71
Update PublicationFieldValidationRulesTest for renamed class
caendesilva Dec 20, 2022
7e6b1e2
Merge branch 'publications-feature' into test-and-refactor-publicatio…
caendesilva Dec 21, 2022
a829ce1
Merge branch 'publications-feature' into test-and-refactor-publicatio…
caendesilva Dec 21, 2022
b0d75d1
Resolve todos
caendesilva Dec 21, 2022
4308643
Add the URL rule to URLs
caendesilva Dec 21, 2022
4eed23e
Link to the rules documentation
caendesilva Dec 21, 2022
a601376
Rename test methods
caendesilva Dec 21, 2022
f038165
Add testing helper to expect a validation exception
caendesilva Dec 21, 2022
e2f1f26
Parse the datetimes to ensure they are valid and normalized
caendesilva Dec 21, 2022
7894869
Support only using min date values
caendesilva Dec 21, 2022
1f4420f
Remove code comment
caendesilva Dec 21, 2022
851f667
Evaluate min/max values for dates independently
caendesilva Dec 21, 2022
4db1fe1
Test array validation
caendesilva Dec 21, 2022
bc32f14
Add the date rule to datetime fields
caendesilva Dec 21, 2022
4492aa7
Test datetime validation
caendesilva Dec 21, 2022
380ae76
Split out test methods
caendesilva Dec 21, 2022
a50908c
Apply fixes from StyleCI
StyleCIBot Dec 21, 2022
374bb41
Allow only min value to be set
caendesilva Dec 21, 2022
76431ff
Use class constant instead of FQCN
caendesilva Dec 21, 2022
22f57d5
Rename test methods to be more descriptive
caendesilva Dec 21, 2022
7aeeb2d
Floats must be numeric to be properly range validated
caendesilva Dec 21, 2022
353e66d
Remove range validation tests
caendesilva Dec 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

namespace Hyde\Framework\Features\Publications\Models;

use function collect;
use Hyde\Framework\Features\Publications\PublicationFieldTypes;
use Hyde\Framework\Features\Publications\PublicationService;
use Hyde\Support\Concerns\Serializable;
use Hyde\Support\Contracts\SerializableContract;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Rgasch\Collection\Collection;
Expand Down Expand Up @@ -44,7 +46,7 @@ public function __construct(PublicationFieldTypes|string $type, string $name, in
$this->tagGroup = $tagGroup;
$this->publicationType = $publicationType;

if ($max < $min) {
if ($max < $min && $max !== '0') {
throw new InvalidArgumentException("The 'max' value cannot be less than the 'min' value.");
}
}
Expand All @@ -60,34 +62,48 @@ public function toArray(): array
];
}

/**
* @see \Hyde\Framework\Testing\Unit\PublicationFieldTypeValidationRulesTest
* @see https://laravel.com/docs/9.x/validation#available-validation-rules
*/
public function getValidationRules(bool $reload = true): Collection
{
$defaultRules = Collection::create(PublicationFieldTypes::values());
$fieldRules = Collection::create($defaultRules->get($this->type->value));

$doBetween = true;
$useRange = true;
// The trim command used to process the min/max input results in a string, so
// we need to test both int and string values to determine required status.
if (($this->min && ! $this->max) || ($this->min == '0' && $this->max == '0')) {
$fieldRules->forget($fieldRules->search('required'));
$doBetween = false;
$useRange = false;
}

switch ($this->type->value) {
case 'array':
$fieldRules->add('array');
break;
case 'datetime':
if ($doBetween) {
$fieldRules->add("after:$this->min");
$fieldRules->add("before:$this->max");
$fieldRules->add('date');
if ($this->min) {
$dateMin = Carbon::parse($this->min);
$fieldRules->add("after:$dateMin");
}
if ($this->max) {
$dateMax = Carbon::parse($this->max);
$fieldRules->add("before:$dateMax");
}
break;
case 'float':
$fieldRules->add('numeric');
if ($useRange) {
$fieldRules->add("between:$this->min,$this->max");
}
break;
case 'integer':
case 'string':
case 'text':
if ($doBetween) {
if ($useRange) {
$fieldRules->add("between:$this->min,$this->max");
}
break;
Expand All @@ -97,16 +113,13 @@ public function getValidationRules(bool $reload = true): Collection
$fieldRules->add("in:$valueList");
break;
case 'tag':
$tagValues = PublicationService::getValuesForTagName($this->tagGroup, $reload);
$tagValues = PublicationService::getValuesForTagName($this->tagGroup, $reload) ?? collect([]);
$valueList = $tagValues->implode(',');
$fieldRules->add("in:$valueList");
break;
case 'url':
$fieldRules->add('url');
break;
default:
throw new \InvalidArgumentException(
"Unhandled field type [{$this->type->value}]. Possible field types are: ".implode(', ', PublicationFieldTypes::values())
);
}

return $fieldRules;
Expand Down
14 changes: 13 additions & 1 deletion packages/framework/tests/Feature/PublicationFieldTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ public function test_max_value_cannot_be_less_than_min_value()
new PublicationField('string', 'test', '10', '1');
}

public function test_only_min_value_can_be_set()
{
new PublicationField('string', 'test', '1');
$this->assertTrue(true);
}

public function test_only_max_value_can_be_set()
{
new PublicationField('string', 'test', null, '10');
$this->assertTrue(true);
}

public function test_integers_can_be_added_as_strings()
{
$field = new PublicationField('string', 'test', '1', '10');
Expand All @@ -102,7 +114,7 @@ public function test_integers_can_be_added_as_strings()
public function test_type_must_be_valid()
{
$this->expectException(ValueError::class);
$this->expectExceptionMessage('"invalid" is not a valid backing value for enum "Hyde\Framework\Features\Publications\PublicationFieldTypes"');
$this->expectExceptionMessage('"invalid" is not a valid backing value for enum "'.PublicationFieldTypes::class.'"');

new PublicationField('invalid', 'test', '1', '10');
}
Expand Down
103 changes: 103 additions & 0 deletions packages/framework/tests/Unit/PublicationFieldValidationRulesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Unit;

use Hyde\Framework\Features\Publications\Models\PublicationField;
use Hyde\Framework\Features\Publications\Models\PublicationType;
use Hyde\Testing\TestCase;
use Illuminate\Validation\ValidationException;

/**
* @covers \Hyde\Framework\Features\Publications\Models\PublicationField
*/
class PublicationFieldValidationRulesTest extends TestCase
{
public function testGetRulesForArray()
{
$rules = (new PublicationField('array', 'myArray'))->getValidationRules();
$this->assertSame(['array'], $rules->toArray());
}

public function testValidateArrayPasses()
{
$validated = (new PublicationField('array', 'myArray'))->validate(['foo', 'bar', 'baz']);
$this->assertSame(['my-array' => ['foo', 'bar', 'baz']], $validated);
}

public function testValidateArrayFails()
{
$this->expectValidationException('The my-array must be an array.');
(new PublicationField('array', 'myArray'))->validate('foo');
}

public function testGetRulesForDatetime()
{
$rules = (new PublicationField('datetime', 'myDatetime'))->getValidationRules();
$this->assertSame(['date'], $rules->toArray());
}

public function testValidateDatetimePasses()
{
$validated = (new PublicationField('datetime', 'myDatetime'))->validate('2021-01-01');
$this->assertSame(['my-datetime' => '2021-01-01'], $validated);
}

public function testValidateDatetimeFailsForInvalidType()
{
$this->expectValidationException('The my-datetime is not a valid date.');
(new PublicationField('datetime', 'myDatetime'))->validate('string');
}

public function testGetRulesForFloat()
{
$rules = (new PublicationField('float', 'myFloat'))->getValidationRules();
$this->assertSame(['numeric'], $rules->toArray());
}

public function testGetRulesForInteger()
{
$rules = (new PublicationField('integer', 'myInteger'))->getValidationRules();
$this->assertSame([], $rules->toArray());
}

public function testGetRulesForString()
{
$rules = (new PublicationField('string', 'myString'))->getValidationRules();
$this->assertSame([], $rules->toArray());
}

public function testGetRulesForText()
{
$rules = (new PublicationField('text', 'myText'))->getValidationRules();
$this->assertSame([], $rules->toArray());
}

public function testGetRulesForImage()
{
$this->directory('_media/foo');
$this->file('_media/foo/bar.jpg');
$this->file('_media/foo/baz.png');
$rules = (new PublicationField('image', 'myImage', publicationType: new PublicationType('foo')))->getValidationRules();
$this->assertSame(['in:_media/foo/bar.jpg,_media/foo/baz.png'], $rules->toArray());
}

public function testGetRulesForTag()
{
$rules = (new PublicationField('tag', 'myTag', tagGroup: 'foo'))->getValidationRules();
$this->assertSame(['in:'], $rules->toArray());
}

public function testGetRulesForUrl()
{
$rules = (new PublicationField('url', 'myUrl'))->getValidationRules();
$this->assertSame(['url'], $rules->toArray());
}

protected function expectValidationException(string $message): void
{
$this->expectException(ValidationException::class);
$this->expectExceptionMessage($message);
}
}