Prevent serialization of non-backed enums#6796
Prevent serialization of non-backed enums#6796innerfly wants to merge 8 commits intoCodeception:mainfrom
Conversation
Arhell
left a comment
There was a problem hiding this comment.
@Naktibalda look when you have time, thanks
|
@innerfly Can you try to add a test case? |
|
@W0rma Simple test case: Result: |
|
@innerfly I think what he meant was a test that can be added to the repo showing that this is fixed with your changes and ensures it won't break again by some future changes. |
src/Codeception/Test/Descriptor.php
Outdated
| $signature .= ':' . substr(sha1($encoded), 0, 7); | ||
| try { | ||
| if (method_exists($testCase, 'getMetadata') && $example = $testCase->getMetadata()->getCurrent('example')) { | ||
| $encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE); |
There was a problem hiding this comment.
This will avoid breaking the whole execution, however this might result in non-unique signatures being returned as the error will just get ignored. I don't know if this is an issue or not.
But I think we could improve this even further by avoiding an exception entirely. We could convert enums manually before passing the example to json_encode. Maybe something like this:
| $encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE); | |
| $example = self::normalizeForJsonEncoding($example); | |
| $encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE); | |
| // ... | |
| } | |
| private static function normalizeForJsonEncoding(mixed $value): mixed | |
| { | |
| return match (true) { | |
| is_array($value) => array_map(self::normalizeForJsonEncoding(...), $value), | |
| $value instanceof UnitEnum => $value->name, | |
| default => $value, | |
| }; | |
| } |
There was a problem hiding this comment.
@burned42 I have added manual enum convertions following your idea, and test cases to cover this
There was a problem hiding this comment.
Just one minor nitpick, it's not necessary to manually convert backed enums as those can indeed be serialized to json and only the non-backed enums cause issues.
Unfortunately github tells me I don't have the permission to mark my discussions as resolved, but the change itself looks good to me now other than this small note 👍
The test setup looks a bit complicated, but I don't know if that can be simplified. The tests do seem to cover the changed code though :)
There was a problem hiding this comment.
Idea of adding backed enums before unit enums was to process them before unit enums because techically every enum is UnitEnum (BackedEnum extends UnitEnum). Following
$value instanceof UnitEnum => $value->name,
would convert every enum. Ended up by adding advanced checking, this way it looks more obvious
$value instanceof UnitEnum && !($value instanceof BackedEnum) => $value->name,
0fa872b to
a1684b0
Compare
a1684b0 to
da50e50
Compare
src/Codeception/Test/Descriptor.php
Outdated
| }; | ||
| } | ||
|
|
||
| private static function normalizeForJsonEncoding(mixed $value): mixed |
There was a problem hiding this comment.
Indentation is a bit off here:
| private static function normalizeForJsonEncoding(mixed $value): mixed | |
| private static function normalizeForJsonEncoding(mixed $value): mixed |
Fixes an #6753, when json_encode fails to serialize non-backed enum.
Follow up #6762 (comment)