Compare commits

..

2 Commits
1.x ... 0.x

15 changed files with 1090 additions and 683 deletions

View File

@ -15,7 +15,7 @@ before_script:
apt-get update -yqq && apt-get upgrade -yqq && apt-get install -yqq git libzip-dev unzip zip libpcre3-dev && docker-php-ext-install zip && pecl install xdebug && docker-php-ext-enable xdebug apt-get update -yqq && apt-get upgrade -yqq && apt-get install -yqq git libzip-dev unzip zip libpcre3-dev && docker-php-ext-install zip && pecl install xdebug && docker-php-ext-enable xdebug
fi fi
- > - >
if [ "$CI_JOB_NAME" == "test:8.1" ]; then if [ "$CI_JOB_NAME" == "test:7.4" ] || [ "$CI_JOB_NAME" == "test:8.0" ]; then
pecl install ds && docker-php-ext-enable ds pecl install ds && docker-php-ext-enable ds
fi fi
- > - >
@ -23,20 +23,36 @@ before_script:
curl -sS https://getcomposer.org/installer | php curl -sS https://getcomposer.org/installer | php
php composer.phar install php composer.phar install
fi fi
test:8.1: test:7.4:
only: only:
- branches - branches
tags: tags:
- default - default
image: php:8.1 image: php:7.4
script: script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never - vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
test:8.1-without-ext-ds: test:7.4-without-ext-ds:
only: only:
- branches - branches
tags: tags:
- default - default
image: php:8.1 image: php:7.4
script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
test:8.0:
only:
- branches
tags:
- default
image: php:8.0
script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
test:8.0-without-ext-ds:
only:
- branches
tags:
- default
image: php:8.0
script: script:
- vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never - vendor/bin/phpunit --configuration phpunit.xml --coverage-text --colors=never
stages: stages:

View File

@ -1,77 +0,0 @@
<?php declare(strict_types=1);
/*
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
*
* This file is a part of Olive BBS
*
* This Source Code Form is subject to the
* terms of the Mozilla Public License, v. 2.0.
*
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*
* ___ ___ ___
* ( ).-. ( ) ( )
* .--. | |( __)___ ___ .--. | |.-. | |.-. .--.
* / \| |(''"( )( / \| / \| / \ / _ \
* | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ;
* | | | | | | | | | | | | | | | | | | | || ' | |
* | | | | | | | | | | | |/ | | | | | | |_\_`.(___)
* | | | | | | | | | | | ' _.| | | | | | ( ). '.
* | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ |
* ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' '
* `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.'
*
*/
$header = '';
if (file_exists(__DIR__.'/header.txt')) {
$header = file_get_contents('header.txt');
}
return (new \PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR2' => true,
'@PHP80Migration' => true,
'@PHP80Migration:risky' => true,
'@PHP81Migration' => true,
'header_comment' => ['header' => $header],
'ordered_class_elements' => true,
'ordered_imports' => true,
'no_mixed_echo_print' => ['use' => 'print'],
'strict_param' => true,
'strict_comparison' => true,
'single_import_per_statement' => false,
'phpdoc_order' => true,
'array_syntax' => ['syntax' => 'short'],
'phpdoc_add_missing_param_annotation' => true,
'psr_autoloading' => true,
'phpdoc_var_without_name' => false,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_extra_blank_lines' => [
'tokens' => [
'break',
'continue',
'extra',
'return',
'throw',
'parenthesis_brace_block',
'square_brace_block',
'curly_brace_block',
],
],
])->setFinder(
(new \PhpCsFixer\Finder())
->ignoreDotFiles(true)
->ignoreVCS(true)
->name('*.php')
->in([
'src',
'tests',
__DIR__,
])
);

58
.php_cs.dist Normal file
View File

@ -0,0 +1,58 @@
<?php
$header = '';
if(file_exists(__DIR__.'/header.txt')) {
$header = file_get_contents('header.txt');
}
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules(
[
'@PSR2' => true,
'@PHP70Migration' => true,
'@PHP70Migration:risky' => true,
'@PHP71Migration' => true,
'@PHP71Migration:risky' => true,
'@PHP73Migration' => true,
'@PHP74Migration' => true,
'@PHP74Migration:risky' => true,
'@PHP80Migration' => true,
'@PHP80Migration:risky' => true,
'header_comment' => ['header' => $header],
'ordered_class_elements' => true,
'ordered_imports' => true,
'no_mixed_echo_print' => ['use' => 'print'],
'strict_param' => true,
'strict_comparison' => true,
'single_import_per_statement' => false,
'phpdoc_order' => true,
'array_syntax' => ['syntax' => 'short'],
'phpdoc_add_missing_param_annotation' => true,
'psr4' => true,
'phpdoc_var_without_name' => false,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_extra_consecutive_blank_lines' => [
'break',
'continue',
'extra',
'return',
'throw',
'parenthesis_brace_block',
'square_brace_block',
'curly_brace_block',
],
]
)->setFinder(
PhpCsFixer\Finder::create()
->ignoreDotFiles(true)
->ignoreVCS(true)
->name('*.php')
->in([
'src',
'tests',
])
);

View File

@ -2,21 +2,18 @@
Very simple typed map class. Very simple typed map class.
Includes IntCharMap and CharMap as examples. It is best to extend `Olivebbs\Map\GenericMap `for your uses. Includes IntCharMap and CharMap as examples. It is best to extend `Olivebbs\Map\GenericMap `for your uses.
### Example ### Example
```php ```php
use Olivebbs\Map\GenericMap; use Olivebbs\Map\GenericMap;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Enum\KeyType;
final class MyStringMap extends GenericMap final class MyStringMap extends GenericMap
{ {
public function __construct(array $values) public function __construct(array $values)
{ {
parent::__construct(KeyType::STRING, ValueType::STRING); parent::__construct(GenericMap::STRING, GenericMap::STRING);
$this->map->putAll($values); $this->map->putAll($values);
} }
} }
@ -26,10 +23,8 @@ or
```php ```php
use Olivebbs\Map\GenericMap; use Olivebbs\Map\GenericMap;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Enum\KeyType;
$myIntMap = new GenericMap(KeyType::INT, ValueType::INT); $myIntMap = new GenericMap(GenericMap::INT, GenericMap::INT);
``` ```
Then use it. Then use it.
```php ```php

View File

@ -2,13 +2,13 @@
"name": "olive/map", "name": "olive/map",
"description": "Generic map for PHP", "description": "Generic map for PHP",
"type": "library", "type": "library",
"keywords": ["map", "hashmap", "hash-map", "data", "data structure", "array", "arrayaccess"],
"require": { "require": {
"php": ">=8.1", "php": "7.4 - 8.0",
"php-ds/php-ds": "^1.4" "php-ds/php-ds": "^1.3",
"symfony/polyfill-php80": "^1.22"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^3.13", "friendsofphp/php-cs-fixer": "^2.18",
"phpunit/phpunit": "^9.5" "phpunit/phpunit": "^9.5"
}, },
"license": "MPL-2.0", "license": "MPL-2.0",
@ -19,7 +19,7 @@
} }
], ],
"suggest": { "suggest": {
"ext-ds": "To use the Data structure extension instead of polyfill." "ext-ds": "ext-ds"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

1157
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -28,23 +28,20 @@
namespace Olivebbs\Map; namespace Olivebbs\Map;
use function array_combine; use function array_combine;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use function str_split; use function str_split;
class CharMap extends GenericMap class CharMap extends GenericMap
{ {
public function __construct(array $initialValues = []) public function __construct(array $initialValues = [])
{ {
parent::__construct(keyType: KeyType::CHAR, valueType: ValueType::CHAR); parent::__construct(self::CHAR, self::CHAR);
$this->map->putAll(values: $initialValues); $this->map->putAll($initialValues);
} }
public static function fromString(string $string): static public static function fromString(string $string): CharMap
{ {
$values = str_split(string: $string); $values = str_split($string);
return new self(array_combine($values, $values));
return new static(initialValues: array_combine(keys: $values, values: $values));
} }
} }

View File

@ -1,37 +0,0 @@
<?php declare(strict_types=1);
/*
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
*
* This file is a part of Olive BBS
*
* This Source Code Form is subject to the
* terms of the Mozilla Public License, v. 2.0.
*
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*
* ___ ___ ___
* ( ).-. ( ) ( )
* .--. | |( __)___ ___ .--. | |.-. | |.-. .--.
* / \| |(''"( )( / \| / \| / \ / _ \
* | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ;
* | | | | | | | | | | | | | | | | | | | || ' | |
* | | | | | | | | | | | |/ | | | | | | |_\_`.(___)
* | | | | | | | | | | | ' _.| | | | | | ( ). '.
* | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ |
* ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' '
* `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.'
*
*/
namespace Olivebbs\Map\Enum;
enum KeyType : string
{
case INT = 'int';
case INTEGER = 'integer'; // Shouldn't really use, just for compatibility.
case STRING = 'string';
case CHAR = 'char';
case ANY = 'any';
}

View File

@ -1,41 +0,0 @@
<?php declare(strict_types=1);
/*
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
*
* This file is a part of Olive BBS
*
* This Source Code Form is subject to the
* terms of the Mozilla Public License, v. 2.0.
*
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*
* ___ ___ ___
* ( ).-. ( ) ( )
* .--. | |( __)___ ___ .--. | |.-. | |.-. .--.
* / \| |(''"( )( / \| / \| / \ / _ \
* | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ;
* | | | | | | | | | | | | | | | | | | | || ' | |
* | | | | | | | | | | | |/ | | | | | | |_\_`.(___)
* | | | | | | | | | | | ' _.| | | | | | ( ). '.
* | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ |
* ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' '
* `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.'
*
*/
namespace Olivebbs\Map\Enum;
enum ValueType : string
{
case OBJECT = 'object';
case CALLABLE = 'callable';
case ARRAY = 'array';
case INT = 'int';
case INTEGER = 'integer';
case STRING = 'string';
case CHAR = 'char';
case ENUM = 'enum';
case ANY = 'any';
}

View File

@ -28,46 +28,57 @@
namespace Olivebbs\Map; namespace Olivebbs\Map;
use ArrayAccess; use ArrayAccess;
use function class_exists;
use Countable; use Countable;
use Ds\Map; use Ds\Map;
use function enum_exists;
use function is_array; use function is_array;
use function is_callable; use function is_callable;
use function is_int; use function is_int;
use function is_object; use function is_object;
use function is_string; use function is_string;
use function mb_strlen;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Exception\InvalidArgumentException; use Olivebbs\Map\Exception\InvalidArgumentException;
use function sprintf;
use function strtolower;
use TypeError;
use ValueError;
class GenericMap implements ArrayAccess, Countable class GenericMap implements ArrayAccess, Countable
{ {
public const OBJECT = 'object';
public const CALLABLE = 'callable';
public const ARRAY = 'array';
public const INT = 'int';
public const INTEGER = 'integer';
public const STRING = 'string';
public const CHAR = 'char';
public const ANY = 'any';
protected Map $map; protected Map $map;
protected string $keyType;
protected string $valueType;
private readonly string $valueTypeValue; public function __construct(string $keyType = self::ANY, string $valueType = self::ANY)
private readonly string $keyTypeValue;
public function __construct(protected KeyType $keyType = KeyType::ANY, protected object|string $valueType = ValueType::ANY)
{ {
$this->keyTypeValue = $this->keyType->value; $this->keyType = strtolower($keyType);
$this->valueTypeValue = is_string(value: $this->valueType) ? $this->valueType : $this->valueType->value;
if (!$this->isValidValueType(type: $this->valueType)) { $this->valueType = class_exists($valueType) ? $valueType : strtolower($valueType);
throw new InvalidArgumentException(message: sprintf('Invalid value type (%s)', $this->valueTypeValue));
if (!$this->isValidKeyType($this->keyType)) {
throw new InvalidArgumentException(sprintf('Invalid key type (%s)', $this->keyType));
}
if (!$this->isValidValueType($this->valueType)) {
throw new InvalidArgumentException(sprintf('Invalid value type (%s)', $this->valueType));
} }
$this->map = new Map(); $this->map = new Map();
} }
public function getKeyType(): KeyType public function getKeyType(): string
{ {
return $this->keyType; return $this->keyType;
} }
public function getValueType(): object|string public function getValueType(): string
{ {
return $this->valueType; return $this->valueType;
} }
@ -75,45 +86,71 @@ class GenericMap implements ArrayAccess, Countable
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function offsetExists(mixed $offset): bool public function offsetExists($offset): bool
{ {
$this->checkTypes(offset: $offset); if (is_array($offset) || is_object($offset)) {
throw new InvalidArgumentException('Map keys cannot be objects or arrays');
return $this->map->offsetExists(offset: $offset);
}
/**
* @inheritDoc
*/
public function offsetGet(mixed $offset): mixed
{
$this->checkTypes(offset: $offset);
if (!$this->map->offsetExists(offset: $offset)) {
return null;
} }
return $this->map->offsetGet(offset: $offset); if (!$this->checkType($this->keyType, $offset)) {
throw new TypeError(sprintf('Key should be of value %s.', $this->keyType));
}
return $this->map->offsetExists($offset);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function offsetSet(mixed $offset, mixed $value): void public function offsetGet($offset)
{ {
$this->checkTypes(offset: $offset, value: $value); if (is_array($offset) || is_object($offset)) {
throw new InvalidArgumentException('Map keys cannot be objects or arrays');
}
$this->map->offsetSet(offset: $offset, value: $value); if (!$this->checkType($this->keyType, $offset)) {
throw new TypeError(sprintf('Key should be of value %s.', $this->keyType));
}
if (!$this->map->offsetExists($offset)) {
return null;
}
return $this->map->offsetGet($offset);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function offsetUnset(mixed $offset): void public function offsetSet($offset, $value): void
{ {
$this->checkTypes(offset: $offset); if (is_array($offset) || is_object($offset)) {
throw new InvalidArgumentException('Map keys cannot be objects or arrays');
}
$this->map->offsetUnset(offset: $offset); if (!$this->checkType($this->keyType, $offset)) {
throw new TypeError(sprintf('Key should be of value %s.', $this->keyType));
}
if (!$this->checkType($this->valueType, $value)) {
throw new ValueError(sprintf('Value should be of type %s.', $this->valueType));
}
$this->map->offsetSet($offset, $value);
}
/**
* @inheritDoc
*/
public function offsetUnset($offset): void
{
if (is_array($offset) || is_object($offset)) {
throw new InvalidArgumentException('Map keys cannot be objects or arrays');
}
if (!$this->checkType($this->keyType, $offset)) {
throw new TypeError(sprintf('Key should be of value %s.', $this->keyType));
}
$this->map->offsetUnset($offset);
} }
/** /**
@ -139,56 +176,68 @@ class GenericMap implements ArrayAccess, Countable
{ {
foreach ($initialValues as $key => $value) { foreach ($initialValues as $key => $value) {
if (!$this->checkType($this->keyType, $key) || !$this->checkType($this->valueType, $value)) { if (!$this->checkType($this->keyType, $key) || !$this->checkType($this->valueType, $value)) {
throw new InvalidArgumentException(message: sprintf('Invalid types for map [%s => %s], they should be [%s => %s]', get_debug_type(value: $key), get_debug_type(value: $value), $this->keyType->value, is_string($this->valueType) ? $this->valueType : $this->valueType->value)); throw new InvalidArgumentException(sprintf('Invalid types for map [%s => %s], they should be [%s => %s]', get_debug_type($key), get_debug_type($value), $this->keyType, $this->valueType));
} }
} }
return true; return true;
} }
private function checkTypes(mixed $offset, mixed $value = null): void
{
if (is_array(value: $offset) || is_object(value: $offset)) {
throw new InvalidArgumentException(message: 'Map keys cannot be objects or arrays');
}
if (!$this->checkType(type: $this->keyType, var: $offset)) {
throw new InvalidArgumentException(message: sprintf('Key should be of value %s.', $this->keyTypeValue));
}
if (null !== $value && !$this->checkType(type: $this->valueType, var: $value)) {
throw new InvalidArgumentException(message: sprintf('Value should be of type %s.', $this->valueTypeValue));
}
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @param KeyType|ValueType|string $type * @param string $type
* @param mixed $var * @param $var
* *
* @return bool * @return bool
*/ */
private function checkType(KeyType|ValueType|string $type, mixed $var): bool private function checkType(string $type, $var): bool
{ {
return match ($type) { switch ($type) {
ValueType::OBJECT => is_object(value: $var), case self::OBJECT:
ValueType::CALLABLE => is_callable(value: $var), return is_object($var);
ValueType::ARRAY => is_array(value: $var), case self::CALLABLE:
KeyType::INT, KeyType::INTEGER, ValueType::INT, ValueType::INTEGER => is_int(value: $var), return is_callable($var);
KeyType::STRING, ValueType::STRING => is_string(value: $var), case self::ARRAY:
KeyType::CHAR, ValueType::CHAR => is_string(value: $var) && (function_exists('mb_strlen') ? mb_strlen(string: $var) === 1 : strlen(string: $var) === 1), return is_array($var);
ValueType::ENUM => is_object(value: $var) && enum_exists(enum: $var::class), case self::INT:
KeyType::ANY, ValueType::ANY => true, case self::INTEGER:
default => $var instanceof $type, return is_int($var);
}; case self::STRING:
return is_string($var);
case self::CHAR:
return is_string($var) && \mb_strlen($var) === 1;
case self::ANY:
return true;
default:
return $var instanceof $type;
}
}
private function isValidKeyType(string $type): bool
{
return in_array($type, [
self::INT,
self::INTEGER,
self::STRING,
self::CHAR,
self::ANY,
], true);
} }
private function isValidValueType(object|string $type): bool private function isValidValueType(string $type): bool
{ {
if (is_string(value: $type) && class_exists(class: $type)) { if (class_exists($type)) {
return true; return true;
} }
return $type instanceof ValueType; return in_array($type, [
self::OBJECT,
self::CALLABLE,
self::ARRAY,
self::INT,
self::INTEGER,
self::STRING,
self::CHAR,
self::ANY,
], true);
} }
} }

View File

@ -27,35 +27,33 @@
namespace Olivebbs\Map; namespace Olivebbs\Map;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Exception\ImmutableMapException; use Olivebbs\Map\Exception\ImmutableMapException;
class ImmutableMap extends GenericMap class ImmutableMap extends GenericMap
{ {
private function __construct( private function __construct(
KeyType $keyType, ?string $keyType,
object|string $valueType, ?string $valueType,
array $values array $values
) { ) {
parent::__construct(keyType: $keyType, valueType: $valueType); parent::__construct($keyType, $valueType);
$this->assertInitialValues(initialValues: $values); $this->assertInitialValues($values);
$this->map->putAll(values: $values); $this->map->putAll($values);
} }
public function offsetSet(mixed $offset, mixed $value): void public function offsetSet($offset, $value): void
{ {
throw new ImmutableMapException(message: sprintf('Cannot change values in %s', __CLASS__)); throw new ImmutableMapException(sprintf('Cannot change values in %s', __CLASS__));
} }
public function offsetUnset(mixed $offset): void public function offsetUnset($offset): void
{ {
throw new ImmutableMapException(message: sprintf('Cannot unset values in %s', __CLASS__)); throw new ImmutableMapException(sprintf('Cannot unset values in %s', __CLASS__));
} }
public static function create(KeyType $keyType, ValueType $valueType, array $values): static public static function create(string $keyType, string $valueType, array $values): ImmutableMap
{ {
return new static(keyType: $keyType, valueType: $valueType, values: $values); return new self($keyType, $valueType, $values);
} }
} }

View File

@ -27,22 +27,20 @@
namespace Olivebbs\Map; namespace Olivebbs\Map;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use function str_split; use function str_split;
class IntCharMap extends GenericMap class IntCharMap extends GenericMap
{ {
public function __construct(array $initialValues = []) public function __construct(array $initialValues = [])
{ {
parent::__construct(keyType:KeyType::INT, valueType: ValueType::CHAR); parent::__construct(self::INT, self::CHAR);
$this->map->putAll(values: $initialValues); $this->map->putAll($initialValues);
} }
public static function fromString(string $string): static public static function fromString(string $string): IntCharMap
{ {
$values = str_split(string: $string); $values = str_split($string);
return new static(initialValues: $values); return new self($values);
} }
} }

View File

@ -27,13 +27,10 @@
namespace Olivebbs\Tests\Map; namespace Olivebbs\Tests\Map;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Exception\InvalidArgumentException; use Olivebbs\Map\Exception\InvalidArgumentException;
use Olivebbs\Map\GenericMap; use Olivebbs\Map\GenericMap;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use SplObjectStorage; use ValueError;
use stdClass;
class GenericMapTest extends TestCase class GenericMapTest extends TestCase
{ {
@ -49,13 +46,13 @@ class GenericMapTest extends TestCase
public function testHashMap(): void public function testHashMap(): void
{ {
$genericHashMap = new GenericMap(KeyType::INT, ValueType::INT); $genericHashMap = new GenericMap(GenericMap::INT, GenericMap::INT);
foreach (range(0, 9) as $range) { foreach (range(0, 9) as $range) {
$genericHashMap[$range] = $range; $genericHashMap[$range] = $range;
} }
self::assertSame(KeyType::INT, $this->genericMap->getKeyType()); self::assertSame(GenericMap::INT, $this->genericMap->getKeyType());
self::assertSame(ValueType::INT, $this->genericMap->getValueType()); self::assertSame(GenericMap::INT, $this->genericMap->getValueType());
self::assertCount(10, $this->genericMap); self::assertCount(10, $this->genericMap);
self::assertEquals(10, $this->genericMap->count()); self::assertEquals(10, $this->genericMap->count());
$array = array_combine(range(0, 9), range(0, 9)); $array = array_combine(range(0, 9), range(0, 9));
@ -67,15 +64,15 @@ class GenericMapTest extends TestCase
unset($this->genericMap[1]); unset($this->genericMap[1]);
self::assertNull($this->genericMap[1]); self::assertNull($this->genericMap[1]);
$this->expectException(InvalidArgumentException::class); $this->expectException(\TypeError::class);
$this->genericMap['H'] = 1; $this->genericMap['H'] = 1;
} }
public function testInvalidArgumentExceptionThrowsIsset(): void public function testInvalidArgumentExceptionThrowsIsset(): void
{ {
$genericHashMap = new GenericMap(KeyType::ANY, ValueType::ANY); $genericHashMap = new GenericMap(GenericMap::ANY, GenericMap::ANY);
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$obj = new stdClass(); $obj = new \stdClass();
/** @noinspection PhpExpressionResultUnusedInspection */ /** @noinspection PhpExpressionResultUnusedInspection */
isset($genericHashMap[$obj]); isset($genericHashMap[$obj]);
} }
@ -83,17 +80,23 @@ class GenericMapTest extends TestCase
public function testTypeErrorThrowsIsset(): void public function testTypeErrorThrowsIsset(): void
{ {
$genericMap = $this->getGenericMap(); $genericMap = $this->getGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(\TypeError::class);
/** @noinspection PhpExpressionResultUnusedInspection */ /** @noinspection PhpExpressionResultUnusedInspection */
isset($genericMap['C']); isset($genericMap['C']);
} }
public function testInvalidArgumentExceptionThrowsOnArrayOrObject(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid key type (array)');
$genericMap = new GenericMap(GenericMap::ARRAY, GenericMap::ARRAY);
}
public function testOffsetGetThrowsInvalidArgumentException(): void public function testOffsetGetThrowsInvalidArgumentException(): void
{ {
$genericMap = $this->getGenericMap(); $genericMap = $this->getGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$obj = new stdClass(); $obj = new \stdClass();
$test = $genericMap[$obj]; $test = $genericMap[$obj];
} }
@ -101,7 +104,7 @@ class GenericMapTest extends TestCase
{ {
$genericMap = $this->getGenericMap(); $genericMap = $this->getGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$obj = new stdClass(); $obj = new \stdClass();
$genericMap[$obj] = 1; $genericMap[$obj] = 1;
} }
@ -109,14 +112,14 @@ class GenericMapTest extends TestCase
{ {
$genericMap = $this->getGenericMap(); $genericMap = $this->getGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$obj = new stdClass(); $obj = new \stdClass();
unset($genericMap[$obj]); unset($genericMap[$obj]);
} }
public function testOffsetSetThrowsValueErrorException(): void public function testOffsetSetThrowsValueErrorException(): void
{ {
$genericMap = $this->getGenericMap(); $genericMap = $this->getGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(ValueError::class);
$genericMap[0] = 'string'; $genericMap[0] = 'string';
} }
@ -125,7 +128,7 @@ class GenericMapTest extends TestCase
{ {
$this->resetGenericMap(); $this->resetGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(\TypeError::class);
unset($this->genericMap['C']); unset($this->genericMap['C']);
} }
@ -133,7 +136,7 @@ class GenericMapTest extends TestCase
public function testOffsetGetThrowsTypeErrorException(): void public function testOffsetGetThrowsTypeErrorException(): void
{ {
$this->resetGenericMap(); $this->resetGenericMap();
$this->expectException(InvalidArgumentException::class); $this->expectException(\TypeError::class);
$test = $this->genericMap['C']; $test = $this->genericMap['C'];
} }
@ -141,14 +144,14 @@ class GenericMapTest extends TestCase
public function testThrowInvalidArgumentExceptionOnConstructValue(): void public function testThrowInvalidArgumentExceptionOnConstructValue(): void
{ {
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$genericMap = new GenericMap(KeyType::CHAR, 'test'); $genericMap = new GenericMap(GenericMap::CHAR, 'test');
} }
public function testUsingClassAsValue(): void public function testUsingClassAsValue(): void
{ {
$genericMap = new GenericMap(KeyType::INT, SplObjectStorage::class); $genericMap = new GenericMap(GenericMap::INT, \SplObjectStorage::class);
$splObject = new SplObjectStorage(); $splObject = new \SplObjectStorage();
$stdClass = new stdClass(); $stdClass = new \stdClass();
$splObject->attach($stdClass); $splObject->attach($stdClass);
$genericMap[0] = $splObject; $genericMap[0] = $splObject;
self::assertSame($splObject, $genericMap[0]); self::assertSame($splObject, $genericMap[0]);
@ -157,29 +160,13 @@ class GenericMapTest extends TestCase
public function testObjectCantBeUsedAsKeyWithAny(): void public function testObjectCantBeUsedAsKeyWithAny(): void
{ {
$genericMap = new GenericMap(KeyType::ANY, ValueType::ANY); $genericMap = new GenericMap(GenericMap::ANY, GenericMap::ANY);
$object = new SplObjectStorage(); $object = new \SplObjectStorage();
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Map keys cannot be objects or arrays'); $this->expectExceptionMessage('Map keys cannot be objects or arrays');
$genericMap[$object] = 1; $genericMap[$object] = 1;
} }
public function testEnumMap(): void
{
$enumMap = new class(TestEnum::cases()) extends GenericMap {
public function __construct(array $values = [])
{
parent::__construct(KeyType::INT, ValueType::ENUM);
$this->assertInitialValues($values);
$this->map->putAll($values);
}
};
self::assertCount(8, $enumMap->toArray());
self::assertSame(TestEnum::a, $enumMap[0]);
self::assertSame(TestEnum::h, $enumMap[7]);
}
private function resetGenericMap(): void private function resetGenericMap(): void
{ {
$this->genericMap = $this->getGenericMap(); $this->genericMap = $this->getGenericMap();
@ -187,6 +174,6 @@ class GenericMapTest extends TestCase
private function getGenericMap(): GenericMap private function getGenericMap(): GenericMap
{ {
return new GenericMap(KeyType::INT, ValueType::INT); return new GenericMap(GenericMap::INT, GenericMap::INT);
} }
} }

View File

@ -27,10 +27,9 @@
namespace Olivebbs\Tests\Map; namespace Olivebbs\Tests\Map;
use Olivebbs\Map\Enum\KeyType;
use Olivebbs\Map\Enum\ValueType;
use Olivebbs\Map\Exception\ImmutableMapException; use Olivebbs\Map\Exception\ImmutableMapException;
use Olivebbs\Map\Exception\InvalidArgumentException; use Olivebbs\Map\Exception\InvalidArgumentException;
use Olivebbs\Map\GenericMap;
use Olivebbs\Map\ImmutableMap; use Olivebbs\Map\ImmutableMap;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -38,14 +37,14 @@ class ImmutableMapTest extends TestCase
{ {
public function testOffsetUnset(): void public function testOffsetUnset(): void
{ {
$immutableMap = ImmutableMap::create(KeyType::INTEGER, ValueType::CHAR, range('A', 'Z')); $immutableMap = ImmutableMap::create(GenericMap::INTEGER, GenericMap::CHAR, range('A', 'Z'));
$this->expectException(ImmutableMapException::class); $this->expectException(ImmutableMapException::class);
unset($immutableMap[0]); unset($immutableMap[0]);
} }
public function testOffsetSet(): void public function testOffsetSet(): void
{ {
$immutableMap = ImmutableMap::create(KeyType::INTEGER, ValueType::CHAR, range('A', 'Z')); $immutableMap = ImmutableMap::create(GenericMap::INTEGER, GenericMap::CHAR, range('A', 'Z'));
$this->expectException(ImmutableMapException::class); $this->expectException(ImmutableMapException::class);
$immutableMap[0] = 1; $immutableMap[0] = 1;
} }
@ -59,6 +58,6 @@ class ImmutableMapTest extends TestCase
]; ];
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid types for map [string => int], they should be [int => string]'); $this->expectExceptionMessage('Invalid types for map [string => int], they should be [int => string]');
$immutableMap = ImmutableMap::create(KeyType::INT, ValueType::STRING, $values); $immutableMap = ImmutableMap::create(GenericMap::INT, GenericMap::STRING, $values);
} }
} }

View File

@ -1,40 +0,0 @@
<?php declare(strict_types=1);
/*
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
*
* This file is a part of Olive BBS
*
* This Source Code Form is subject to the
* terms of the Mozilla Public License, v. 2.0.
*
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*
* ___ ___ ___
* ( ).-. ( ) ( )
* .--. | |( __)___ ___ .--. | |.-. | |.-. .--.
* / \| |(''"( )( / \| / \| / \ / _ \
* | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ;
* | | | | | | | | | | | | | | | | | | | || ' | |
* | | | | | | | | | | | |/ | | | | | | |_\_`.(___)
* | | | | | | | | | | | ' _.| | | | | | ( ). '.
* | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ |
* ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' '
* `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.'
*
*/
namespace Olivebbs\Tests\Map;
enum TestEnum
{
case a;
case b;
case c;
case d;
case e;
case f;
case g;
case h;
}