<?php // BencodeSerialisableTest.php // Created: 2024-09-29 // Updated: 2025-04-02 declare(strict_types=1); use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\{CoversClass,UsesClass}; use Index\Bencode\{Bencode,BencodeProperty,BencodeSerializable,BencodeSerializableCommon}; #[CoversClass(BencodeProperty::class)] #[CoversClass(BencodeSerializableCommon::class)] #[UsesClass(Bencode::class)] #[UsesClass(BencodeSerializable::class)] final class BencodeSerialisableTest extends TestCase { private const BASIC_BENCODED_ENCODED = 'd9:stringVal12:string value6:intVali1234e9:intStrVal4:56788:floatVal5:12.3411:floatStrVal5:56.787:trueVali1e22:truePossiblyOmittedVali1e8:falseVali0e14:nullValPresent10:scalarValsli0ei1234e5:12.343:stre16:stringVal_method12:string value9:getIntVali1234e11:getFloatVal5:12.3417:getFloatStringVal5:56.7810:getTrueVali1e25:getTruePossiblyOmittedVali1e11:getFalseVali0e17:getNullValPresent13:getScalarValsli0ei1234e5:12.343:stre5:innerd3:objd3:str21:wow this is illegibleee15:getIntStringVal4:5678e'; public function testBasicBencodedObject(): void { $test = new class implements BencodeSerializable { use BencodeSerializableCommon; #[BencodeProperty] public string $stringVal = 'string value'; #[BencodeProperty] public int $intVal = 1234; #[BencodeProperty(numbersAsString: true)] public int $intStrVal = 5678; #[BencodeProperty] public float $floatVal = 12.34; #[BencodeProperty(numbersAsString: true)] public float $floatStrVal = 56.78; #[BencodeProperty] public bool $trueVal = true; #[BencodeProperty(omitIfValue: false)] public bool $truePossiblyOmittedVal = true; #[BencodeProperty] public bool $falseVal = false; #[BencodeProperty(omitIfValue: false)] public bool $falseOmittedVal = false; #[BencodeProperty] public mixed $nullValOmitted = null; #[BencodeProperty(omitIfNull: false)] public mixed $nullValPresent = null; /** @var array<?scalar> */ #[BencodeProperty] public array $scalarVals = [null, 0, 1234, 12.34, 'str', true, false]; #[BencodeProperty('stringVal_method')] public function getStringVal(): string { return 'string value'; } #[BencodeProperty] public function getIntVal(): int { return 1234; } #[BencodeProperty(order: 1, numbersAsString: true)] public function getIntStringVal(): int { return 5678; } #[BencodeProperty] public function getFloatVal(): float { return 12.34; } #[BencodeProperty(numbersAsString: true)] public function getFloatStringVal(): float { return 56.78; } #[BencodeProperty] public function getTrueVal(): bool { return true; } #[BencodeProperty(omitIfValue: false)] public function getTruePossiblyOmittedVal(): bool { return true; } #[BencodeProperty] public function getFalseVal(): bool { return false; } #[BencodeProperty(omitIfValue: false)] public function getFalseOmittedVal(): bool { return false; } #[BencodeProperty] public function getNullValOmitted(): mixed { return null; } #[BencodeProperty(omitIfNull: false)] public function getNullValPresent(): mixed { return null; } /** @return array<?scalar> */ #[BencodeProperty] public function getScalarVals(): array { return [null, 0, 1234, 12.34, 'str', true, false]; } #[BencodeProperty('inner')] public function getObject(): object { return new class implements BencodeSerializable { use BencodeSerializableCommon; #[BencodeProperty('obj')] public function getObject(): object { return new class implements BencodeSerializable { use BencodeSerializableCommon; #[BencodeProperty('str')] public function getString(): string { return 'wow this is illegible'; } }; } }; } public function methodWithArguments(string $meow): string { return $meow; } public static function staticMethodWithArguments(string $meow): string { return $meow; } }; $this->assertEquals(self::BASIC_BENCODED_ENCODED, Bencode::encode($test)); } public function testDoubleBencodedProperty(): void { $this->expectException(RuntimeException::class); $test = new class implements BencodeSerializable { use BencodeSerializableCommon; #[BencodeProperty('test1')] #[BencodeProperty('test2')] // @phpstan-ignore attribute.nonRepeatable public string $stringVal = 'string value'; #[BencodeProperty('test3')] #[BencodeProperty('test4')] // @phpstan-ignore attribute.nonRepeatable public function getIntVal(): int { return 1234; } }; Bencode::encode($test); } public function testDuplicateBencodedProperty(): void { $this->expectException(RuntimeException::class); $test = new class implements BencodeSerializable { use BencodeSerializableCommon; #[BencodeProperty] public string $test1 = 'string value'; #[BencodeProperty('test1')] public function getIntVal(): int { return 1234; } }; Bencode::encode($test); } }