From 184ec6ff5a7f9fa998420b87ac428686789360a2 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sun, 24 Mar 2024 10:52:29 +0000 Subject: [PATCH] feat(default): introduce `Default` component Signed-off-by: azjezz --- docs/component/collection.md | 2 +- docs/component/comparison.md | 2 +- docs/component/data-structure.md | 2 +- docs/component/encoding-base64.md | 2 +- docs/component/html.md | 2 +- docs/component/network.md | 2 +- docs/component/os.md | 2 +- docs/component/password.md | 2 +- docs/component/random-sequence.md | 2 +- docs/component/shell.md | 2 +- docs/component/str.md | 2 +- docs/component/tcp.md | 4 +- examples/tcp/basic-http-server.php | 2 +- src/Psl/Collection/CollectionInterface.php | 3 +- src/Psl/Collection/Map.php | 15 +++- src/Psl/Collection/MutableMap.php | 12 +++ src/Psl/Collection/MutableVector.php | 14 +++ src/Psl/Collection/Vector.php | 16 +++- src/Psl/Comparison/Order.php | 34 ++++++- src/Psl/DataStructure/PriorityQueue.php | 22 +++++ src/Psl/DataStructure/Queue.php | 22 +++++ src/Psl/DataStructure/QueueInterface.php | 3 +- src/Psl/DataStructure/Stack.php | 22 +++++ src/Psl/Default/DefaultInterface.php | 37 ++++++++ src/Psl/Encoding/Base64/Variant.php | 44 +++++++-- src/Psl/Html/Encoding.php | 90 ++++++++++++------- src/Psl/Network/SocketOptions.php | 73 +++++++++++++-- src/Psl/OS/OperatingSystemFamily.php | 51 ++++++++++- src/Psl/Password/Algorithm.php | 51 +++++++++-- .../Internal/MersenneTwisterTrait.php | 2 +- src/Psl/RandomSequence/SecureSequence.php | 15 +++- src/Psl/Shell/ErrorOutputBehavior.php | 31 ++++++- src/Psl/Str/Encoding.php | 27 +++++- src/Psl/TCP/ConnectOptions.php | 58 +++++++++++- src/Psl/TCP/ServerOptions.php | 80 ++++++++++++++--- tests/unit/Collection/AbstractMapTest.php | 7 ++ tests/unit/Collection/AbstractVectorTest.php | 7 ++ .../Comparison/AbstractComparisonTest.php | 6 ++ .../unit/DataStructure/PriorityQueueTest.php | 12 +-- tests/unit/DataStructure/QueueTest.php | 6 +- tests/unit/DataStructure/StackTest.php | 6 +- tests/unit/Encoding/Base64Test.php | 8 +- tests/unit/OS/FamilyTest.php | 4 + tests/unit/Password/PasswordTest.php | 12 +++ .../RandomSequence/SecureSequenceTest.php | 2 +- tests/unit/Shell/ExecuteTest.php | 4 + tests/unit/TCP/ConnectOptionsTest.php | 2 +- tests/unit/TCP/ServerOptionsTest.php | 41 ++++++++- 48 files changed, 758 insertions(+), 109 deletions(-) create mode 100644 src/Psl/Default/DefaultInterface.php diff --git a/docs/component/collection.md b/docs/component/collection.md index 8987435e..05b4bd5d 100644 --- a/docs/component/collection.md +++ b/docs/component/collection.md @@ -13,7 +13,7 @@ #### `Interfaces` - [AccessibleCollectionInterface](./../../src/Psl/Collection/AccessibleCollectionInterface.php#L20) -- [CollectionInterface](./../../src/Psl/Collection/CollectionInterface.php#L22) +- [CollectionInterface](./../../src/Psl/Collection/CollectionInterface.php#L23) - [IndexAccessInterface](./../../src/Psl/Collection/IndexAccessInterface.php#L13) - [MapInterface](./../../src/Psl/Collection/MapInterface.php#L15) - [MutableAccessibleCollectionInterface](./../../src/Psl/Collection/MutableAccessibleCollectionInterface.php#L22) diff --git a/docs/component/comparison.md b/docs/component/comparison.md index 8820f0ea..3a81d981 100644 --- a/docs/component/comparison.md +++ b/docs/component/comparison.md @@ -28,6 +28,6 @@ #### `Enums` -- [Order](./../../src/Psl/Comparison/Order.php#L7) +- [Order](./../../src/Psl/Comparison/Order.php#L23) diff --git a/docs/component/data-structure.md b/docs/component/data-structure.md index c96849d7..7f702b9f 100644 --- a/docs/component/data-structure.md +++ b/docs/component/data-structure.md @@ -13,7 +13,7 @@ #### `Interfaces` - [PriorityQueueInterface](./../../src/Psl/DataStructure/PriorityQueueInterface.php#L12) -- [QueueInterface](./../../src/Psl/DataStructure/QueueInterface.php#L16) +- [QueueInterface](./../../src/Psl/DataStructure/QueueInterface.php#L17) - [StackInterface](./../../src/Psl/DataStructure/StackInterface.php#L16) #### `Classes` diff --git a/docs/component/encoding-base64.md b/docs/component/encoding-base64.md index 63fea577..231dc3d6 100644 --- a/docs/component/encoding-base64.md +++ b/docs/component/encoding-base64.md @@ -17,6 +17,6 @@ #### `Enums` -- [Variant](./../../src/Psl/Encoding/Base64/Variant.php#L7) +- [Variant](./../../src/Psl/Encoding/Base64/Variant.php#L12) diff --git a/docs/component/html.md b/docs/component/html.md index 426b48ee..e3c7785e 100644 --- a/docs/component/html.md +++ b/docs/component/html.md @@ -20,6 +20,6 @@ #### `Enums` -- [Encoding](./../../src/Psl/Html/Encoding.php#L7) +- [Encoding](./../../src/Psl/Html/Encoding.php#L20) diff --git a/docs/component/network.md b/docs/component/network.md index 093b11ff..c6dbeaee 100644 --- a/docs/component/network.md +++ b/docs/component/network.md @@ -20,7 +20,7 @@ #### `Classes` - [Address](./../../src/Psl/Network/Address.php#L7) -- [SocketOptions](./../../src/Psl/Network/SocketOptions.php#L7) +- [SocketOptions](./../../src/Psl/Network/SocketOptions.php#L14) #### `Enums` diff --git a/docs/component/os.md b/docs/component/os.md index 920e5450..8a53feb8 100644 --- a/docs/component/os.md +++ b/docs/component/os.md @@ -18,6 +18,6 @@ #### `Enums` -- [OperatingSystemFamily](./../../src/Psl/OS/OperatingSystemFamily.php#L7) +- [OperatingSystemFamily](./../../src/Psl/OS/OperatingSystemFamily.php#L16) diff --git a/docs/component/password.md b/docs/component/password.md index bf4bf7da..bcc6c77e 100644 --- a/docs/component/password.md +++ b/docs/component/password.md @@ -19,6 +19,6 @@ #### `Enums` -- [Algorithm](./../../src/Psl/Password/Algorithm.php#L11) +- [Algorithm](./../../src/Psl/Password/Algorithm.php#L23) diff --git a/docs/component/random-sequence.md b/docs/component/random-sequence.md index 440a1df7..b2702ead 100644 --- a/docs/component/random-sequence.md +++ b/docs/component/random-sequence.md @@ -18,6 +18,6 @@ - [MersenneTwisterPHPVariantSequence](./../../src/Psl/RandomSequence/MersenneTwisterPHPVariantSequence.php#L10) - [MersenneTwisterSequence](./../../src/Psl/RandomSequence/MersenneTwisterSequence.php#L10) -- [SecureSequence](./../../src/Psl/RandomSequence/SecureSequence.php#L12) +- [SecureSequence](./../../src/Psl/RandomSequence/SecureSequence.php#L15) diff --git a/docs/component/shell.md b/docs/component/shell.md index 52d91a93..364fdd49 100644 --- a/docs/component/shell.md +++ b/docs/component/shell.md @@ -18,6 +18,6 @@ #### `Enums` -- [ErrorOutputBehavior](./../../src/Psl/Shell/ErrorOutputBehavior.php#L7) +- [ErrorOutputBehavior](./../../src/Psl/Shell/ErrorOutputBehavior.php#L17) diff --git a/docs/component/str.md b/docs/component/str.md index e35583bb..be2c43fe 100644 --- a/docs/component/str.md +++ b/docs/component/str.md @@ -79,6 +79,6 @@ #### `Enums` -- [Encoding](./../../src/Psl/Str/Encoding.php#L7) +- [Encoding](./../../src/Psl/Str/Encoding.php#L16) diff --git a/docs/component/tcp.md b/docs/component/tcp.md index 79cc007f..8c208bab 100644 --- a/docs/component/tcp.md +++ b/docs/component/tcp.md @@ -16,8 +16,8 @@ #### `Classes` -- [ConnectOptions](./../../src/Psl/TCP/ConnectOptions.php#L7) +- [ConnectOptions](./../../src/Psl/TCP/ConnectOptions.php#L14) - [Server](./../../src/Psl/TCP/Server.php#L11) -- [ServerOptions](./../../src/Psl/TCP/ServerOptions.php#L9) +- [ServerOptions](./../../src/Psl/TCP/ServerOptions.php#L15) diff --git a/examples/tcp/basic-http-server.php b/examples/tcp/basic-http-server.php index ea81a013..95bdeaa1 100644 --- a/examples/tcp/basic-http-server.php +++ b/examples/tcp/basic-http-server.php @@ -27,7 +27,7 @@ HTML; -$server = TCP\Server::create('localhost', 3030, TCP\ServerOptions::create(idleConnections: 1024)); +$server = TCP\Server::create('localhost', 3030, TCP\ServerOptions::create(idle_connections: 1024)); Async\Scheduler::onSignal(SIGINT, $server->close(...)); diff --git a/src/Psl/Collection/CollectionInterface.php b/src/Psl/Collection/CollectionInterface.php index 69995346..a79fb165 100644 --- a/src/Psl/Collection/CollectionInterface.php +++ b/src/Psl/Collection/CollectionInterface.php @@ -8,6 +8,7 @@ use Countable; use IteratorAggregate; use JsonSerializable; +use Psl\Default\DefaultInterface; /** * The base interface implemented for a CollectionInterface type. @@ -19,7 +20,7 @@ * * @extends IteratorAggregate */ -interface CollectionInterface extends Countable, IteratorAggregate, JsonSerializable +interface CollectionInterface extends Countable, DefaultInterface, IteratorAggregate, JsonSerializable { /** * Is the CollectionInterface empty? diff --git a/src/Psl/Collection/Map.php b/src/Psl/Collection/Map.php index 0cd49611..aee6b319 100644 --- a/src/Psl/Collection/Map.php +++ b/src/Psl/Collection/Map.php @@ -26,12 +26,26 @@ final class Map implements MapInterface { /** * @param array $elements + * + * @pure */ public function __construct( private readonly array $elements ) { } + /** + * Creates and returns a default instance of {@see Map}. + * + * @return static A default instance of {@see Map}. + * + * @pure + */ + public static function default(): static + { + return new self([]); + } + /** * @template Tsk of array-key * @template Tsv @@ -44,7 +58,6 @@ public function __construct( */ public static function fromArray(array $elements): Map { - /** @psalm-suppress ImpureMethodCall - conditionally pure */ return new self($elements); } diff --git a/src/Psl/Collection/MutableMap.php b/src/Psl/Collection/MutableMap.php index 3c67de07..10faa92d 100644 --- a/src/Psl/Collection/MutableMap.php +++ b/src/Psl/Collection/MutableMap.php @@ -34,6 +34,18 @@ public function __construct( ) { } + /** + * Creates and returns a default instance of {@see MutableMap}. + * + * @return static A default instance of {@see MutableMap}. + * + * @pure + */ + public static function default(): static + { + return new self([]); + } + /** * @template Tsk of array-key * @template Tsv diff --git a/src/Psl/Collection/MutableVector.php b/src/Psl/Collection/MutableVector.php index 87e67291..d5e59c78 100644 --- a/src/Psl/Collection/MutableVector.php +++ b/src/Psl/Collection/MutableVector.php @@ -31,6 +31,8 @@ final class MutableVector implements MutableVectorInterface * MutableVector constructor. * * @param array $elements + * + * @external-mutation-free */ public function __construct(array $elements) { @@ -39,6 +41,18 @@ public function __construct(array $elements) } } + /** + * Creates and returns a default instance of {@see MutableVector}. + * + * @return static A default instance of {@see MutableVector}. + * + * @external-mutation-free + */ + public static function default(): static + { + return new self([]); + } + /** * Create a vector from the given $elements array. * diff --git a/src/Psl/Collection/Vector.php b/src/Psl/Collection/Vector.php index a436e87f..527adadd 100644 --- a/src/Psl/Collection/Vector.php +++ b/src/Psl/Collection/Vector.php @@ -28,6 +28,8 @@ final class Vector implements VectorInterface /** * @param array $elements + * + * @external-mutation-free */ public function __construct(array $elements) { @@ -39,6 +41,18 @@ public function __construct(array $elements) $this->elements = $list; } + /** + * Creates and returns a default instance of {@see Vector}. + * + * @return static A default instance of {@see Vector}. + * + * @external-mutation-free + */ + public static function default(): static + { + return new self([]); + } + /** * Create a vector from the given $elements array. * @@ -517,7 +531,7 @@ public function chunk(int $size): Vector * * @return Vector */ - static fn(array $chunk) => Vector::fromArray($chunk) + static fn(array $chunk) => static::fromArray($chunk) )); } } diff --git a/src/Psl/Comparison/Order.php b/src/Psl/Comparison/Order.php index 0ce86c5a..754cffa9 100644 --- a/src/Psl/Comparison/Order.php +++ b/src/Psl/Comparison/Order.php @@ -4,9 +4,41 @@ namespace Psl\Comparison; -enum Order : int +use Psl\Default\DefaultInterface; + +/** + * Enum the possible outcomes of a comparison operation. + * + * This enum provides a standardized way to represent the result of a comparison, + * making it easier to understand and use comparison outcomes in a type-safe manner. + * Implementing the DefaultInterface, it also provides a sensible default value. + * + * - `Less` indicates that the first value is less than the second. + * - `Equal` suggests that the two values are equal. + * - `Greater` means that the first value is greater than the second. + * + * Usage of this enum can help to avoid "magic numbers" in comparison logic and make + * code more readable and maintainable. + */ +enum Order: int implements DefaultInterface { case Less = -1; case Equal = 0; case Greater = 1; + + /** + * Provides the default comparison outcome. + * + * This method returns the `Equal` case as the default state, indicating no difference + * between the compared values. It's useful in contexts where a neutral or "no change" + * state is needed as the starting point. + * + * @return static The default instance of the enum, which is `Order::Equal`. + * + * @pure + */ + public static function default(): static + { + return self::Equal; + } } diff --git a/src/Psl/DataStructure/PriorityQueue.php b/src/Psl/DataStructure/PriorityQueue.php index 1ab8993d..1b726af1 100644 --- a/src/Psl/DataStructure/PriorityQueue.php +++ b/src/Psl/DataStructure/PriorityQueue.php @@ -22,10 +22,24 @@ final class PriorityQueue implements PriorityQueueInterface */ private array $queue = []; + /** + * Provides a default instance of the {@see PriorityQueue}. + * + * @return static A new instance of {@see PriorityQueue}, devoid of any nodes. + * + * @pure + */ + public static function default(): static + { + return new self(); + } + /** * Adds a node to the queue. * * @param T $node + * + * @external-mutation-free */ public function enqueue(mixed $node, int $priority = 0): void { @@ -40,6 +54,8 @@ public function enqueue(mixed $node, int $priority = 0): void * or returns null if this queue is empty. * * @return null|T + * + * @mutation-free */ public function peek(): mixed { @@ -64,6 +80,8 @@ public function peek(): mixed * or returns null if this queue is empty. * * @return null|T + * + * @external-mutation-free */ public function pull(): mixed { @@ -80,6 +98,8 @@ public function pull(): mixed * @throws Exception\UnderflowException If the queue is empty. * * @return T + * + * @external-mutation-free */ public function dequeue(): mixed { @@ -117,6 +137,8 @@ public function dequeue(): mixed * Count the nodes in the queue. * * @return int<0, max> + * + * @mutation-free */ public function count(): int { diff --git a/src/Psl/DataStructure/Queue.php b/src/Psl/DataStructure/Queue.php index 01ee6839..34d00d7a 100644 --- a/src/Psl/DataStructure/Queue.php +++ b/src/Psl/DataStructure/Queue.php @@ -21,10 +21,24 @@ final class Queue implements QueueInterface */ private array $queue = []; + /** + * Provides a default instance of the {@see Queue}. + * + * @return static A new instance of {@see Queue}, devoid of any nodes. + * + * @pure + */ + public static function default(): static + { + return new self(); + } + /** * Adds a node to the queue. * * @param T $node + * + * @external-mutation-free */ public function enqueue(mixed $node): void { @@ -36,6 +50,8 @@ public function enqueue(mixed $node): void * or returns null if this queue is empty. * * @return null|T + * + * @mutation-free */ public function peek(): mixed { @@ -47,6 +63,8 @@ public function peek(): mixed * or returns null if this queue is empty. * * @return null|T + * + * @external-mutation-free */ public function pull(): mixed { @@ -59,6 +77,8 @@ public function pull(): mixed * @throws Exception\UnderflowException If the queue is empty. * * @return T + * + * @external-mutation-free */ public function dequeue(): mixed { @@ -74,6 +94,8 @@ public function dequeue(): mixed * Count the nodes in the queue. * * @return int<0, max> + * + * @mutation-free */ public function count(): int { diff --git a/src/Psl/DataStructure/QueueInterface.php b/src/Psl/DataStructure/QueueInterface.php index 3ba790c0..d7ed38fb 100644 --- a/src/Psl/DataStructure/QueueInterface.php +++ b/src/Psl/DataStructure/QueueInterface.php @@ -5,6 +5,7 @@ namespace Psl\DataStructure; use Countable; +use Psl\Default\DefaultInterface; /** * An interface representing a queue data structure ( FIFO ). @@ -13,7 +14,7 @@ * * @see https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics) */ -interface QueueInterface extends Countable +interface QueueInterface extends Countable, DefaultInterface { /** * Adds a node to the queue. diff --git a/src/Psl/DataStructure/Stack.php b/src/Psl/DataStructure/Stack.php index ca15e9fc..e2204cb0 100644 --- a/src/Psl/DataStructure/Stack.php +++ b/src/Psl/DataStructure/Stack.php @@ -21,10 +21,24 @@ final class Stack implements StackInterface */ private array $items = []; + /** + * Provides a default instance of the {@see Stack}. + * + * @return static A new instance of {@see Stack}, devoid of any items. + * + * @pure + */ + public static function default(): static + { + return new self(); + } + /** * Adds an item to the stack. * * @param T $item + * + * @external-mutation-free */ public function push(mixed $item): void { @@ -36,6 +50,8 @@ public function push(mixed $item): void * or returns null if this queue is empty. * * @return null|T + * + * @mutation-free */ public function peek(): mixed { @@ -49,6 +65,8 @@ public function peek(): mixed * or returns null if this queue is empty. * * @return null|T + * + * @external-mutation-free */ public function pull(): mixed { @@ -61,6 +79,8 @@ public function pull(): mixed * @throws Exception\UnderflowException If the stack is empty. * * @return T + * + * @external-mutation-free */ public function pop(): mixed { @@ -76,6 +96,8 @@ public function pop(): mixed * Count the items in the stack. * * @return int<0, max> + * + * @mutation-free */ public function count(): int { diff --git a/src/Psl/Default/DefaultInterface.php b/src/Psl/Default/DefaultInterface.php new file mode 100644 index 00000000..9a52c6c7 --- /dev/null +++ b/src/Psl/Default/DefaultInterface.php @@ -0,0 +1,37 @@ +portReuse, $this->broadcast); } + /** + * Returns a new instance with the port reuse option modified. + * + * @param bool $enabled The desired state for the SO_REUSEPORT option. + * + * @mutation-free + */ public function withPortReuse(bool $enabled = true): SocketOptions { return new self($this->addressReuse, $enabled, $this->broadcast); } + /** + * Returns a new instance with the broadcast option modified. + * + * @param bool $enabled The desired state for the SO_BROADCAST option. + * + * @mutation-free + */ public function withBroadcast(bool $enabled = true): SocketOptions { return new self($this->addressReuse, $this->portReuse, $enabled); diff --git a/src/Psl/OS/OperatingSystemFamily.php b/src/Psl/OS/OperatingSystemFamily.php index 11466bab..b65a6d9f 100644 --- a/src/Psl/OS/OperatingSystemFamily.php +++ b/src/Psl/OS/OperatingSystemFamily.php @@ -4,12 +4,61 @@ namespace Psl\OS; -enum OperatingSystemFamily: string +use Psl\Default\DefaultInterface; + +/** + * Enumerates the family of operating systems recognized by the platform. + * + * This enumeration classifies different operating systems into a set of well-known families, + * facilitating OS-specific behavior or optimizations in a type-safe manner. The classification + * helps in abstracting OS checks and performing operations that depend on the underlying OS family. + */ +enum OperatingSystemFamily: string implements DefaultInterface { + /** + * Represents the Windows family of operating systems. + */ case Windows = 'Windows'; + + /** + * Represents the various BSD flavors, including FreeBSD, OpenBSD, and NetBSD. + */ case BSD = 'BSD'; + + /** + * Represents the Darwin system, the core of macOS and iOS. + */ case Darwin = 'Darwin'; + + /** + * Represents the Solaris family of operating systems, including Oracle Solaris. + */ case Solaris = 'Solaris'; + + /** + * Represents Linux-based operating systems, covering a wide range of Linux distributions. + */ case Linux = 'Linux'; + + /** + * Represents an unknown or unrecognized operating system family. + * This case is used when the OS does not match any of the known families. + */ case Unknown = 'Unknown'; + + /** + * Provides the default operating system family based on the current environment. + * + * This method leverages the {@see family()} function to dynamically determine and + * return the operating system family of the environment in which the PHP script is executed. + * It allows for adaptive behavior in applications, depending on the OS family at runtime. + * + * @return static The operating system family that matches the current environment. + * + * @pure + */ + public static function default(): static + { + return namespace\family(); + } } diff --git a/src/Psl/Password/Algorithm.php b/src/Psl/Password/Algorithm.php index eb680ee3..f1c6d5e4 100644 --- a/src/Psl/Password/Algorithm.php +++ b/src/Psl/Password/Algorithm.php @@ -4,26 +4,40 @@ namespace Psl\Password; +use Psl\Default\DefaultInterface; + use const PASSWORD_ARGON2I; use const PASSWORD_ARGON2ID; use const PASSWORD_BCRYPT; +use const PASSWORD_DEFAULT; -enum Algorithm: string +/** + * Enumerates supported hashing algorithms for passwords. + * + * This enum provides a type-safe way to specify the algorithm to be used for hashing passwords. + * + * It includes support for widely used algorithms like Bcrypt, Argon2i, and Argon2id, + * and allows for the default algorithm to be used, which is subject to change with + * future PHP versions to ensure the use of strong, up-to-date cryptographic standards. + */ +enum Algorithm: string implements DefaultInterface { /** * The default algorithm to use for hashing if no algorithm is provided. + * * This may change in newer PHP releases when newer, stronger hashing algorithms are supported. * - * It is worth noting that over time this constant can (and likely will) change. + * It is worth noting that over time the algorithm behind this case can (and likely will) change. + * * Therefore you should be aware that the length of the resulting hash can change. * - * Therefore, if you use `Psl\Password\DEFAULT_ALGORITHM` you should store + * Therefore, if you use `Psl\Password\Algorithm::Default` you should store * the resulting hash in a way that can store more than 60 characters (255 is the recommended width). */ case Default = 'default'; /** - * The `BCRYPT_ALGORITHM` is used to create new password hashes + * The `Algorithm::Bcrypt` is used to create new password hashes * using the blowfish algorithm. * * This will result in a hash using the `"$2y$"` crypt format @@ -35,7 +49,7 @@ enum Algorithm: string case Bcrypt = 'bcrypt'; /** - * The `Argon2i` is used to create new password hashes using the argon2i algorithm. + * The `Algorithm::Argon2i` is used to create new password hashes using the argon2i algorithm. * * Supported options: * - `memory_cost` ( integer ): Maximum memory (in bytes) that may be used to compute the Argon2 hash. @@ -45,7 +59,7 @@ enum Algorithm: string case Argon2i = 'argon2i'; /** - * The `Argon2id` is used to create new password hashes using the argon2id algorithm. + * The `Algorithm::Argon2id` is used to create new password hashes using the argon2id algorithm. * * Supported options: * - `memory_cost` ( integer ): Maximum memory (in bytes) that may be used to compute the Argon2 hash. @@ -55,14 +69,37 @@ enum Algorithm: string case Argon2id = 'argon2id'; /** + * Retrieves the PHP built-in constant value associated with each algorithm. + * + * This method maps the enum cases to their corresponding PHP built-in constant + * values used by the password hashing API. It enables seamless integration between + * the type-safe enum approach and PHP's underlying password hashing mechanism. + * * @mutation-free */ public function getBuiltinConstantValue(): string { return match ($this) { - static::Default, static::Bcrypt => PASSWORD_BCRYPT, + static::Default => PASSWORD_DEFAULT, + static::Bcrypt => PASSWORD_BCRYPT, static::Argon2i => PASSWORD_ARGON2I, static::Argon2id => PASSWORD_ARGON2ID, }; } + + /** + * Provides the default algorithm to use for hashing if no algorithm is provided. + * + * It is recommended to store the resulting hash in a way that can accommodate more than 60 characters, + * as the default algorithm may change in newer PHP releases to incorporate stronger hashing algorithms, + * potentially leading to longer hash strings. + * + * @return static The default algorithm instance, subject to change in future implementations. + * + * @pure + */ + public static function default(): static + { + return self::Default; + } } diff --git a/src/Psl/RandomSequence/Internal/MersenneTwisterTrait.php b/src/Psl/RandomSequence/Internal/MersenneTwisterTrait.php index f0c5d41a..78f3745c 100644 --- a/src/Psl/RandomSequence/Internal/MersenneTwisterTrait.php +++ b/src/Psl/RandomSequence/Internal/MersenneTwisterTrait.php @@ -40,7 +40,7 @@ final public function __construct( /** * Generates the next pseudorandom number. * - * @psalm-external-mutation-free + * @external-mutation-free */ final public function next(): int { diff --git a/src/Psl/RandomSequence/SecureSequence.php b/src/Psl/RandomSequence/SecureSequence.php index b121a7ff..cf07ceaf 100644 --- a/src/Psl/RandomSequence/SecureSequence.php +++ b/src/Psl/RandomSequence/SecureSequence.php @@ -4,15 +4,28 @@ namespace Psl\RandomSequence; +use Psl\Default\DefaultInterface; use Psl\SecureRandom; /** * A Cryptographically Secure PRNG. + * + * @immutable */ -final class SecureSequence implements SequenceInterface +final class SecureSequence implements DefaultInterface, SequenceInterface { + /** + * @pure + */ + public static function default(): static + { + return new self(); + } + /** * Generates the next pseudorandom number. + * + * @external-mutation-free */ public function next(): int { diff --git a/src/Psl/Shell/ErrorOutputBehavior.php b/src/Psl/Shell/ErrorOutputBehavior.php index 4d69e0b0..de46d8b9 100644 --- a/src/Psl/Shell/ErrorOutputBehavior.php +++ b/src/Psl/Shell/ErrorOutputBehavior.php @@ -4,7 +4,18 @@ namespace Psl\Shell; -enum ErrorOutputBehavior { +use Psl\Default\DefaultInterface; + +/** + * Specifies the behavior for handling the standard error (stderr) output of shell commands. + * + * This enum is utilized to configure how stderr output should be treated in relation to the + * standard output (stdout) when executing shell commands via the Shell component. Each case + * offers a different strategy for managing or combining stderr and stdout, allowing for flexible + * error output handling based on specific requirements of the execution context. + */ +enum ErrorOutputBehavior implements DefaultInterface +{ /** * Discard the standard error output. * @@ -53,4 +64,22 @@ enum ErrorOutputBehavior { * @note The packing format is not guaranteed to be BC, you should always use `Shell\unpack` instead of attempting to unpack the result manually. */ case Packed; + + /** + * Provides the default error output behavior. + * + * The default behavior is to discard the standard error output. This choice simplifies + * handling of command outputs in scenarios where error details are not crucial, or + * errors are expected and non-critical. It offers a clean approach for focusing solely + * on the standard output content, especially in automated scripts or where output clarity + * is a priority. + * + * @return static The default `Discard` behavior instance, representing the preference to ignore stderr output. + * + * @pure + */ + public static function default(): static + { + return self::Discard; + } } diff --git a/src/Psl/Str/Encoding.php b/src/Psl/Str/Encoding.php index 64b16673..c0f27fd0 100644 --- a/src/Psl/Str/Encoding.php +++ b/src/Psl/Str/Encoding.php @@ -4,7 +4,16 @@ namespace Psl\Str; -enum Encoding: string +use Psl\Default\DefaultInterface; + +/** + * Enumerates supported character encodings for string operations. + * + * This enum defines a comprehensive list of character encodings supported for various string manipulation + * and processing tasks. It includes encodings from multiple languages and regions, ensuring wide-ranging + * internationalization support across different platforms and systems. + */ +enum Encoding: string implements DefaultInterface { case BASE64 = 'BASE64'; case UUENCODE = 'UUENCODE'; @@ -83,4 +92,20 @@ enum Encoding: string case CP50220 = 'CP50220'; case CP50221 = 'CP50221'; case CP50222 = 'CP50222'; + + /** + * Provides the default character encoding. + * + * UTF-8 is selected as the default encoding because of its ability to represent any character in the Unicode + * standard and its compatibility with ASCII. It's a practical choice for web and application development, + * offering flexibility for handling international text and ensuring data integrity across diverse systems. + * + * @return static The UTF-8 encoding instance, representing the default encoding choice for string operations. + * + * @pure + */ + public static function default(): static + { + return self::UTF_8; + } } diff --git a/src/Psl/TCP/ConnectOptions.php b/src/Psl/TCP/ConnectOptions.php index 9d528af2..98da8263 100644 --- a/src/Psl/TCP/ConnectOptions.php +++ b/src/Psl/TCP/ConnectOptions.php @@ -4,19 +4,69 @@ namespace Psl\TCP; -final class ConnectOptions +use Psl\Default\DefaultInterface; + +/** + * Represents the configuration options for TCP connections. + * + * @immutable + */ +final class ConnectOptions implements DefaultInterface { + /** + * Initializes a new instance of {@see ConnectOptions} with the specified settings. + * + * @param bool $noDelay Determines whether the TCP_NODELAY option is enabled, controlling + * the use of the Nagle algorithm. When true, TCP_NODELAY is enabled, + * and the Nagle algorithm is disabled. + * + * @pure + */ public function __construct( public readonly bool $noDelay, ) { } - public static function create( - bool $noDelay = false, - ): ConnectOptions { + /** + * Constructs a new ConnectOptions instance with specified noDelay setting. + * + * This static method provides a named constructor pattern, allowing for explicit + * configuration of the options at the time of instantiation. It offers an alternative + * to the default constructor for cases where named constructors improve readability + * and usage clarity. + * + * @param bool $noDelay Specifies whether the TCP_NODELAY option should be enabled. + * + * @pure + */ + public static function create(bool $noDelay = false): ConnectOptions + { return new self($noDelay); } + /** + * Creates and returns a default instance of {@see ConnectOptions}. + * + * The default instance has the TCP_NODELAY option disabled, allowing the Nagle algorithm + * to be used. This method is a convenience wrapper around the `create` method, adhering to + * the {@see DefaultInterface} contract. + * + * @return static A default ConnectOptions instance with noDelay set to false. + * + * @pure + */ + public static function default(): static + { + return self::create(); + } + + /** + * Returns a new instance of {@see ConnectOptions} with the noDelay setting modified. + * + * @param bool $enabled Specifies the desired state of the TCP_NODELAY option. + * + * @mutation-free + */ public function withNoDelay(bool $enabled = true): ConnectOptions { return new self($enabled); diff --git a/src/Psl/TCP/ServerOptions.php b/src/Psl/TCP/ServerOptions.php index 898252e0..df75efed 100644 --- a/src/Psl/TCP/ServerOptions.php +++ b/src/Psl/TCP/ServerOptions.php @@ -4,14 +4,31 @@ namespace Psl\TCP; +use Psl\Default\DefaultInterface; use Psl\Network; -final class ServerOptions +/** + * Configures options for a TCP server. + * + * @immutable + */ +final class ServerOptions implements DefaultInterface { + /** + * Default number of idle connections allowed. + */ public const DEFAULT_IDLE_CONNECTIONS = 256; /** - * @param int<1, max> $idleConnections + * Initializes a new instance of ServerOptions with specified settings. + * + * @param bool $noDelay Determines whether the TCP_NODELAY option is enabled, controlling + * the use of the Nagle algorithm. When true, TCP_NODELAY is enabled, + * and the Nagle algorithm is disabled. + * @param int<1, max> $idleConnections The maximum number of idle connections the server will keep open. + * @param Network\SocketOptions $socketOptions Socket configuration options. + * + * @pure */ public function __construct( public readonly bool $noDelay, @@ -21,29 +38,68 @@ public function __construct( } /** - * @param int<1, max> $idleConnections + * Creates a new {@see ServerOptions} instance with the specified settings. + * + * This method provides a convenient way to create a {@see ServerOptions} instance with custom settings + * or with defaults. + * + * @param bool $no_delay Specifies whether the TCP_NODELAY option should be enabled. + * @param int<1, max> $idle_connections Specifies the maximum number of idle connections to allow. + * @param ?Network\SocketOptions $socket_options Optional. Specifies custom socket options. If null, defaults are used. + * + * @pure */ public static function create( - bool $noDelay = false, - int $idleConnections = self::DEFAULT_IDLE_CONNECTIONS, - ?Network\SocketOptions $socketOptions = null, + bool $no_delay = false, + int $idle_connections = self::DEFAULT_IDLE_CONNECTIONS, + ?Network\SocketOptions $socket_options = null, ): ServerOptions { - return new self($noDelay, $idleConnections, $socketOptions ?? Network\SocketOptions::create()); + return new self($no_delay, $idle_connections, $socket_options ?? Network\SocketOptions::default()); } - public function withSocketOptions( - Network\SocketOptions $socketOptions - ): ServerOptions { - return new self($this->noDelay, $this->idleConnections, $socketOptions); + /** + * Provides a default {@see ServerOptions} instance. + * + * Returns a {@see ServerOptions} instance configured with default settings. This includes TCP_NODELAY disabled, + * the default number of idle connections, and default socket options. + * + * @pure + */ + public static function default(): static + { + return self::create(); } + /** + * Returns a new instance with updated socket options. + * + * @param Network\SocketOptions $socket_options New socket configuration options. + * + * @mutation-free + */ + public function withSocketOptions(Network\SocketOptions $socket_options): ServerOptions + { + return new self($this->noDelay, $this->idleConnections, $socket_options); + } + + /** + * Returns a new instance with the noDelay option modified. + * + * @param bool $enabled The desired state for the TCP_NODELAY option. + * + * @mutation-free + */ public function withNoDelay(bool $enabled = true): ServerOptions { return new self($enabled, $this->idleConnections, $this->socketOptions); } /** - * @param int<1, max> $idleConnections + * Returns a new instance with the idleConnections option modified. + * + * @param int<1, max> $idleConnections The new maximum number of idle connections to allow. + * + * @mutation-free */ public function withIdleConnections(int $idleConnections): ServerOptions { diff --git a/tests/unit/Collection/AbstractMapTest.php b/tests/unit/Collection/AbstractMapTest.php index c08f9cce..de3aef1b 100644 --- a/tests/unit/Collection/AbstractMapTest.php +++ b/tests/unit/Collection/AbstractMapTest.php @@ -28,6 +28,7 @@ abstract class AbstractMapTest extends TestCase public function testIsEmpty(): void { + static::assertTrue($this->default()->isEmpty()); static::assertTrue($this->create([])->isEmpty()); static::assertFalse($this->create(['foo' => 'bar'])->isEmpty()); static::assertEmpty($this->create(['foo' => null])->isEmpty()); @@ -35,6 +36,7 @@ public function testIsEmpty(): void public function testCount(): void { + static::assertCount(0, $this->default()); static::assertCount(0, $this->create([])); static::assertCount(1, $this->create(['foo' => 'bar'])); static::assertSame(5, $this->create([ @@ -591,6 +593,11 @@ public function testChunk(): void static::assertSame(['baz' => '!'], $chunks->at(2)->toArray()); } + protected function default(): MapInterface + { + return ($this->mapClass)::default(); + } + /** * @template Tk of array-key * @template Tv diff --git a/tests/unit/Collection/AbstractVectorTest.php b/tests/unit/Collection/AbstractVectorTest.php index ad60016a..1082ce7b 100644 --- a/tests/unit/Collection/AbstractVectorTest.php +++ b/tests/unit/Collection/AbstractVectorTest.php @@ -20,6 +20,7 @@ abstract class AbstractVectorTest extends TestCase public function testIsEmpty(): void { + static::assertTrue($this->default()->isEmpty()); static::assertTrue($this->create([])->isEmpty()); static::assertFalse($this->create(['foo', 'bar'])->isEmpty()); static::assertEmpty($this->create([null])->isEmpty()); @@ -27,6 +28,7 @@ public function testIsEmpty(): void public function testCount(): void { + static::assertCount(0, $this->default()); static::assertCount(0, $this->create([])); static::assertCount(2, $this->create(['foo', 'bar'])); static::assertSame(5, $this->create([ @@ -560,6 +562,11 @@ public function testChunk(): void static::assertSame(['baz'], $chunks->at(2)->toArray()); } + protected function default(): VectorInterface + { + return ($this->vectorClass)::default(); + } + /** * @template T * diff --git a/tests/unit/Comparison/AbstractComparisonTest.php b/tests/unit/Comparison/AbstractComparisonTest.php index 1494f624..4cba0c0f 100644 --- a/tests/unit/Comparison/AbstractComparisonTest.php +++ b/tests/unit/Comparison/AbstractComparisonTest.php @@ -14,10 +14,16 @@ abstract class AbstractComparisonTest extends TestCase { public static function provideComparisonCases(): Generator { + yield 'scalar-default' => [0, 0, Order::default()]; yield 'scalar-equal' => [0, 0, Order::Equal]; yield 'scalar-less' => [0, 1, Order::Less]; yield 'scalar-greater' => [1, 0, Order::Greater]; + yield 'comparable-default' => [ + self::createComparableIntWrapper(0), + self::createComparableIntWrapper(0), + Order::default() + ]; yield 'comparable-equal' => [ self::createComparableIntWrapper(0), self::createComparableIntWrapper(0), diff --git a/tests/unit/DataStructure/PriorityQueueTest.php b/tests/unit/DataStructure/PriorityQueueTest.php index d22a87de..8b8abbba 100644 --- a/tests/unit/DataStructure/PriorityQueueTest.php +++ b/tests/unit/DataStructure/PriorityQueueTest.php @@ -11,7 +11,7 @@ final class PriorityQueueTest extends TestCase { public function testEnqueueAndDequeue(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); $queue->enqueue('hi', 1); $queue->enqueue('hey', 2); $queue->enqueue('hello', 3); @@ -26,7 +26,7 @@ public function testEnqueueAndDequeue(): void public function testDefaultEnqueueSettings(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); $queue->enqueue('hey'); $queue->enqueue('ho', 0); $queue->enqueue('hi', -1); @@ -44,7 +44,7 @@ public function testDefaultEnqueueSettings(): void public function testMultipleNodesWithSamePriority(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); $queue->enqueue('hi', 1); $queue->enqueue('hey', 1); $queue->enqueue('hello', 1); @@ -59,7 +59,7 @@ public function testMultipleNodesWithSamePriority(): void public function testPeekDoesNotRemoveTheNode(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); $queue->enqueue('hi', 1); $queue->enqueue('hey', 2); $queue->enqueue('hello', 3); @@ -72,7 +72,7 @@ public function testPeekDoesNotRemoveTheNode(): void public function testPeekReturnsNullWhenTheQueueIsEmpty(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); static::assertCount(0, $queue); static::assertNull($queue->peek()); @@ -80,7 +80,7 @@ public function testPeekReturnsNullWhenTheQueueIsEmpty(): void public function testPullDoesRemoveTheNode(): void { - $queue = new DataStructure\PriorityQueue(); + $queue = DataStructure\PriorityQueue::default(); $queue->enqueue('hi', 1); $queue->enqueue('hey', 2); $queue->enqueue('hello', 3); diff --git a/tests/unit/DataStructure/QueueTest.php b/tests/unit/DataStructure/QueueTest.php index 31954029..5c32eb87 100644 --- a/tests/unit/DataStructure/QueueTest.php +++ b/tests/unit/DataStructure/QueueTest.php @@ -11,7 +11,7 @@ final class QueueTest extends TestCase { public function testEnqueueAndDequeue(): void { - $queue = new DataStructure\Queue(); + $queue = DataStructure\Queue::default(); $queue->enqueue('hello'); $queue->enqueue('hey'); $queue->enqueue('hi'); @@ -26,7 +26,7 @@ public function testEnqueueAndDequeue(): void public function testPeekDoesNotRemoveTheNode(): void { - $queue = new DataStructure\Queue(); + $queue = DataStructure\Queue::default(); $queue->enqueue('hello'); $queue->enqueue('hey'); $queue->enqueue('hi'); @@ -39,7 +39,7 @@ public function testPeekDoesNotRemoveTheNode(): void public function testPeekReturnsNullWhenTheQueueIsEmpty(): void { - $queue = new DataStructure\Queue(); + $queue = DataStructure\Queue::default(); static::assertCount(0, $queue); static::assertNull($queue->peek()); diff --git a/tests/unit/DataStructure/StackTest.php b/tests/unit/DataStructure/StackTest.php index 11139b1e..473f047a 100644 --- a/tests/unit/DataStructure/StackTest.php +++ b/tests/unit/DataStructure/StackTest.php @@ -11,7 +11,7 @@ final class StackTest extends TestCase { public function testPushAndPop(): void { - $stack = new DataStructure\Stack(); + $stack = DataStructure\Stack::default(); $stack->push('hello'); $stack->push('hey'); $stack->push('hi'); @@ -29,7 +29,7 @@ public function testPushAndPop(): void public function testPeek(): void { - $stack = new DataStructure\Stack(); + $stack = DataStructure\Stack::default(); static::assertNull($stack->peek()); @@ -45,7 +45,7 @@ public function testPeek(): void public function testPopThrowsForEmptyStack(): void { - $stack = new DataStructure\Stack(); + $stack = DataStructure\Stack::default(); $stack->push('hello'); static::assertSame('hello', $stack->pop()); diff --git a/tests/unit/Encoding/Base64Test.php b/tests/unit/Encoding/Base64Test.php index 19e292de..213381d7 100644 --- a/tests/unit/Encoding/Base64Test.php +++ b/tests/unit/Encoding/Base64Test.php @@ -17,8 +17,10 @@ final class Base64Test extends TestCase */ public function testEncodeAndDecode(string $random): void { - $encoded = Base64\encode($random); + $encoded = Base64\encode($random, Base64\Variant::default()); + static::assertSame($random, Base64\decode($encoded)); + static::assertSame($random, Base64\decode($encoded, Base64\Variant::default())); } public function testDecodeThrowsForCharactersOutsideTheBase64Range(): void @@ -40,9 +42,9 @@ public function testDecodeThrowsForIncorrectPadding(): void */ public function testEncodeWithoutPaddingThenDecode(string $random): void { - $encoded = Base64\encode($random, Base64\Variant::Default, false); + $encoded = Base64\encode($random, Base64\Variant::default(), false); static::assertFalse(Regex\matches($encoded, '/={1,3}$/')); - static::assertSame($random, Base64\decode($encoded, Base64\Variant::Default, false)); + static::assertSame($random, Base64\decode($encoded, Base64\Variant::default(), false)); } public function provideRandomBytes(): iterable diff --git a/tests/unit/OS/FamilyTest.php b/tests/unit/OS/FamilyTest.php index 63ab29f1..5822e2c3 100644 --- a/tests/unit/OS/FamilyTest.php +++ b/tests/unit/OS/FamilyTest.php @@ -14,12 +14,16 @@ final class FamilyTest extends TestCase public function testFamily(): void { if (OS\is_windows()) { + static::assertSame(OS\OperatingSystemFamily::Windows, OS\OperatingSystemFamily::default()); static::assertSame(OS\OperatingSystemFamily::Windows, OS\family()); static::assertFalse(OS\is_darwin()); } elseif (OS\is_darwin()) { + static::assertSame(OS\OperatingSystemFamily::Darwin, OS\OperatingSystemFamily::default()); static::assertSame(OS\OperatingSystemFamily::Darwin, OS\family()); static::assertFalse(OS\is_windows()); } else { + static::assertNotSame(OS\OperatingSystemFamily::Windows, OS\OperatingSystemFamily::default()); + static::assertNotSame(OS\OperatingSystemFamily::Darwin, OS\OperatingSystemFamily::default()); static::assertNotSame(OS\OperatingSystemFamily::Windows, OS\family()); static::assertNotSame(OS\OperatingSystemFamily::Darwin, OS\family()); static::assertFalse(OS\is_windows()); diff --git a/tests/unit/Password/PasswordTest.php b/tests/unit/Password/PasswordTest.php index ffa442aa..1c1b8c14 100644 --- a/tests/unit/Password/PasswordTest.php +++ b/tests/unit/Password/PasswordTest.php @@ -11,6 +11,18 @@ final class PasswordTest extends TestCase { + /** + * @dataProvider providePasswords + */ + public function testDefault(string $password): void + { + $hash = Password\hash($password, Password\Algorithm::default()); + + static::assertTrue(Password\verify($password, $hash)); + + static::assertFalse(Password\needs_rehash($hash, Password\Algorithm::default())); + } + /** * @dataProvider providePasswords */ diff --git a/tests/unit/RandomSequence/SecureSequenceTest.php b/tests/unit/RandomSequence/SecureSequenceTest.php index c96ae3fe..824bac4a 100644 --- a/tests/unit/RandomSequence/SecureSequenceTest.php +++ b/tests/unit/RandomSequence/SecureSequenceTest.php @@ -11,7 +11,7 @@ final class SecureSequenceTest extends TestCase { public function testNext(): void { - $sequence = new SecureSequence(); + $sequence = SecureSequence::default(); $a = $sequence->next(); $b = $sequence->next(); diff --git a/tests/unit/Shell/ExecuteTest.php b/tests/unit/Shell/ExecuteTest.php index 743808fc..7e0fc8f2 100644 --- a/tests/unit/Shell/ExecuteTest.php +++ b/tests/unit/Shell/ExecuteTest.php @@ -97,6 +97,10 @@ public function testErrorOutputIsDiscarded(): void $result = Shell\execute(PHP_BINARY, ['-r', 'fwrite(STDOUT, "hello"); fwrite(STDERR, " world");']); static::assertSame('hello', $result); + + $result = Shell\execute(PHP_BINARY, ['-r', 'fwrite(STDOUT, "hello"); fwrite(STDERR, " world");'], error_output_behavior: Shell\ErrorOutputBehavior::default()); + + static::assertSame('hello', $result); } public function testErrorOutputIsAppended(): void diff --git a/tests/unit/TCP/ConnectOptionsTest.php b/tests/unit/TCP/ConnectOptionsTest.php index 6c3ba285..89433864 100644 --- a/tests/unit/TCP/ConnectOptionsTest.php +++ b/tests/unit/TCP/ConnectOptionsTest.php @@ -11,7 +11,7 @@ final class ConnectOptionsTest extends TestCase { public function testOptions(): void { - $options = ConnectOptions::create(); + $options = ConnectOptions::default(); static::assertFalse($options->noDelay); diff --git a/tests/unit/TCP/ServerOptionsTest.php b/tests/unit/TCP/ServerOptionsTest.php index d1666e27..8347bc8b 100644 --- a/tests/unit/TCP/ServerOptionsTest.php +++ b/tests/unit/TCP/ServerOptionsTest.php @@ -5,13 +5,22 @@ namespace Psl\Tests\Unit\TCP; use PHPUnit\Framework\TestCase; +use Psl\Network\SocketOptions; use Psl\TCP\ServerOptions; final class ServerOptionsTest extends TestCase { - public function testOptions(): void + public function testDefaultOptions(): void { - $options = ServerOptions::create(); + $options = ServerOptions::default(); + + static::assertFalse($options->noDelay); + static::assertEquals(ServerOptions::DEFAULT_IDLE_CONNECTIONS, $options->idleConnections); + static::assertEquals(SocketOptions::default(), $options->socketOptions); + } + public function testNoDelay(): void + { + $options = ServerOptions::default(); static::assertFalse($options->noDelay); @@ -22,5 +31,33 @@ public function testOptions(): void $options = $options->withNoDelay(false); static::assertFalse($options->noDelay); + + $options = $options->withNoDelay(true); + + static::assertTrue($options->noDelay); + } + + public function testIdleConnections(): void + { + $options = ServerOptions::create(idle_connections: 10); + + static::assertSame(10, $options->idleConnections); + + $options = $options->withIdleConnections(20); + + static::assertSame(20, $options->idleConnections); + } + + public function testSocketOptions(): void + { + $options = ServerOptions::default(); + + static::assertEquals(SocketOptions::default(), $options->socketOptions); + + $socketOptions = SocketOptions::default()->withBroadcast(); + + $options = $options->withSocketOptions($socketOptions); + + static::assertSame($socketOptions, $options->socketOptions); } }