Docblocks, first pass with Psalm.

pull/150/head
Anthony Birkett 4 years ago
parent e62d011689
commit b5d355514b

@ -39,7 +39,7 @@ $Timer = number_format(microtime(true) - $Timer, 4, '.', '');
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Source Query PHP Library</title> <title>Source Query PHP Library</title>
@ -111,15 +111,13 @@ $Timer = number_format(microtime(true) - $Timer, 4, '.', '');
echo "<pre>"; echo "<pre>";
print_r($InfoValue); print_r($InfoValue);
echo "</pre>"; echo "</pre>";
} else { } elseif ($InfoValue === true) {
if ($InfoValue === true) {
echo 'true'; echo 'true';
} elseif ($InfoValue === false) { } elseif ($InfoValue === false) {
echo 'false'; echo 'false';
} else { } else {
echo htmlspecialchars($InfoValue); echo htmlspecialchars($InfoValue);
} }
}
?></td> ?></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>

@ -23,29 +23,82 @@ use xPaw\SourceQuery\Exception\SocketException;
* *
* @package xPaw\SourceQuery * @package xPaw\SourceQuery
* *
* @uses xPaw\SourceQuery\Exception\InvalidPacketException * @uses InvalidPacketException
* @uses xPaw\SourceQuery\Exception\SocketException * @uses SocketException
*/ */
abstract class BaseSocket abstract class BaseSocket
{ {
/** @var ?resource */ /**
* @var resource
*/
public $Socket; public $Socket;
public int $Engine;
public string $Address; /**
public int $Port; * @var int $Engine
public int $Timeout; */
public int $Engine = SourceQuery::SOURCE;
/**
* @var string $Address
*/
public string $Address = '';
/**
* @var int $Port
*/
public int $Port = 0;
/**
* @var int $Timeout
*/
public int $Timeout = 0;
/**
* Destructor
*/
public function __destruct() public function __destruct()
{ {
$this->Close(); $this->Close();
} }
/**
* Close
*/
abstract public function Close(): void; abstract public function Close(): void;
/**
* @param string $Address
* @param int $Port
* @param int $Timeout
* @param int $Engine
*/
abstract public function Open(string $Address, int $Port, int $Timeout, int $Engine): void; abstract public function Open(string $Address, int $Port, int $Timeout, int $Engine): void;
/**
* @param int $Header
* @param string $String
*
* @return bool
*/
abstract public function Write(int $Header, string $String = ''): bool; abstract public function Write(int $Header, string $String = ''): bool;
/**
* @param int $Length
*
* @return Buffer
*/
abstract public function Read(int $Length = 1400): Buffer; abstract public function Read(int $Length = 1400): Buffer;
/**
* @param Buffer $Buffer
* @param int $Length
* @param callable $SherlockFunction
*
* @return Buffer
*
* @throws InvalidPacketException
* @throws SocketException
*/
protected function ReadInternal(Buffer $Buffer, int $Length, callable $SherlockFunction): Buffer protected function ReadInternal(Buffer $Buffer, int $Length, callable $SherlockFunction): Buffer
{ {
if ($Buffer->Remaining() === 0) { if ($Buffer->Remaining() === 0) {
@ -54,12 +107,14 @@ abstract class BaseSocket
$Header = $Buffer->GetLong(); $Header = $Buffer->GetLong();
if ($Header === -1) { // Single packet // Single packet, do nothing.
// We don't have to do anything if ($Header === -1) {
} elseif ($Header === -2) { // Split packet return $Buffer;
}
if ($Header === -2) { // Split packet
$Packets = []; $Packets = [];
$IsCompressed = false; $IsCompressed = false;
$ReadMore = false;
$PacketChecksum = null; $PacketChecksum = null;
do { do {
@ -98,18 +153,13 @@ abstract class BaseSocket
$Packets[ $PacketNumber ] = $Buffer->Get(); $Packets[ $PacketNumber ] = $Buffer->Get();
$ReadMore = $PacketCount > sizeof($Packets); $ReadMore = $PacketCount > count($Packets);
} while ($ReadMore && $SherlockFunction($Buffer, $Length)); } while ($ReadMore && $SherlockFunction($Buffer, $Length));
$Data = implode($Packets); $Data = implode($Packets);
// TODO: Test this // TODO: Test this
if ($IsCompressed) { if ($IsCompressed) {
// Let's make sure this function exists, it's not included in PHP by default
if (!function_exists('bzdecompress')) {
throw new \RuntimeException('Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.');
}
$Data = bzdecompress($Data); $Data = bzdecompress($Data);
if (!is_string($Data) || crc32($Data) !== $PacketChecksum) { if (!is_string($Data) || crc32($Data) !== $PacketChecksum) {

@ -22,7 +22,7 @@ use xPaw\SourceQuery\Exception\InvalidPacketException;
* *
* @package xPaw\SourceQuery * @package xPaw\SourceQuery
* *
* @uses xPaw\SourceQuery\Exception\InvalidPacketException * @uses InvalidPacketException
*/ */
final class Buffer final class Buffer
{ {
@ -43,6 +43,8 @@ final class Buffer
/** /**
* Sets buffer * Sets buffer
*
* @param string $Buffer
*/ */
public function Set(string $Buffer): void public function Set(string $Buffer): void
{ {
@ -61,10 +63,20 @@ final class Buffer
return $this->Length - $this->Position; return $this->Length - $this->Position;
} }
/**
* @return bool
*/
public function isEmpty(): bool
{
return $this->Remaining() <= 0;
}
/** /**
* Gets data from buffer * Gets data from buffer
* *
* @param int $Length Bytes to read * @param int $Length Bytes to read
*
* @return string
*/ */
public function Get(int $Length = -1): string public function Get(int $Length = -1): string
{ {
@ -97,6 +109,8 @@ final class Buffer
/** /**
* Get short from buffer * Get short from buffer
*
* @throws InvalidPacketException
*/ */
public function GetShort(): int public function GetShort(): int
{ {
@ -111,6 +125,8 @@ final class Buffer
/** /**
* Get long from buffer * Get long from buffer
*
* @throws InvalidPacketException
*/ */
public function GetLong(): int public function GetLong(): int
{ {
@ -125,6 +141,8 @@ final class Buffer
/** /**
* Get float from buffer * Get float from buffer
*
* @throws InvalidPacketException
*/ */
public function GetFloat(): float public function GetFloat(): float
{ {
@ -139,6 +157,8 @@ final class Buffer
/** /**
* Get unsigned long from buffer * Get unsigned long from buffer
*
* @throws InvalidPacketException
*/ */
public function GetUnsignedLong(): int public function GetUnsignedLong(): int
{ {

@ -15,7 +15,9 @@ declare(strict_types=1);
namespace xPaw\SourceQuery\Exception; namespace xPaw\SourceQuery\Exception;
abstract class SourceQueryException extends \Exception use Exception;
abstract class SourceQueryException extends Exception
{ {
// Base exception class // Base exception class
} }

@ -33,28 +33,48 @@ final class GoldSourceRcon
* *
* @var BaseSocket * @var BaseSocket
*/ */
private $Socket; private BaseSocket $Socket;
/**
* @var string $RconPassword
*/
private string $RconPassword = ''; private string $RconPassword = '';
/**
* @var string $RconChallenge
*/
private string $RconChallenge = ''; private string $RconChallenge = '';
/**
* @param BaseSocket $Socket
*/
public function __construct(BaseSocket $Socket) public function __construct(BaseSocket $Socket)
{ {
$this->Socket = $Socket; $this->Socket = $Socket;
} }
/**
* Close
*/
public function Close(): void public function Close(): void
{ {
$this->RconChallenge = ''; $this->RconChallenge = '';
$this->RconPassword = ''; $this->RconPassword = '';
} }
/**
* Open
*/
public function Open(): void public function Open(): void
{ {
//
} }
public function Write(int $Header, string $String = ''): bool /**
* @param string $String
*
* @return bool
*/
public function Write(string $String = ''): bool
{ {
$Command = pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String); $Command = pack('cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String);
$Length = strlen($Command); $Length = strlen($Command);
@ -63,17 +83,17 @@ final class GoldSourceRcon
} }
/** /**
* @param int $Length
* @throws AuthenticationException * @throws AuthenticationException
* @throws InvalidPacketException
*
* @return Buffer * @return Buffer
*/ */
public function Read(int $Length = 1400): Buffer public function Read(): Buffer
{ {
// GoldSource RCON has same structure as Query // GoldSource RCON has same structure as Query
$Buffer = $this->Socket->Read(); $Buffer = $this->Socket->Read();
$StringBuffer = ''; $StringBuffer = '';
$ReadMore = false;
// There is no indentifier of the end, so we just need to continue reading // There is no indentifier of the end, so we just need to continue reading
do { do {
@ -110,23 +130,36 @@ final class GoldSourceRcon
return $Buffer; return $Buffer;
} }
/**
* @param string $Command
*
* @return string
*
* @throws AuthenticationException
* @throws InvalidPacketException
*/
public function Command(string $Command): string public function Command(string $Command): string
{ {
if (!$this->RconChallenge) { if (!$this->RconChallenge) {
throw new AuthenticationException('Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD); throw new AuthenticationException('Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD);
} }
$this->Write(0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0"); $this->Write('rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0");
$Buffer = $this->Read(); $Buffer = $this->Read();
return $Buffer->Get(); return $Buffer->Get();
} }
/**
* @param string $Password
*
* @throws AuthenticationException
*/
public function Authorize(string $Password): void public function Authorize(string $Password): void
{ {
$this->RconPassword = $Password; $this->RconPassword = $Password;
$this->Write(0, 'challenge rcon'); $this->Write('challenge rcon');
$Buffer = $this->Socket->Read(); $Buffer = $this->Socket->Read();
if ($Buffer->Get(14) !== 'challenge rcon') { if ($Buffer->Get(14) !== 'challenge rcon') {

@ -28,15 +28,26 @@ use xPaw\SourceQuery\Exception\SocketException;
*/ */
final class Socket extends BaseSocket final class Socket extends BaseSocket
{ {
/**
* Close
*/
public function Close(): void public function Close(): void
{ {
if ($this->Socket !== null) { if ($this->Socket !== null) {
fclose($this->Socket); fclose($this->Socket);
$this->Socket = null; $this->Socket = 0;
} }
} }
/**
* @param string $Address
* @param int $Port
* @param int $Timeout
* @param int $Engine
*
* @throws SocketException
*/
public function Open(string $Address, int $Port, int $Timeout, int $Engine): void public function Open(string $Address, int $Port, int $Timeout, int $Engine): void
{ {
$this->Timeout = $Timeout; $this->Timeout = $Timeout;
@ -55,6 +66,12 @@ final class Socket extends BaseSocket
stream_set_blocking($this->Socket, true); stream_set_blocking($this->Socket, true);
} }
/**
* @param int $Header
* @param string $String
*
* @return bool
*/
public function Write(int $Header, string $String = ''): bool public function Write(int $Header, string $String = ''): bool
{ {
$Command = pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String); $Command = pack('ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String);
@ -66,9 +83,13 @@ final class Socket extends BaseSocket
/** /**
* Reads from socket and returns Buffer. * Reads from socket and returns Buffer.
* *
* @throws InvalidPacketException * @param int $Length
* *
* @return Buffer Buffer * @return Buffer Buffer
*
* @throws InvalidPacketException
* @throws SocketException
*
*/ */
public function Read(int $Length = 1400): Buffer public function Read(int $Length = 1400): Buffer
{ {
@ -80,6 +101,14 @@ final class Socket extends BaseSocket
return $Buffer; return $Buffer;
} }
/**
* @param Buffer $Buffer
* @param int $Length
*
* @return bool
*
* @throws InvalidPacketException
*/
public function Sherlock(Buffer $Buffer, int $Length): bool public function Sherlock(Buffer $Buffer, int $Length): bool
{ {
$Data = fread($this->Socket, $Length); $Data = fread($this->Socket, $Length);

@ -15,6 +15,7 @@ declare(strict_types=1);
namespace xPaw\SourceQuery; namespace xPaw\SourceQuery;
use RuntimeException;
use xPaw\SourceQuery\Exception\AuthenticationException; use xPaw\SourceQuery\Exception\AuthenticationException;
use xPaw\SourceQuery\Exception\InvalidArgumentException; use xPaw\SourceQuery\Exception\InvalidArgumentException;
use xPaw\SourceQuery\Exception\InvalidPacketException; use xPaw\SourceQuery\Exception\InvalidPacketException;
@ -98,11 +99,17 @@ final class SourceQuery
*/ */
private bool $UseOldGetChallengeMethod = false; private bool $UseOldGetChallengeMethod = false;
/**
* @param BaseSocket|null $Socket
*/
public function __construct(BaseSocket $Socket = null) public function __construct(BaseSocket $Socket = null)
{ {
$this->Socket = $Socket ?: new Socket(); $this->Socket = $Socket ?: new Socket();
} }
/**
* Destructor
*/
public function __destruct() public function __destruct()
{ {
$this->Disconnect(); $this->Disconnect();
@ -137,7 +144,7 @@ final class SourceQuery
* *
* @param bool $Value Set to true to force old method * @param bool $Value Set to true to force old method
* *
* @returns bool Previous value * @return bool Previous value
*/ */
public function SetUseOldGetChallengeMethod(bool $Value): bool public function SetUseOldGetChallengeMethod(bool $Value): bool
{ {
@ -299,7 +306,6 @@ final class SourceQuery
if ($Flags & 0x10) { if ($Flags & 0x10) {
$SteamIDLower = $Buffer->GetUnsignedLong(); $SteamIDLower = $Buffer->GetUnsignedLong();
$SteamIDInstance = $Buffer->GetUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance $SteamIDInstance = $Buffer->GetUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance
$SteamID = 0;
if (PHP_INT_SIZE === 4) { if (PHP_INT_SIZE === 4) {
if (extension_loaded('gmp')) { if (extension_loaded('gmp')) {
@ -307,7 +313,7 @@ final class SourceQuery
$SteamIDInstance = gmp_abs($SteamIDInstance); $SteamIDInstance = gmp_abs($SteamIDInstance);
$SteamID = gmp_strval(gmp_or($SteamIDLower, gmp_mul($SteamIDInstance, gmp_pow(2, 32)))); $SteamID = gmp_strval(gmp_or($SteamIDLower, gmp_mul($SteamIDInstance, gmp_pow(2, 32))));
} else { } else {
throw new \RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.'); throw new RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.');
} }
} else { } else {
$SteamID = $SteamIDLower | ($SteamIDInstance << 32); $SteamID = $SteamIDLower | ($SteamIDInstance << 32);
@ -334,7 +340,7 @@ final class SourceQuery
$Server[ 'GameID' ] = $Buffer->GetUnsignedLong() | ($Buffer->GetUnsignedLong() << 32); $Server[ 'GameID' ] = $Buffer->GetUnsignedLong() | ($Buffer->GetUnsignedLong() << 32);
} }
if ($Buffer->Remaining() > 0) { if (!$Buffer->isEmpty()) {
throw new InvalidPacketException( throw new InvalidPacketException(
'GetInfo: unread data? ' . $Buffer->Remaining() . ' bytes remaining in the buffer. Please report it to the library developer.', 'GetInfo: unread data? ' . $Buffer->Remaining() . ' bytes remaining in the buffer. Please report it to the library developer.',
InvalidPacketException::BUFFER_NOT_EMPTY InvalidPacketException::BUFFER_NOT_EMPTY
@ -431,7 +437,11 @@ final class SourceQuery
/** /**
* Get challenge (used for players/rules packets) * Get challenge (used for players/rules packets)
* *
* @param int $Header
* @param int $ExpectedResult
*
* @throws InvalidPacketException * @throws InvalidPacketException
* @throws SocketException
*/ */
private function GetChallenge(int $Header, int $ExpectedResult): void private function GetChallenge(int $Header, int $ExpectedResult): void
{ {
@ -488,13 +498,13 @@ final class SourceQuery
} }
switch ($this->Socket->Engine) { switch ($this->Socket->Engine) {
case SourceQuery::GOLDSOURCE: case self::GOLDSOURCE:
{ {
$this->Rcon = new GoldSourceRcon($this->Socket); $this->Rcon = new GoldSourceRcon($this->Socket);
break; break;
} }
case SourceQuery::SOURCE: case self::SOURCE:
{ {
$this->Rcon = new SourceRcon($this->Socket); $this->Rcon = new SourceRcon($this->Socket);

@ -35,15 +35,27 @@ final class SourceRcon
*/ */
private BaseSocket $Socket; private BaseSocket $Socket;
/** @var ?resource */ /**
* @var ?resource
*/
private $RconSocket; private $RconSocket;
/**
* @var int $RconRequestId
*/
private int $RconRequestId = 0; private int $RconRequestId = 0;
/**
* @param BaseSocket $Socket
*/
public function __construct(BaseSocket $Socket) public function __construct(BaseSocket $Socket)
{ {
$this->Socket = $Socket; $this->Socket = $Socket;
} }
/**
* Close
*/
public function Close(): void public function Close(): void
{ {
if ($this->RconSocket) { if ($this->RconSocket) {
@ -55,6 +67,9 @@ final class SourceRcon
$this->RconRequestId = 0; $this->RconRequestId = 0;
} }
/**
* @throws SocketException
*/
public function Open(): void public function Open(): void
{ {
if (!$this->RconSocket) { if (!$this->RconSocket) {
@ -70,6 +85,12 @@ final class SourceRcon
} }
} }
/**
* @param int $Header
* @param string $String
*
* @return bool
*/
public function Write(int $Header, string $String = ''): bool public function Write(int $Header, string $String = ''): bool
{ {
// Pack the packet together // Pack the packet together
@ -82,6 +103,11 @@ final class SourceRcon
return $Length === fwrite($this->RconSocket, $Command, $Length); return $Length === fwrite($this->RconSocket, $Command, $Length);
} }
/**
* @return Buffer
*
* @throws InvalidPacketException
*/
public function Read(): Buffer public function Read(): Buffer
{ {
$Buffer = new Buffer(); $Buffer = new Buffer();
@ -117,6 +143,14 @@ final class SourceRcon
return $Buffer; return $Buffer;
} }
/**
* @param string $Command
*
* @return string
*
* @throws AuthenticationException
* @throws InvalidPacketException
*/
public function Command(string $Command): string public function Command(string $Command): string
{ {
$this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command); $this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
@ -161,6 +195,12 @@ final class SourceRcon
return rtrim($Data, "\0"); return rtrim($Data, "\0");
} }
/**
* @param string $Password
*
* @throws AuthenticationException
* @throws InvalidPacketException
*/
public function Authorize(string $Password): void public function Authorize(string $Password): void
{ {
$this->Write(SourceQuery::SERVERDATA_AUTH, $Password); $this->Write(SourceQuery::SERVERDATA_AUTH, $Password);

@ -6,28 +6,48 @@ use PHPUnit\Framework\TestCase;
use xPaw\SourceQuery\BaseSocket; use xPaw\SourceQuery\BaseSocket;
use xPaw\SourceQuery\SourceQuery; use xPaw\SourceQuery\SourceQuery;
use xPaw\SourceQuery\Buffer; use xPaw\SourceQuery\Buffer;
use xPaw\SourceQuery\Exception\AuthenticationException;
use xPaw\SourceQuery\Exception\InvalidArgumentException;
use xPaw\SourceQuery\Exception\InvalidPacketException;
use xPaw\SourceQuery\Exception\SocketException;
final class TestableSocket extends BaseSocket final class TestableSocket extends BaseSocket
{ {
/** @var \SplQueue<string> */ /**
private \SplQueue $PacketQueue; * @var SplQueue<string>
*/
private SplQueue $PacketQueue;
/**
* TestableSocket constructor.
*/
public function __construct() public function __construct()
{ {
$this->PacketQueue = new \SplQueue(); $this->PacketQueue = new SplQueue();
$this->PacketQueue->setIteratorMode(\SplDoublyLinkedList::IT_MODE_DELETE); $this->PacketQueue->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE);
} }
/**
* @param string $Data
*/
public function Queue(string $Data): void public function Queue(string $Data): void
{ {
$this->PacketQueue->push($Data); $this->PacketQueue->push($Data);
} }
/**
* Close.
*/
public function Close(): void public function Close(): void
{ {
//
} }
/**
* @param string $Address
* @param int $Port
* @param int $Timeout
* @param int $Engine
*/
public function Open(string $Address, int $Port, int $Timeout, int $Engine): void public function Open(string $Address, int $Port, int $Timeout, int $Engine): void
{ {
$this->Timeout = $Timeout; $this->Timeout = $Timeout;
@ -36,11 +56,25 @@ final class TestableSocket extends BaseSocket
$this->Address = $Address; $this->Address = $Address;
} }
/**
* @param int $Header
* @param string $String
*
* @return bool
*/
public function Write(int $Header, string $String = ''): bool public function Write(int $Header, string $String = ''): bool
{ {
return true; return true;
} }
/**
* @param int $Length
*
* @return Buffer
*
* @throws InvalidPacketException
* @throws SocketException
*/
public function Read(int $Length = 1400): Buffer public function Read(int $Length = 1400): Buffer
{ {
$Buffer = new Buffer(); $Buffer = new Buffer();
@ -51,7 +85,14 @@ final class TestableSocket extends BaseSocket
return $Buffer; return $Buffer;
} }
public function Sherlock(Buffer $Buffer, int $Length): bool /**
* @param Buffer $Buffer
*
* @return bool
*
* @throws InvalidPacketException
*/
public function Sherlock(Buffer $Buffer): bool
{ {
if ($this->PacketQueue->isEmpty()) { if ($this->PacketQueue->isEmpty()) {
return false; return false;
@ -65,9 +106,20 @@ final class TestableSocket extends BaseSocket
final class Tests extends TestCase final class Tests extends TestCase
{ {
/**
* @var TestableSocket $Socket
*/
private TestableSocket $Socket; private TestableSocket $Socket;
/**
* @var SourceQuery $SourceQuery
*/
private SourceQuery $SourceQuery; private SourceQuery $SourceQuery;
/**
* @throws SocketException
* @throws InvalidArgumentException
*/
public function setUp(): void public function setUp(): void
{ {
$this->Socket = new TestableSocket(); $this->Socket = new TestableSocket();
@ -75,6 +127,9 @@ final class Tests extends TestCase
$this->SourceQuery->Connect('', 2); $this->SourceQuery->Connect('', 2);
} }
/**
* tearDown
*/
public function tearDown(): void public function tearDown(): void
{ {
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
@ -82,65 +137,103 @@ final class Tests extends TestCase
unset($this->Socket, $this->SourceQuery); unset($this->Socket, $this->SourceQuery);
} }
/**
* @throws InvalidArgumentException
* @throws SocketException
*/
public function testInvalidTimeout(): void public function testInvalidTimeout(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$SourceQuery = new SourceQuery(); $SourceQuery = new SourceQuery();
$SourceQuery->Connect('', 2, -1); $SourceQuery->Connect('', 2, -1);
} }
/**
* @throws InvalidPacketException
* @throws SocketException
*/
public function testNotConnectedGetInfo(): void public function testNotConnectedGetInfo(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->GetInfo(); $this->SourceQuery->GetInfo();
} }
/**
* @throws InvalidPacketException
* @throws SocketException
*/
public function testNotConnectedPing(): void public function testNotConnectedPing(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->Ping(); $this->SourceQuery->Ping();
} }
/**
* @throws InvalidPacketException
* @throws SocketException
*/
public function testNotConnectedGetPlayers(): void public function testNotConnectedGetPlayers(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->GetPlayers(); $this->SourceQuery->GetPlayers();
} }
/** /**
* @expectedException xPaw\SourceQuery\Exception\SocketException * @throws InvalidPacketException
* @throws SocketException
*/ */
public function testNotConnectedGetRules(): void public function testNotConnectedGetRules(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->GetRules(); $this->SourceQuery->GetRules();
} }
/**
* @throws SocketException
* @throws AuthenticationException
* @throws InvalidPacketException
*/
public function testNotConnectedSetRconPassword(): void public function testNotConnectedSetRconPassword(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->SetRconPassword('a'); $this->SourceQuery->SetRconPassword('a');
} }
/**
* @throws AuthenticationException
* @throws InvalidPacketException
* @throws SocketException
*/
public function testNotConnectedRcon(): void public function testNotConnectedRcon(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Disconnect(); $this->SourceQuery->Disconnect();
$this->SourceQuery->Rcon('a'); $this->SourceQuery->Rcon('a');
} }
/**
* @throws AuthenticationException
* @throws InvalidPacketException
* @throws SocketException
*/
public function testRconWithoutPassword(): void public function testRconWithoutPassword(): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\SocketException::class); $this->expectException(SocketException::class);
$this->SourceQuery->Rcon('a'); $this->SourceQuery->Rcon('a');
} }
/** /**
* @param string $RawInput
* @param array $ExpectedOutput
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider InfoProvider * @dataProvider InfoProvider
*/ */
public function testGetInfo(string $RawInput, array $ExpectedOutput): void public function testGetInfo(string $RawInput, array $ExpectedOutput): void
@ -156,6 +249,11 @@ final class Tests extends TestCase
self::assertEquals($ExpectedOutput, $RealOutput); self::assertEquals($ExpectedOutput, $RealOutput);
} }
/**
* @return array
*
* @throws JsonException
*/
public function InfoProvider(): array public function InfoProvider(): array
{ {
$DataProvider = []; $DataProvider = [];
@ -166,7 +264,14 @@ final class Tests extends TestCase
$DataProvider[] = $DataProvider[] =
[ [
hex2bin(trim(file_get_contents($File))), hex2bin(trim(file_get_contents($File))),
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true) json_decode(
file_get_contents(
str_replace('.raw', '.json', $File)
),
true,
512,
JSON_THROW_ON_ERROR
)
]; ];
} }
@ -174,33 +279,48 @@ final class Tests extends TestCase
} }
/** /**
* @param string $Data
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider BadPacketProvider * @dataProvider BadPacketProvider
*/ */
public function testBadGetInfo(string $Data): void public function testBadGetInfo(string $Data): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class); $this->expectException(InvalidPacketException::class);
$this->Socket->Queue($Data); $this->Socket->Queue($Data);
$this->SourceQuery->GetInfo(); $this->SourceQuery->GetInfo();
} }
/** /**
* @param string $Data
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider BadPacketProvider * @dataProvider BadPacketProvider
*/ */
public function testBadGetChallengeViaPlayers(string $Data): void public function testBadGetChallengeViaPlayers(string $Data): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class); $this->expectException(InvalidPacketException::class);
$this->Socket->Queue($Data); $this->Socket->Queue($Data);
$this->SourceQuery->GetPlayers(); $this->SourceQuery->GetPlayers();
} }
/** /**
* @param string $Data
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider BadPacketProvider * @dataProvider BadPacketProvider
*/ */
public function testBadGetPlayersAfterCorrectChallenge(string $Data): void public function testBadGetPlayersAfterCorrectChallenge(string $Data): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class); $this->expectException(InvalidPacketException::class);
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
$this->Socket->Queue($Data); $this->Socket->Queue($Data);
@ -208,17 +328,25 @@ final class Tests extends TestCase
} }
/** /**
* @param string $Data
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider BadPacketProvider * @dataProvider BadPacketProvider
*/ */
public function testBadGetRulesAfterCorrectChallenge(string $Data): void public function testBadGetRulesAfterCorrectChallenge(string $Data): void
{ {
$this->expectException(xPaw\SourceQuery\Exception\InvalidPacketException::class); $this->expectException(InvalidPacketException::class);
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
$this->Socket->Queue($Data); $this->Socket->Queue($Data);
$this->SourceQuery->GetRules(); $this->SourceQuery->GetRules();
} }
/**
* @return string[][]
*/
public function BadPacketProvider(): array public function BadPacketProvider(): array
{ {
return return
@ -233,6 +361,10 @@ final class Tests extends TestCase
]; ];
} }
/**
* @throws InvalidPacketException
* @throws SocketException
*/
public function testGetChallengeTwice(): void public function testGetChallengeTwice(): void
{ {
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $this->Socket->Queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11");
@ -244,8 +376,13 @@ final class Tests extends TestCase
} }
/** /**
* @param array $RawInput
* @param array $ExpectedOutput
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider RulesProvider * @dataProvider RulesProvider
* @param array<string> $RawInput
*/ */
public function testGetRules(array $RawInput, array $ExpectedOutput): void public function testGetRules(array $RawInput, array $ExpectedOutput): void
{ {
@ -260,6 +397,11 @@ final class Tests extends TestCase
self::assertEquals($ExpectedOutput, $RealOutput); self::assertEquals($ExpectedOutput, $RealOutput);
} }
/**
* @return array
*
* @throws JsonException
*/
public function RulesProvider(): array public function RulesProvider(): array
{ {
$DataProvider = []; $DataProvider = [];
@ -270,7 +412,14 @@ final class Tests extends TestCase
$DataProvider[] = $DataProvider[] =
[ [
file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES), file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES),
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true) json_decode(
file_get_contents(
str_replace('.raw', '.json', $File)
),
true,
512,
JSON_THROW_ON_ERROR
)
]; ];
} }
@ -278,8 +427,13 @@ final class Tests extends TestCase
} }
/** /**
* @param string[] $RawInput
* @param array $ExpectedOutput
*
* @throws InvalidPacketException
* @throws SocketException
*
* @dataProvider PlayersProvider * @dataProvider PlayersProvider
* @param array<string> $RawInput
*/ */
public function testGetPlayers(array $RawInput, array $ExpectedOutput): void public function testGetPlayers(array $RawInput, array $ExpectedOutput): void
{ {
@ -294,6 +448,11 @@ final class Tests extends TestCase
self::assertEquals($ExpectedOutput, $RealOutput); self::assertEquals($ExpectedOutput, $RealOutput);
} }
/**
* @return array
*
* @throws JsonException
*/
public function PlayersProvider(): array public function PlayersProvider(): array
{ {
$DataProvider = []; $DataProvider = [];
@ -304,13 +463,24 @@ final class Tests extends TestCase
$DataProvider[] = $DataProvider[] =
[ [
file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES), file($File, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES),
json_decode(file_get_contents(str_replace('.raw', '.json', $File)), true) json_decode(
file_get_contents(
str_replace('.raw', '.json', $File)
),
true,
512,
JSON_THROW_ON_ERROR
)
]; ];
} }
return $DataProvider; return $DataProvider;
} }
/**
* @throws InvalidPacketException
* @throws SocketException
*/
public function testPing(): void public function testPing(): void
{ {
$this->Socket->Queue("\xFF\xFF\xFF\xFF\x6A\x00"); $this->Socket->Queue("\xFF\xFF\xFF\xFF\x6A\x00");

@ -18,7 +18,10 @@
], ],
"require": "require":
{ {
"php": ">=7.4" "php": ">=7.4",
"ext-bz2": ">7.*",
"ext-gmp": ">7.*",
"ext-json": ">7.*"
}, },
"require-dev": "require-dev":
{ {

@ -1,7 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<psalm <psalm
errorLevel="1" errorLevel="1"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"

Loading…
Cancel
Save