Git viewing holonet/common / bdc0e727ab1163869a035e43b0a948d801b1b48b


Filter

bdc0e727ab1163869a035e43b0a948d801b1b48b

Matthias Lantsch(4 months ago)

Fix tests and static analysis; CollectionTest

Browse Files
  • Changed file composer.json
    diff --git a/f5c95406e1cf6fe15e67f77eba8593013a789ada b/d8b0941aa9db8a5d10a69c77989eff84e247ffff
    index f5c9540..d8b0941 100644
    --- a/f5c95406e1cf6fe15e67f77eba8593013a789ada
    +++ b/d8b0941aa9db8a5d10a69c77989eff84e247ffff
    @@ -11,7 +11,7 @@
     	"require": {
     		"php": ">=8.1",
     		"monolog/monolog": "^2.0",
    -		"psr/container": "2.0.2"
    +		"psr/container": "^2.0.2"
     	},
     	"require-dev": {
     		"holonet/hdev": "~1.1.0@dev",
    @@ -19,7 +19,7 @@
     		"spatie/phpunit-snapshot-assertions": "dev-main"
     	},
     	"provide": {
    -		"psr/container-implementation": "2.0.2"
    +		"psr/container-implementation": "^2.0.2"
     	},
     	"repositories": [
     		{
    @@ -60,7 +60,7 @@
     		"test": [
     			"@composer validate",
     			"@composer normalize --dry-run --diff",
    -			"@php -d memory_limit=-1 vendor/phpunit/phpunit/phpunit -c phpunit.xml",
    +			"@php -d xdebug.mode=coverage -d memory_limit=-1 vendor/phpunit/phpunit/phpunit -c phpunit.xml",
     			"@php -d memory_limit=-1 vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix --verbose --dry-run --ansi",
     			"@php -d memory_limit=-1 vendor/vimeo/psalm/psalm"
     		]
  • Changed file Collection.php
    diff --git a/1143f81053f5f8ef420d7160d252fae32606b2b4 b/666402878461d1424cc03cc31a398400131fb5b7
    index 1143f81..6664028 100644
    --- a/1143f81053f5f8ef420d7160d252fae32606b2b4
    +++ b/666402878461d1424cc03cc31a398400131fb5b7
    @@ -50,16 +50,16 @@ class Collection implements Countable, IteratorAggregate {
     	}
    
     	/**
    -	 * return a reference so we can change e.g. sub arrays from this call
    +	 * return a reference, so we can change e.g. sub arrays from this call
     	 *  => cannot use our own get() method.
     	 */
    -	public function __get(string $key): mixed {
    -		if (is_object($this->data[$key]) || $this->data[$key] === null) {
    -			//only actual variables should be returned by reference
    -			return $this->data[$key];
    +	public function &__get(string $key): mixed {
    +		if (!$this->has($key)) {
    +			$null = null;
    +			return $null;
     		}
    
    -		return $this->data[$key] ?? null;
    +		return $this->data[$key];
     	}
    
     	public function clear(): void {
  • Changed file Container.php
    diff --git a/21ee65a51cd70364e05a7f2ea12430f60941afeb b/d6bc6a57128a2919c477cdb80941c7864713ed1d
    index 21ee65a..d6bc6a5 100644
    --- a/21ee65a51cd70364e05a7f2ea12430f60941afeb
    +++ b/d6bc6a57128a2919c477cdb80941c7864713ed1d
    @@ -75,7 +75,6 @@ class Container implements ContainerInterface {
     	 * @template T
     	 * @param class-string<T> $class
     	 * @return T
    -	 * @psalm-suppress InvalidReturnType
     	 * @psalm-suppress InvalidReturnStatement
     	 */
     	public function byType(string $class, ?string $alias = null): object {
  • Changed file ErrorDispatcher.php
    diff --git a/673104a5d862e8b99bf9ee18c0beba4698e5d1cc b/693d31a10cd04f72185098dd3bee63e444aa2e26
    index 673104a..693d31a 100644
    --- a/673104a5d862e8b99bf9ee18c0beba4698e5d1cc
    +++ b/693d31a10cd04f72185098dd3bee63e444aa2e26
    @@ -47,7 +47,6 @@ class ErrorDispatcher {
     	public function __construct() {
     		/**
     		 * @psalm-suppress InvalidArgument
    -		 * @psalm-suppress MissingClosureParamType
     		 */
     		set_error_handler(function (...$args): void {
     			foreach ($this->errorHandlers as $handler) {
    @@ -55,10 +54,6 @@ class ErrorDispatcher {
     			}
     		});
    
    -		/**
    -		 * @psalm-suppress InvalidArgument
    -		 * @psalm-suppress MissingClosureParamType
    -		 */
     		set_exception_handler(function (...$args): void {
     			foreach ($this->exceptionHandlers as $handler) {
     				$handler(...$args);
    @@ -66,7 +61,6 @@ class ErrorDispatcher {
     		});
    
     		/**
    -		 * @psalm-suppress InvalidArgument
     		 * @psalm-suppress MissingClosureParamType
     		 */
     		register_shutdown_function(function (...$args): void {
  • Created new file CollectionTest.php
    <?php
    /**
     * This file is part of the hdev common library package
     * (c) Matthias Lantsch.
     *
     * @license http://www.wtfpl.net/ Do what the fuck you want Public License
     * @author  Matthias Lantsch <[email protected]>
     */
    
    namespace holonet\common\tests;
    
    use holonet\common\collection\Collection;
    use PHPUnit\Framework\TestCase;
    use PHPUnit\Framework\Attributes\CoversClass;
    
    #[CoversClass(Collection::class)]
    class CollectionTest extends TestCase {
    	public function test_constructor_with_initial_data(): void {
    		$initialData = ['foo' => 'bar', 'baz' => 123];
    		$collection = new Collection($initialData);
    
    		$this->assertSame($initialData, $collection->all());
    	}
    
    	public function test_constructor_with_empty_initial_data(): void {
    		$collection = new Collection();
    
    		$this->assertTrue($collection->empty());
    	}
    
    	public function test_set_and_get(): void {
    		$collection = new Collection();
    		$collection->set('key1', 'value1');
    		$collection->key2 = 'value2';
    
    		$this->assertEquals('value1', $collection->key1);
    		$this->assertEquals('value2', $collection->get('key2'));
    		$this->assertNull($collection->NonsensicalKey);
    	}
    
    	public function test_set_with_null_key(): void {
    		$collection = new Collection();
    		$collection->set(null, 'value');
    
    		$this->assertEquals('value', $collection->get(0)); // 0 is the index when the key is null
    	}
    
    	public function test_set_with_null_key_adds_to_the_end(): void {
    		$collection = new Collection(['existingValue']);
    		$collection->set(null, 'newValue');
    
    		$this->assertEquals(['existingValue', 'newValue'], $collection->all());
    	}
    
    	public function test_get_with_default(): void {
    		$collection = new Collection(['existingKey' => 'value']);
    
    		$this->assertEquals('value', $collection->get('existingKey'));
    		$this->assertEquals('default', $collection->get('nonExistingKey', 'default'));
    	}
    
    	public function test_changes_to_magic_method_reads_work(): void {
    		$collection = new Collection(['null' => null, 'object' => new \stdClass(), 'array' => ['key' => 'value']]);
    
    		// make sure the reference to null points nowhere
    		$reference = $collection->null;
    		$reference = 'test';
    		$this->assertNull($collection->get('null'));
    
    		// make sure the reference to the object works as expected
    		$reference = $collection->object;
    		$reference->test = 'test';
    		$this->assertEquals('test', $collection->get('object')->test);
    		$collection->object->test = 'new value';
    		$this->assertEquals('new value', $collection->get('object')->test);
    
    		// make sure the reference to the array works as expected
    		$collection->array['key'] = 'new value';
    		$this->assertEquals(array('key' => 'new value'), $collection->get('array'));
    		$collection->array[] = 'appended';
    		$this->assertEquals(array('key' => 'new value', 'appended'), $collection->get('array'));
    
    		// changes to a subarray
    		$collection = new Collection(['key' => ['subkey' => 'value']]);
    		$collection->key['subkey'] = 'new value';
    
    		$this->assertEquals(['key' => ['subkey' => 'new value']], $collection->all());
    	}
    
    	public function test_has(): void {
    		$collection = new Collection(['existingKey' => 'value']);
    
    		$this->assertTrue($collection->has('existingKey'));
    		$this->assertTrue(isset($collection->existingKey));
    		$this->assertFalse($collection->has('nonExistingKey'));
    		$this->assertFalse(isset($collection->nonExistingKey));
    
    		$collection->set('nullKey', null);
    
    		// behave differently when the value is null
    		// => the key is set but the offset definitely is not "isset"
    		$this->assertTrue($collection->has('nullKey'));
    		$this->assertFalse(isset($collection->nullKey));
    	}
    
    	public function test_remove(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2']);
    		$collection->remove('key1');
    
    		$this->assertEquals(['key2' => 'value2'], $collection->all());
    
    		unset($collection->key2);
    
    		$this->assertEquals([], $collection->all());
    	}
    
    	public function test_clear(): void {
    		$collection = new Collection(['key' => 'value']);
    		$collection->clear();
    
    		$this->assertTrue($collection->empty());
    	}
    
    	public function test_count(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2']);
    
    		$this->assertEquals(2, $collection->count());
    	}
    
    	public function test_empty(): void {
    		$collection = new Collection();
    
    		$this->assertTrue($collection->empty());
    
    		$collection->set('key', 'value');
    
    		$this->assertFalse($collection->empty());
    	}
    
    	public function test_iterator(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2']);
    		$iterator = $collection->getIterator();
    
    		$this->assertEquals(['key1' => 'value1', 'key2' => 'value2'], iterator_to_array($iterator));
    	}
    
    	public function test_merge(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2']);
    		$collection->merge(['key2' => 'newValue2', 'key3' => 'value3']);
    
    		$this->assertEquals(['key1' => 'value1', 'key2' => 'newValue2', 'key3' => 'value3'], $collection->all());
    	}
    
    	public function test_replace(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2']);
    		$collection->replace(['key3' => 'value3']);
    
    		$this->assertEquals(['key3' => 'value3'], $collection->all());
    	}
    
    	public function test_all(): void {
    		$collection = new Collection(['key' => 'value']);
    
    		$this->assertEquals(['key' => 'value'], $collection->all());
    	}
    
    	public function test_filter_param_can_be_used_to_filter_keys(): void {
    		$collection = new Collection(['key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3']);
    
    		$this->assertEquals(['key1' => 'value1', 'key3' => 'value3'], $collection->all(['key1', 'key3']));
    	}
    
    }
  • Changed file ConfigRegistryTest.php
    diff --git a/c8f6b5cb9102a780e073d81b93c3d49b423508bc b/7af8d219d10448638ea998ec46f742b23c21be41
    index c8f6b5c..7af8d21 100644
    --- a/c8f6b5cb9102a780e073d81b93c3d49b423508bc
    +++ b/7af8d219d10448638ea998ec46f742b23c21be41
    @@ -33,7 +33,7 @@ class ConfigRegistryTest extends TestCase {
     		putenv('ENV_VALUE_2=');
     	}
    
    -	public function testEnvPlaceholderReplacement(): void {
    +	public function test_env_placeholder_gets_replaced(): void {
     		$registry = new ConfigRegistry();
     		$registry->setAll(array(
     			'test' => '%env(ENV_VALUE)%',
    @@ -44,7 +44,7 @@ class ConfigRegistryTest extends TestCase {
     		$this->assertSame('test value', $registry->get('test2'));
     	}
    
    -	public function testNormalPlaceholdersStillWork(): void {
    +	public function test_normal_placeholders_still_work(): void {
     		$registry = new ConfigRegistry();
     		$registry->setAll(array(
     			'test' => '%test_prop%',
    @@ -54,7 +54,7 @@ class ConfigRegistryTest extends TestCase {
     		$this->assertSame('cool', $registry->get('test'));
     	}
    
    -	public function testVerifiedDto(): void {
    +	public function test_config_data_can_be_fetched_as_a_verified_dto_object(): void {
     		$this->expectException(BadEnvironmentException::class);
     		$this->expectExceptionMessage('Faulty config with key \'test.testProp\': testProp must be exactly 11 characters long');
    
    @@ -72,7 +72,7 @@ class ConfigRegistryTest extends TestCase {
     		$registry->verifiedDto('test', $dto);
     	}
    
    -	public function testVerifiedDtoTypeError(): void {
    +	public function test_faulty_config_data_fetch_with_dto_object_throws_type_error(): void {
     		$this->expectException(BadEnvironmentException::class);
     		$this->expectExceptionMessage('Faulty config with key \'test\': TypeError: Cannot assign array to property class@anonymous::$testProp of type string');
    
    @@ -90,16 +90,34 @@ class ConfigRegistryTest extends TestCase {
     		$registry->verifiedDto('test', $dto);
     	}
    
    -	public function testVerifiedDtoUsingClass(): void {
    +	public function test_config_data_can_be_fetched_using_an_actual_dto_object_class(): void {
     		$registry = new ConfigRegistry();
     		$registry->set('test', 'amazing value');
    
    -		$dto = $registry->verifiedDto('test', TestDto::class);
    +		$dto = $registry->verifiedDto('test', holonet_common_tests_ConfigRegistryTest_TestDto::class);
     		$this->assertSame('amazing value', $dto->value);
     	}
    +
    +	public function test_accessing_a_non_existing_key_will_throw_a_helpful_exception(): void {
    +		$this->expectException(BadEnvironmentException::class);
    +		$this->expectExceptionMessage('Faulty config with key \'test\': Config item doesn\'t exist');
    +
    +		$registry = new ConfigRegistry();
    +		$registry->asDto('test', holonet_common_tests_ConfigRegistryTest_TestDto::class);
    +	}
    +
    +	public function test_having_an_unset_environment_placeholder_in_a_value_defaults_to_empty_string(): void {
    +		$registry = new ConfigRegistry();
    +		$registry->setAll(array(
    +			'test' => '%env(ENV_VALUE_3)%',
    +		));
    +
    +		$this->assertSame('', $registry->get('test'));
    +	}
    +
     }
    
    -class TestDto {
    +class holonet_common_tests_ConfigRegistryTest_TestDto {
     	public function __construct(
     		#[MinLength(4)]
     		public string $value