<?php // JsonSerializableTest.php // Created: 2024-09-29 // Updated: 2025-04-02 declare(strict_types=1); use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\CoversClass; use Index\Json\{JsonProperty,JsonSerializableCommon}; #[CoversClass(JsonProperty::class)] #[CoversClass(JsonSerializableCommon::class)] final class JsonSerializableTest extends TestCase { private const BASIC_JSON_ENCODED = '{"stringVal":"string value","intVal":1234,"intStrVal":"5678","floatVal":12.34,"floatStrVal":"56.78","trueVal":true,"truePossiblyOmittedVal":true,"falseVal":false,"nullValPresent":null,"scalarVals":[null,0,1234,12.34,"str",true,false],"stringVal_method":"string value","getIntVal":1234,"getFloatVal":12.34,"getFloatStringVal":"56.78","getTrueVal":true,"getTruePossiblyOmittedVal":true,"getFalseVal":false,"getNullValPresent":null,"getScalarVals":[null,0,1234,12.34,"str",true,false],"inner":{"obj":{"str":"wow this is illegible"}},"getIntStringVal":"5678"}'; public function testBasicJsonObject(): void { $test = new class implements JsonSerializable { use JsonSerializableCommon; #[JsonProperty] public string $stringVal = 'string value'; #[JsonProperty] public int $intVal = 1234; #[JsonProperty(numbersAsString: true)] public int $intStrVal = 5678; #[JsonProperty] public float $floatVal = 12.34; #[JsonProperty(numbersAsString: true)] public float $floatStrVal = 56.78; #[JsonProperty] public bool $trueVal = true; #[JsonProperty(omitIfValue: false)] public bool $truePossiblyOmittedVal = true; #[JsonProperty] public bool $falseVal = false; #[JsonProperty(omitIfValue: false)] public bool $falseOmittedVal = false; #[JsonProperty] public mixed $nullValOmitted = null; #[JsonProperty(omitIfNull: false)] public mixed $nullValPresent = null; /** @var array<?scalar> */ #[JsonProperty] public array $scalarVals = [null, 0, 1234, 12.34, 'str', true, false]; #[JsonProperty('stringVal_method')] public function getStringVal(): string { return 'string value'; } #[JsonProperty] public function getIntVal(): int { return 1234; } #[JsonProperty(order: 1, numbersAsString: true)] public function getIntStringVal(): int { return 5678; } #[JsonProperty] public function getFloatVal(): float { return 12.34; } #[JsonProperty(numbersAsString: true)] public function getFloatStringVal(): float { return 56.78; } #[JsonProperty] public function getTrueVal(): bool { return true; } #[JsonProperty(omitIfValue: false)] public function getTruePossiblyOmittedVal(): bool { return true; } #[JsonProperty] public function getFalseVal(): bool { return false; } #[JsonProperty(omitIfValue: false)] public function getFalseOmittedVal(): bool { return false; } #[JsonProperty] public function getNullValOmitted(): mixed { return null; } #[JsonProperty(omitIfNull: false)] public function getNullValPresent(): mixed { return null; } /** @return array<?scalar> */ #[JsonProperty] public function getScalarVals(): array { return [null, 0, 1234, 12.34, 'str', true, false]; } #[JsonProperty('inner')] public function getObject(): object { return new class implements JsonSerializable { use JsonSerializableCommon; #[JsonProperty('obj')] public function getObject(): object { return new class implements JsonSerializable { use JsonSerializableCommon; #[JsonProperty('str')] public function getString(): string { return 'wow this is illegible'; } }; } }; } public function methodWithArguments(string $meow, string $mewow): string { return $meow . $mewow; } public static function staticMethodWithArguments(string $meow, string $mewow): string { return $meow . $mewow; } }; $this->assertEquals(self::BASIC_JSON_ENCODED, json_encode($test)); } public function testDoubleJsonProperty(): void { $this->expectException(RuntimeException::class); $test = new class implements JsonSerializable { use JsonSerializableCommon; #[JsonProperty('test1')] #[JsonProperty('test2')] // @phpstan-ignore attribute.nonRepeatable public string $stringVal = 'string value'; #[JsonProperty('test3')] #[JsonProperty('test4')] // @phpstan-ignore attribute.nonRepeatable public function getIntVal(): int { return 1234; } }; json_encode($test); } public function testDuplicateJsonProperty(): void { $this->expectException(RuntimeException::class); $test = new class implements JsonSerializable { use JsonSerializableCommon; #[JsonProperty] public string $test1 = 'string value'; #[JsonProperty('test1')] public function getIntVal(): int { return 1234; } }; json_encode($test); } }