Skip to content

Commit

Permalink
* fix not reset keys of reordered array for value of unique param `po…
Browse files Browse the repository at this point in the history
…stTypes` @ `addDefaultParamsThenValidate()`

* inline field `$currentPostTypes` as param of method `validate4000(3|4)()`
@ `ParamsValidator`

* now will throw exception when passing an array with numeric as its first key
* mark public field `$name` as readonly
@ `QueryParam`

* lower the visibility of field `$params` from `protected` to `private` @ `QueryParams`
@ `App\Http\PostsQuery`

* move data from test into provider methods @ `BaseQueryTest` & `CursorCodecTest`
@ `Tests\Feature\App\Http\PostsQuery`
@ be
  • Loading branch information
n0099 committed Sep 23, 2024
1 parent 9fadc11 commit ee11e21
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 59 deletions.
2 changes: 1 addition & 1 deletion be/app/Http/Controllers/PostsQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function query(\Illuminate\Http\Request $request): array
$isSearchQuery = !$isIndexQuery;
Helper::abortAPIIf(40002, $isSearchQuery && $isFidParamNull);

$validator->addDefaultParamsThenValidate($isIndexQuery);
$validator->addDefaultParamsThenValidate(shouldSkip40003: $isIndexQuery);

$queryClass = $isIndexQuery ? IndexQuery::class : SearchQuery::class;
$this->debugbar->startMeasure('$queryClass->query()');
Expand Down
18 changes: 9 additions & 9 deletions be/app/Http/PostsQuery/ParamsValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class ParamsValidator

public QueryParams $params;

protected array $currentPostTypes;

/** @param array[] $params */
public function __construct(private readonly Factory $validator, array $params)
Expand All @@ -29,12 +28,13 @@ public function addDefaultParamsThenValidate(bool $shouldSkip40003): void
$this->params->addDefaultValueOnParams();

Check warning on line 28 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (ubuntu-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ } public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { - $this->params->addDefaultValueOnParams(); + $this->params->addDefaultValueOnUniqueParams(); // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all();

Check warning on line 28 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ } public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { - $this->params->addDefaultValueOnParams(); + $this->params->addDefaultValueOnUniqueParams(); // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all();

Check warning on line 28 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (macos-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ } public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { - $this->params->addDefaultValueOnParams(); + $this->params->addDefaultValueOnUniqueParams(); // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all();
$this->params->addDefaultValueOnUniqueParams();

Check warning on line 29 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (ubuntu-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { $this->params->addDefaultValueOnParams(); - $this->params->addDefaultValueOnUniqueParams(); + // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes);

Check warning on line 29 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { $this->params->addDefaultValueOnParams(); - $this->params->addDefaultValueOnUniqueParams(); + // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes);

Check warning on line 29 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (macos-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ public function addDefaultParamsThenValidate(bool $shouldSkip40003) : void { $this->params->addDefaultValueOnParams(); - $this->params->addDefaultValueOnUniqueParams(); + // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes);
// sort here to prevent further sort while validating
$this->params->setUniqueParamValue('postTypes', Arr::sort($this->params->getUniqueParamValue('postTypes')));
$this->currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes');
$sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all();
$this->params->setUniqueParamValue('postTypes', $sortedPostTypes);

Check warning on line 32 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (ubuntu-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ $this->params->addDefaultValueOnUniqueParams(); // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); - $this->params->setUniqueParamValue('postTypes', $sortedPostTypes); + $currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes'); if (!$shouldSkip40003) { $this->validate40003($currentPostTypes);
$currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes');

Check warning on line 33 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (ubuntu-latest) / phpunit-infection

Escaped Mutant for Mutator "CastArray": --- Original +++ New @@ @@ // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes); - $currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes'); + $currentPostTypes = $this->params->getUniqueParamValue('postTypes'); if (!$shouldSkip40003) { $this->validate40003($currentPostTypes); }

Check warning on line 33 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpunit-infection

Escaped Mutant for Mutator "CastArray": --- Original +++ New @@ @@ // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes); - $currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes'); + $currentPostTypes = $this->params->getUniqueParamValue('postTypes'); if (!$shouldSkip40003) { $this->validate40003($currentPostTypes); }

Check warning on line 33 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (macos-latest) / phpunit-infection

Escaped Mutant for Mutator "CastArray": --- Original +++ New @@ @@ // sort here to prevent further sort while validating $sortedPostTypes = collect($this->params->getUniqueParamValue('postTypes'))->sort()->values()->all(); $this->params->setUniqueParamValue('postTypes', $sortedPostTypes); - $currentPostTypes = (array) $this->params->getUniqueParamValue('postTypes'); + $currentPostTypes = $this->params->getUniqueParamValue('postTypes'); if (!$shouldSkip40003) { $this->validate40003($currentPostTypes); }
if (!$shouldSkip40003) {
$this->validate40003();
$this->validate40003($currentPostTypes);
}
$this->validate40004();
$this->validate40004($currentPostTypes);

Check warning on line 37 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ if (!$shouldSkip40003) { $this->validate40003($currentPostTypes); } - $this->validate40004($currentPostTypes); + } private function validateParamsValue(array $params) : void {

Check warning on line 37 in be/app/Http/PostsQuery/ParamsValidator.php

View workflow job for this annotation

GitHub Actions / runs-on (macos-latest) / phpunit-infection

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ if (!$shouldSkip40003) { $this->validate40003($currentPostTypes); } - $this->validate40004($currentPostTypes); + } private function validateParamsValue(array $params) : void {
}

private function validateParamsValue(array $params): void
Expand Down Expand Up @@ -106,7 +106,7 @@ private static function isRequiredPostTypes(array $current, array $required): bo
: $current === $required[1];
}

private function validate40003(): void
private function validate40003(array $currentPostTypes): void
{
$paramsRequiredPostTypes = [
'pid' => ['SUB', ['reply', 'subReply']],
Expand All @@ -127,12 +127,12 @@ private function validate40003(): void
];
foreach ($paramsRequiredPostTypes as $paramName => $requiredPostTypes) {
if ($this->params->pick($paramName) !== []) {
Helper::abortAPIIfNot(40003, self::isRequiredPostTypes($this->currentPostTypes, $requiredPostTypes));
Helper::abortAPIIfNot(40003, self::isRequiredPostTypes($currentPostTypes, $requiredPostTypes));
}
}
}

private function validate40004(): void
private function validate40004(array $currentPostTypes): void
{
$orderByRequiredPostTypes = [
'pid' => ['SUB', ['reply', 'subReply']],
Expand All @@ -142,7 +142,7 @@ private function validate40004(): void
if (\array_key_exists($currentOrderBy, $orderByRequiredPostTypes)) {
Helper::abortAPIIfNot(
40004,
self::isRequiredPostTypes($this->currentPostTypes, $orderByRequiredPostTypes[$currentOrderBy]),
self::isRequiredPostTypes($currentPostTypes, $orderByRequiredPostTypes[$currentOrderBy]),
);
}
}
Expand Down
5 changes: 4 additions & 1 deletion be/app/Http/PostsQuery/QueryParam.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class QueryParam
{
public string $name;
public readonly string $name;

public array|string|int $value;

Expand All @@ -13,6 +13,9 @@ class QueryParam
public function __construct(array $param)
{
$this->name = (string) array_keys($param)[0];
if (is_numeric($this->name)) {
throw new \InvalidArgumentException();
}
$this->value = $param[$this->name];
array_shift($param);
$this->subParams = $param;
Expand Down
4 changes: 2 additions & 2 deletions be/app/Http/PostsQuery/QueryParams.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
class QueryParams
{
/** @var QueryParam[] */
protected array $params;
private array $params;

/** @param array[] $params */
public function __construct(array $params)
{
$this->params = array_map(static fn($p) => new QueryParam($p), $params);
$this->params = array_map(static fn(array $p) => new QueryParam($p), $params);
}

/** @psalm-return int<0, max> */
Expand Down
50 changes: 30 additions & 20 deletions be/tests/Feature/App/Http/PostsQuery/BaseQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Barryvdh\Debugbar\LaravelDebugbar;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

#[CoversClass(BaseQuery::class)]
Expand All @@ -35,10 +34,9 @@ public function testPerPageItemsDefaultValue(): void
self::assertEquals(50, $prop->getValue($this->sut));
}

#[Test]
#[DataProvider('reOrderNestedPostsDataProvider')]
#[DataProvider('provideReOrderNestedPostsData')]
/** @backupStaticAttributes enabled */
public function reOrderNestedPosts(
public function testReOrderNestedPosts(
array $input,
bool $orderByDesc,
array $expected,
Expand All @@ -50,11 +48,11 @@ public function reOrderNestedPosts(
if ($shouldRemoveSortingKey) { // make https://infection.github.io/guide/mutators.html#TrueValue happy
self::assertEquals($expected, $this->sut->reOrderNestedPosts($input));
} else {

Check failure on line 50 in be/tests/Feature/App/Http/PostsQuery/BaseQueryTest.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpmd

BaseQueryTest.php: The method testReOrderNestedPosts uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them. (ElseExpression, Clean Code Rules)
self::assertEquals($expected, $this->sut->reOrderNestedPosts($input, false));
self::assertEquals($expected, $this->sut->reOrderNestedPosts($input, shouldRemoveSortingKey: false));
}
}

public static function reOrderNestedPostsDataProvider(): array
public static function provideReOrderNestedPostsData(): array

Check warning on line 55 in be/tests/Feature/App/Http/PostsQuery/BaseQueryTest.php

View workflow job for this annotation

GitHub Actions / runs-on (windows-latest) / phpmd

BaseQueryTest.php: The method provideReOrderNestedPostsData() has 168 lines of code. Current threshold is set to 100. Avoid really long methods. (ExcessiveMethodLength, Code Size Rules)
{
$input = [
[
Expand Down Expand Up @@ -223,24 +221,36 @@ public static function reOrderNestedPostsDataProvider(): array
];
}

#[Test]
#[DataProvider('provideNestPostsWithParent')]
/** @backupStaticAttributes enabled */
public function nestPostsWithParent(): void
public function testNestPostsWithParent(array $input, array $expected): void
{
self::assertEquals(
collect($expected)->recursive(),
$this->sut->nestPostsWithParent(...array_map('collect', $input)),
);
}

public static function provideNestPostsWithParent(): array
{
(new \ReflectionClass(Post::class))->setStaticPropertyValue('unguarded', true);
$input = array_map('collect', [
'threads' => [new Thread(['tid' => 1])],
'replies' => [new Reply(['tid' => 1, 'pid' => 2])],
'subReplies' => [new SubReply(['tid' => 1, 'pid' => 2, 'spid' => 3])],
]);
$expected = collect([[
'tid' => 1,
'replies' => [[
$ret = [[
[
'threads' => [new Thread(['tid' => 1])],
'replies' => [new Reply(['tid' => 1, 'pid' => 2])],
'subReplies' => [new SubReply(['tid' => 1, 'pid' => 2, 'spid' => 3])],
],
[[
'tid' => 1,
'pid' => 2,
'subReplies' => [['tid' => 1, 'pid' => 2, 'spid' => 3]],
'replies' => [[
'tid' => 1,
'pid' => 2,
'subReplies' => [['tid' => 1, 'pid' => 2, 'spid' => 3]],
]],
]],
]])->recursive();
self::assertEquals($expected, $this->sut->nestPostsWithParent(...$input));
]];
// https://github.com/sebastianbergmann/phpunit/issues/5103
(new \ReflectionClass(Post::class))->setStaticPropertyValue('unguarded', false);
return $ret;
}
}
69 changes: 43 additions & 26 deletions be/tests/Feature/App/Http/PostsQuery/CursorCodecTest.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<?php

namespace App\Http\PostsQuery;
namespace Tests\Feature\App\Http\PostsQuery;

use App\Eloquent\Model\Post\Post;
use App\Eloquent\Model\Post\Reply;
use App\Eloquent\Model\Post\SubReply;
use App\Eloquent\Model\Post\Thread;
use App\Http\PostsQuery\CursorCodec;
use Illuminate\Pagination\Cursor;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;

#[CoversClass(CursorCodec::class)]
Expand All @@ -22,34 +23,50 @@ protected function setUp(): void
$this->sut = new CursorCodec();
}

#[Test]
/** @backupStaticAttributes enabled */
public function encodeNextCursor(): void
#[DataProvider('provideEncodeNextCursor')]
public function testEncodeNextCursor(string $cursor, array $input): void
{
self::assertEquals($cursor, $this->sut->encodeNextCursor(collect($input)->recursive(maxDepth: 0), 'postedAt'));
}

public static function provideEncodeNextCursor(): array
{
(new \ReflectionClass(Post::class))->setStaticPropertyValue('unguarded', true);
$input = collect([
'threads' => [new Thread(['tid' => 1, 'postedAt' => 0])],
'replies' => [new Reply(['pid' => 2, 'postedAt' => -2147483649])],
'subReplies' => [new SubReply(['spid' => 3, 'postedAt' => 'test'])],
])->recursive(maxDepth: 0);
self::assertEquals('AQ,0,Ag,-:____fw,Aw,S:test', $this->sut->encodeNextCursor($input, 'postedAt'));
$ret = [[
'AQ,0,Ag,-:____fw,Aw,S:test',
[
'threads' => [new Thread(['tid' => 1, 'postedAt' => 0])],
'replies' => [new Reply(['pid' => 2, 'postedAt' => -2147483649])],
'subReplies' => [new SubReply(['spid' => 3, 'postedAt' => 'test'])],
],
]];
// https://github.com/sebastianbergmann/phpunit/issues/5103
(new \ReflectionClass(Post::class))->setStaticPropertyValue('unguarded', false);
return $ret;
}

#[DataProvider('provideDecodeCursor')]
public function testDecodeCursor(string $cursor, array $expected): void
{
self::assertEquals(collect($expected), $this->sut->decodeCursor($cursor, 'postedAt'));
}

#[Test]
public function decodeCursor(): void
public static function provideDecodeCursor(): array
{
$expected = collect([
'thread' => new Cursor(['tid' => 1, 'postedAt' => 0]),
'reply' => new Cursor(['pid' => 2, 'postedAt' => -2147483649]),
'subReply' => new Cursor(['spid' => 3, 'postedAt' => 'test']),
]);
self::assertEquals($expected, $this->sut->decodeCursor('AQ,0,Ag,-:____fw,Aw,S:test', 'postedAt'));

$expected = collect([
'thread' => new Cursor(['tid' => 0, 'postedAt' => 0]),
'reply' => new Cursor(['pid' => 0, 'postedAt' => 0]),
'subReply' => new Cursor(['spid' => 0, 'postedAt' => 0]),
]);
self::assertEquals($expected, $this->sut->decodeCursor(',,,,0,0', 'postedAt'));
return [[
'AQ,0,Ag,-:____fw,Aw,S:test',
[
'thread' => new Cursor(['tid' => 1, 'postedAt' => 0]),
'reply' => new Cursor(['pid' => 2, 'postedAt' => -2147483649]),
'subReply' => new Cursor(['spid' => 3, 'postedAt' => 'test']),
],
], [
',,,,0,0',
[
'thread' => new Cursor(['tid' => 0, 'postedAt' => 0]),
'reply' => new Cursor(['pid' => 0, 'postedAt' => 0]),
'subReply' => new Cursor(['spid' => 0, 'postedAt' => 0]),
],
]];
}
}

0 comments on commit ee11e21

Please sign in to comment.