diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..45f5e23 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,14 @@ +name: phpstan +on: push +jobs: + phpstan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: php-actions/composer@v6 + with: + dev: yes + - uses: php-actions/phpstan@v3 + with: + memory_limit: 1G + args: --memory-limit 1G diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..c5a182c --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,11 @@ +name: phpunit +on: push +jobs: + phpunit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: php-actions/composer@v6 + with: + dev: yes + - uses: php-actions/phpunit@v3 diff --git a/.gitignore b/.gitignore index 3a9875b..82dac7f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -/vendor/ -composer.lock +/vendor +/composer.lock +/.phpunit.result.cache +/coverage \ No newline at end of file diff --git a/README.md b/README.md index bd6e223..44bbf39 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Flatrr -[![Build Status](https://travis-ci.org/jobyone/flatrr.svg?branch=main)](https://travis-ci.org/jobyone/flatrr) +[![phpstan](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml) +[![phpunit](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml) [![Latest Stable Version](http://poser.pugx.org/byjoby/flatrr/v)](https://packagist.org/packages/byjoby/flatrr) [![Total Downloads](http://poser.pugx.org/byjoby/flatrr/downloads)](https://packagist.org/packages/byjoby/flatrr) [![Latest Unstable Version](http://poser.pugx.org/byjoby/flatrr/v/unstable)](https://packagist.org/packages/byjoby/flatrr) diff --git a/composer.json b/composer.json index 66585af..d37415c 100644 --- a/composer.json +++ b/composer.json @@ -3,12 +3,16 @@ "description": "A library for working with multi-dimensional arrays through flattened keys", "type": "library", "license": "MIT", - "authors": [{ - "name": "Joby Elliott", - "email": "joby@byjoby.com" - }], + "authors": [ + { + "name": "Joby Elliott", + "email": "joby@byjoby.com" + } + ], "require-dev": { - "phpunit/phpunit": "^7.3" + "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^1.9", + "squizlabs/php_codesniffer": "^3.7" }, "autoload": { "psr-4": { @@ -21,12 +25,12 @@ } }, "scripts": { - "test": [ - "phpunit" - ] + "test": "phpunit", + "stan": "phpstan", + "sniff": "phpcs" }, "require": { - "php": ">=7.1", + "php": ">=8.1", "mustangostang/spyc": "^0.6.3" } -} +} \ No newline at end of file diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..32ec211 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,19 @@ + + + Coding Standard + + src + + + + + + + + + + + + + \ No newline at end of file diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..3ff6fa8 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + level: 7 + paths: + - src \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 89c010e..bc2f7c1 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,31 @@ - + + + + + + + - - tests + + tests/ - + + + src + + + + + + \ No newline at end of file diff --git a/src/Config/Config.php b/src/Config/Config.php index 33c5987..7d951ff 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -1,5 +1,6 @@ readFile($f, $name, $overwrite); + if ($dir && is_dir($dir)) { + $glob = glob("$dir/*"); + if ($glob) { + foreach ($glob as $f) { + if (is_file($f)) { + $this->readFile($f, $name, $overwrite); + } + } } } + return $this; } - protected function parse(string $input, string $format): array + public function json(bool $raw = false): string { - $fn = 'parse_' . $format; - if (!method_exists($this, $fn)) { - if ($this->strict) { - throw new \Exception("Don't know how to parse the format \"$format\""); - } else { - return null; - } - } - if ($out = $this->$fn($input)) { - return $out; - } - return array(); + return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT); // @phpstan-ignore-line } - protected function parse_yaml($input) - { - return Spyc::YAMLLoadString($input); - } - - public function json($raw = false): string - { - return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT); - } - - public function yaml($raw = false): string + public function yaml(bool $raw = false): string { return Spyc::YAMLDump($this->get(null, $raw), 2); } - protected function read_ini($filename) + /** @return array */ + protected function read_ini(string $filename): false|array { return parse_ini_file($filename, true); } - protected function read_json($filename) + /** @return array */ + protected function read_json(string $filename): null|array { - return json_decode(file_get_contents($filename), true); + /** @var string */ + $data = file_get_contents($filename); + return json_decode($data, true); } - protected function read_yaml($filename) + /** @return array */ + protected function read_yaml(string $filename): array { return Spyc::YAMLLoad($filename); } - protected function read_yml($filename) + /** @return array */ + protected function read_yml(string $filename): array { return $this->read_yaml($filename); } - public function readFile($filename, string $name = null, bool $overwrite = false) + public function readFile(string $filename, string $name = null, bool $overwrite = false): static { - if (!is_file($filename) || !is_readable($filename)) { - if ($this->strict) { - throw new \Exception("Couldn't read config file \"$filename\""); - } else { - return null; - } - } $format = strtolower(preg_replace('/.+\./', '', $filename)); $fn = 'read_' . $format; - if (!method_exists($this, $fn)) { - if ($this->strict) { - throw new \Exception("Don't know how to read the format \"$format\""); - } else { - return null; + if (is_file($filename) && is_readable($filename) && method_exists($this, $fn)) { + $data = $this->$fn($filename); + if ($data !== null) { + $this->merge($data, $name, $overwrite); } } - $data = $this->$fn($filename); - if (!$data) { - if ($this->strict) { - throw new \Exception("Error reading \"" . $filename . "\""); - } else { - return null; - } - } - $this->merge($data, $name, $overwrite); + return $this; } } diff --git a/src/Config/ConfigInterface.php b/src/Config/ConfigInterface.php index 5fff574..5975f9a 100644 --- a/src/Config/ConfigInterface.php +++ b/src/Config/ConfigInterface.php @@ -1,12 +1,17 @@ $data + * @return void + */ + public function __construct(null|array $data = null) { $this->merge($data); } diff --git a/src/FlatArrayInterface.php b/src/FlatArrayInterface.php index f4da1ef..ac4a23c 100644 --- a/src/FlatArrayInterface.php +++ b/src/FlatArrayInterface.php @@ -1,16 +1,25 @@ + * @extends Iterator + */ +interface FlatArrayInterface extends ArrayAccess, Iterator +{ + public function set(null|string $name, mixed $value): mixed; + public function get(null|string $name = null): mixed; + public function unset(null|string $name): static; + public function merge(mixed $value, string $name = null, bool $overwrite = false): static; + + public function push(null|string $name, mixed $value): static; + public function pop(null|string $name): mixed; + public function unshift(null|string $name, mixed $value): static; + public function shift(null|string $name): mixed; } diff --git a/src/FlatArrayTrait.php b/src/FlatArrayTrait.php index 3225986..b79be8e 100644 --- a/src/FlatArrayTrait.php +++ b/src/FlatArrayTrait.php @@ -1,117 +1,126 @@ */ + protected $_arrayData = []; + /** @var array */ + protected $_flattenCache = []; - public function push(?string $name, $value) + public function push(null|string $name, mixed $value): static { $arr = $this->flattenSearch($name); if ($arr !== null && !is_array($arr)) { - return; + return $this; } if ($arr === null) { $arr = []; } $arr[] = $value; $this->set($name, $arr); + return $this; } - public function pop(?string $name) + public function pop(null|string $name): mixed { $arr = $this->flattenSearch($name); if ($arr !== null && !is_array($arr)) { - return; + return null; } $out = array_pop($arr); + $this->unset($name); $this->set($name, $arr); return $out; } - public function unshift(?string $name, $value) + public function unshift(null|string $name, mixed $value): static { $arr = $this->flattenSearch($name); if ($arr !== null && !is_array($arr)) { - return; + return $this; } if ($arr === null) { $arr = []; } array_unshift($arr, $value); $this->set($name, $arr); + return $this; } - public function shift(?string $name) + public function shift(null|string $name): mixed { $arr = $this->flattenSearch($name); if ($arr !== null && !is_array($arr)) { - return; + return null; } $out = array_shift($arr); + $this->unset($name); $this->set($name, $arr); return $out; } - public function set(?string $name, $value) + public function set(null|string $name, mixed $value): static { - return $this->flattenSearch($name, $value); + $this->flattenSearch($name, $value); + return $this; } - public function get(?string $name = null) + public function get(null|string $name = null): mixed { return $this->flattenSearch($name); } - function unset(?string $name) + public function unset(null|string $name): static { $this->flattenSearch($name, null, true); + return $this; } - public function offsetSet($name, $value) + public function offsetSet($name, $value): void { - return $this->set($name, $value); + $this->set($name, $value); } - public function offsetGet($name) + public function offsetGet($name): mixed { return $this->get($name); } - public function offsetExists($name) + public function offsetExists($name): bool { return $this->flattenSearch($name) !== null; } - public function offsetUnset($name) + public function offsetUnset($name): void { $this->unset($name); } - public function rewind() + public function rewind(): void { - return reset($this->_arrayData); + reset($this->_arrayData); } - public function current() + public function current(): mixed { return current($this->_arrayData); } - public function next() + public function next(): void { - return next($this->_arrayData); + next($this->_arrayData); } - public function key() + public function key(): null|string|int { return key($this->_arrayData); } - public function valid() + public function valid(): bool { return isset($this->_arrayData[$this->key()]); } @@ -120,12 +129,11 @@ trait FlatArrayTrait * Recursively set a value, with control over whether existing values or new * values take precedence */ - public function merge($value, string $name = null, bool $overwrite = false) + public function merge(mixed $value, string $name = null, bool $overwrite = false): static { if (!isset($this[$name])) { //easiest possible outcome, old value doesn't exist, so we can just write the value $this->set($name, $value); - return; } elseif (is_array($value) && is_array($this->flattenSearch($name))) { //both new and old values are arrays foreach ($value as $k => $v) { @@ -134,14 +142,13 @@ trait FlatArrayTrait } $this->merge($v, $k, $overwrite); } - return; } else { //old and new values exist, and one or both are not arrays, $overwrite rules the day if ($overwrite) { $this->set($name, $value); } - return; } + return $this; } /** @@ -149,10 +156,10 @@ trait FlatArrayTrait * string. It sets it if $value exists, otherwise it returns the value if it * exists. */ - protected function flattenSearch(?string $name, $value = null, $unset = false) + protected function flattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed { if ($value !== null || $unset) { - $this->_flattenCache = array(); + $this->_flattenCache = []; } if (!isset($this->_flattenCache[$name])) { $this->_flattenCache[$name] = $this->doFlattenSearch($name, $value, $unset); @@ -160,7 +167,7 @@ trait FlatArrayTrait return $this->_flattenCache[$name]; } - protected function doFlattenSearch(?string $name, $value = null, $unset = false) + protected function doFlattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed { //check for home strings if ($name == '' || $name === null) { @@ -178,7 +185,7 @@ trait FlatArrayTrait if ($value !== null) { foreach ($name as $part) { if (!isset($parent[$part])) { - $parent[$part] = array(); + $parent[$part] = []; } $parent = &$parent[$part]; } @@ -199,9 +206,9 @@ trait FlatArrayTrait //both value and destination are arrays, merge them $parent[$key] = array_replace_recursive($parent[$key], $value); } else { - //set the hard way - if (!is_array($parent)) { - $parent = array(); + //destination is not an array, to set this we must overwrite it with an empty array + if (!is_array(@$parent[$key])) { + $parent[$key] = []; } $parent[$key] = $value; } diff --git a/src/SelfReferencingFlatArray.php b/src/SelfReferencingFlatArray.php index be12251..ecbe8c4 100644 --- a/src/SelfReferencingFlatArray.php +++ b/src/SelfReferencingFlatArray.php @@ -1,13 +1,15 @@ */ protected $cache = []; - public function get(string $name = null, bool $raw = false, $unescape = true) + public function get(string $name = null, bool $raw = false, bool $unescape = true): mixed { $out = parent::get($name); if ($raw) { @@ -20,48 +22,29 @@ class SelfReferencingFlatArray extends FlatArray return $out; } - public function set(?string $name, $value) + public function set(null|string $name, mixed $value): static { $this->cache = []; - return $this->filter(parent::set($name, $value)); + $this->filter(parent::set($name, $value)); + return $this; } - public function push(?string $name, $value) - { - return $this->filter(parent::push($name, $value)); - } - - public function pop(?string $name) + public function pop(null|string $name): mixed { return $this->filter(parent::pop($name)); } - public function unshift(?string $name, $value) - { - return $this->filter(parent::unshift($name, $value)); - } - - public function shift(?string $name) + public function shift(null|string $name): mixed { return $this->filter(parent::shift($name)); } - public function rewind() - { - return $this->filter(parent::rewind()); - } - - public function next() - { - return $this->filter(parent::next()); - } - - public function current() + public function current(): mixed { return $this->filter(parent::current()); } - protected function unescape($value) + protected function unescape(mixed $value): mixed { //map this function onto array values if (is_array($value)) { @@ -88,7 +71,7 @@ class SelfReferencingFlatArray extends FlatArray /** * Recursively replace ${var/name} type strings in string values with */ - protected function filter($value) + protected function filter(mixed $value): mixed { //map this function onto array values if (is_array($value)) { @@ -114,9 +97,14 @@ class SelfReferencingFlatArray extends FlatArray return $value; } - protected function filter_regex($matches) + /** + * @param array $matches + * @return string + */ + protected function filter_regex(array $matches): string { - if (null !== $value = $this->get($matches[1], false, false)) { + $value = $this->get($matches[1], false, false); + if ($value !== null) { if (!is_array($value)) { return $value; } diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 54edc70..f12abde 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -1,6 +1,8 @@ readFile(__DIR__.'/configtest.json'); + $a->readFile(__DIR__ . '/configtest.json'); $this->assertEquals($data, $a->get()); //yaml $a = new Config(); - $a->readFile(__DIR__.'/configtest.yaml'); + $a->readFile(__DIR__ . '/configtest.yaml'); $this->assertEquals($data, $a->get()); + //nonexistant files + $a = new Config(); + $a->readFile(__DIR__ . '/does-not-exist.json'); + $a->readFile(__DIR__ . '/does-not-exist.yaml'); + $this->assertEquals([], $a->get()); } public function testSerializing() @@ -52,4 +59,16 @@ class ConfigTest extends TestCase //yaml $this->assertEquals($data, Spyc::YAMLLoad($c->yaml())); } + + public function testReadingDirectory() + { + $config = new Config; + $config->readDir(__DIR__ . '/nonexistantdir'); + $this->assertEquals([], $config->get()); + $config->readDir(__DIR__ . '/configtestdir'); + $this->assertEquals('b', $config['ini_file.a']); + $this->assertEquals('a', $config['yaml_file']); + $this->assertEquals('a', $config['json_file']); + $this->assertEquals('a', $config['yml_file']); + } } diff --git a/tests/Config/configtestdir/inifile.ini b/tests/Config/configtestdir/inifile.ini new file mode 100644 index 0000000..2aca6aa --- /dev/null +++ b/tests/Config/configtestdir/inifile.ini @@ -0,0 +1,2 @@ +[ini_file] +a = b \ No newline at end of file diff --git a/tests/Config/configtestdir/jsonfile.json b/tests/Config/configtestdir/jsonfile.json new file mode 100644 index 0000000..f5a5513 --- /dev/null +++ b/tests/Config/configtestdir/jsonfile.json @@ -0,0 +1,3 @@ +{ + "json_file": "a" +} \ No newline at end of file diff --git a/tests/Config/configtestdir/yamlfile.yaml b/tests/Config/configtestdir/yamlfile.yaml new file mode 100644 index 0000000..089ce12 --- /dev/null +++ b/tests/Config/configtestdir/yamlfile.yaml @@ -0,0 +1 @@ +yaml_file: a \ No newline at end of file diff --git a/tests/Config/configtestdir/ymlfile.yml b/tests/Config/configtestdir/ymlfile.yml new file mode 100644 index 0000000..788a785 --- /dev/null +++ b/tests/Config/configtestdir/ymlfile.yml @@ -0,0 +1 @@ +yml_file: a diff --git a/tests/FlatArrayPushPopTest.php b/tests/FlatArrayPushPopTest.php index 5acdaf2..1afd689 100644 --- a/tests/FlatArrayPushPopTest.php +++ b/tests/FlatArrayPushPopTest.php @@ -1,6 +1,8 @@ push(null, 'foo'); $f->push(null, 'bar'); - $this->assertEquals(['foo','bar'], $f->get()); + $this->assertEquals(['foo', 'bar'], $f->get()); $this->assertEquals('bar', $f->pop(null)); $this->assertEquals(['foo'], $f->get()); $this->assertEquals('foo', $f->pop(null)); $this->assertEquals([], $f->get()); + $this->assertNull($f->pop(null)); + } + + public function testPushIndexCreation() + { + // pushing to a nonexistent index creates it as an array + $f = new FlatArray(); + $f->push('a.b', 'c'); + $this->assertEquals(['c'], $f['a.b']); + $this->assertEquals(['a' => ['b' => ['c']]], $f->get()); + // pushing to an existing non-array index does nothing + $f = new FlatArray(['a' => 'b']); + $f->push('a', 'c'); + $this->assertEquals(['a' => 'b'], $f->get()); + // poping off a non-array does nothing + $this->assertNull($f->pop('a')); } public function testShiftUnshift() @@ -24,10 +42,25 @@ class FlatArrayPushPopTest extends TestCase $f = new FlatArray(); $f->unshift(null, 'foo'); $f->unshift(null, 'bar'); - $this->assertEquals(['bar','foo'], $f->get()); + $this->assertEquals(['bar', 'foo'], $f->get()); $this->assertEquals('bar', $f->shift(null)); $this->assertEquals(['foo'], $f->get()); $this->assertEquals('foo', $f->shift(null)); $this->assertEquals([], $f->get()); } + + public function testUnshiftIndexCreation() + { + // unshifting to a nonexistent index creates it as an array + $f = new FlatArray(); + $f->unshift('a.b', 'c'); + $this->assertEquals(['c'], $f['a.b']); + $this->assertEquals(['a' => ['b' => ['c']]], $f->get()); + // unshifting to an existing non-array index does nothing + $f = new FlatArray(['a' => 'b']); + $f->unshift('a', 'c'); + $this->assertEquals(['a' => 'b'], $f->get()); + // shifting off a non-array does nothing + $this->assertNull($f->shift('a')); + } } diff --git a/tests/FlatArrayTest.php b/tests/FlatArrayTest.php index 81b42db..7268e9c 100644 --- a/tests/FlatArrayTest.php +++ b/tests/FlatArrayTest.php @@ -1,6 +1,8 @@ 'A', - 'b' => ['c'=>'C'] + 'b' => ['c' => 'C'] ]; $a = new FlatArray($data); //first level @@ -21,8 +23,8 @@ class FlatArrayTest extends TestCase $this->assertEquals('C', $a['b.c']); $this->assertEquals('C', $a->get('b.c')); //returning array - $this->assertEquals(['c'=>'C'], $a['b']); - $this->assertEquals(['c'=>'C'], $a->get('b')); + $this->assertEquals(['c' => 'C'], $a['b']); + $this->assertEquals(['c' => 'C'], $a->get('b')); //returning entire array by requesting null or empty string $this->assertEquals($data, $a[null]); $this->assertEquals($data, $a->get()); @@ -62,7 +64,7 @@ class FlatArrayTest extends TestCase { $data = [ 'a' => 'A', - 'b' => ['c'=>'C'] + 'b' => ['c' => 'C'] ]; $a = new FlatArray($data); //setting on first layer @@ -91,7 +93,7 @@ class FlatArrayTest extends TestCase public function testSettingFalseyValues() { - $a = new FlatArray(['foo'=>['bar'=>'baz']]); + $a = new FlatArray(['foo' => ['bar' => 'baz']]); $a['foo.bar'] = false; $this->assertFalse($a['foo.bar']); $a['foo.bar'] = 0; @@ -104,21 +106,21 @@ class FlatArrayTest extends TestCase public function testMerginFalseyValues() { - $a = new FlatArray(['foo'=>['bar'=>'baz']]); - $a->merge(['foo'=>['bar'=>false]], null, true); + $a = new FlatArray(['foo' => ['bar' => 'baz']]); + $a->merge(['foo' => ['bar' => false]], null, true); $this->assertFalse($a['foo.bar']); - $a->merge(['foo'=>['bar'=>0]], null, true); + $a->merge(['foo' => ['bar' => 0]], null, true); $this->assertSame(0, $a['foo.bar']); - $a->merge(['foo'=>['bar'=>'']], null, true); + $a->merge(['foo' => ['bar' => '']], null, true); $this->assertSame('', $a['foo.bar']); - $a->merge(['foo'=>['bar'=>[]]], null, true); + $a->merge(['foo' => ['bar' => []]], null, true); $this->assertSame([], $a['foo.bar']); } public function testCaseSensitivity() { $h = new FlatArray([ - 'ABC'=>['ABC'=>'ABC'] + 'ABC' => ['ABC' => 'ABC'] ]); $this->assertNull($h['abc.abc']); $this->assertNull($h['Abc.aBC']); @@ -126,7 +128,7 @@ class FlatArrayTest extends TestCase public function testAccidentalSubstrings() { - $h = new FlatArray(['foo'=>'bar']); + $h = new FlatArray(['foo' => 'bar']); $this->assertNull($h['foo.baz']); } @@ -169,7 +171,7 @@ class FlatArrayTest extends TestCase //overwrite false with mismatched array-ness $c = new FlatArray($data); $c->merge([ - 'a' => ['b'=>'c'], + 'a' => ['b' => 'c'], 'c' => 'd' ]); $this->assertEquals('b', $c['a']); @@ -177,21 +179,116 @@ class FlatArrayTest extends TestCase //overwrite true with mismatched array-ness $c = new FlatArray($data); $c->merge([ - 'a' => ['b'=>'c'], + 'a' => ['b' => 'c'], 'c' => 'd' ], null, true); $this->assertEquals('c', $c['a.b']); $this->assertEquals('d', $c['c']); } + public function testMergeViaSet() + { + $arr = new FlatArray([ + 'a' => [ + 'a' => 'b', + 'c' => 'd' + ] + ]); + $arr->set('a', [ + 'e' => 'f', + 'g' => 'h' + ]); + $this->assertEquals( + [ + 'a' => [ + 'a' => 'b', + 'c' => 'd', + 'e' => 'f', + 'g' => 'h' + ] + ], + $arr->get() + ); + } + + public function testNoMergeRootViaSet() + { + $arr = new FlatArray([ + 'a' => 'b', + 'c' => 'd' + ]); + $arr->set(null, [ + 'e' => 'f', + 'g' => 'h' + ]); + $this->assertEquals( + [ + 'e' => 'f', + 'g' => 'h' + ], + $arr->get() + ); + } + + public function testMergeViaSetOverNonArray() + { + $arr = new FlatArray([ + 'a' => 'b' + ]); + $arr->set('a', [ + 'e' => 'f', + 'g' => 'h' + ]); + $this->assertEquals( + [ + 'a' => [ + 'e' => 'f', + 'g' => 'h' + ] + ], + $arr->get() + ); + } + public function testConstructionUnflattening() { $arr = new FlatArray([ 'foo.bar' => 'baz' ]); $this->assertEquals( - ['foo'=>['bar'=>'baz']], + ['foo' => ['bar' => 'baz']], $arr->get() ); } + + public function testUnset() + { + $arr = new FlatArray([ + 'a' => [ + 'b' => 'c', + 'd' => 'e' + ] + ]); + unset($arr['a.b']); + $this->assertEquals([ + 'a' => [ + 'd' => 'e' + ] + ], $arr->get()); + // unset root + $arr->unset(null); + $this->assertEquals([], $arr->get()); + } + + public function testForeach() + { + $reference = [ + 'b' => 'c', + 'd' => 'e' + ]; + $arr = new FlatArray($reference); + foreach ($arr as $key => $value) { + $this->assertEquals($reference[$key], $value); + } + } } diff --git a/tests/SelfReferencingFlatArrayTest.php b/tests/SelfReferencingFlatArrayTest.php index 7e3b35c..da99489 100644 --- a/tests/SelfReferencingFlatArrayTest.php +++ b/tests/SelfReferencingFlatArrayTest.php @@ -1,6 +1,8 @@ 'bar', - 'bar' => ['baz'=>'qux'], + 'bar' => ['baz' => 'qux'], 'test' => [ 'foo' => '${foo}', 'bar' => '${bar.baz}', @@ -49,11 +51,13 @@ class SelfReferencingFlatArrayTest extends TestCase $this->assertEquals('${foo}', $f['nested.escaped.full']); $this->assertEquals('${foo}', $f['nested.escaped.left']); $this->assertEquals('${foo}', $f['nested.escaped.right']); + //raw + $this->assertEquals('${foo}', $f->get('test.foo', true)); } public function testSettingFalseyValues() { - $a = new SelfReferencingFlatArray(['foo'=>['bar'=>'baz']]); + $a = new SelfReferencingFlatArray(['foo' => ['bar' => 'baz']]); $a['foo.bar'] = false; $this->assertFalse($a['foo.bar']); $a['foo.bar'] = 0; @@ -64,16 +68,53 @@ class SelfReferencingFlatArrayTest extends TestCase $this->assertSame([], $a['foo.bar']); } - public function testMerginFalseyValues() + public function testMergingFalseyValues() { - $a = new SelfReferencingFlatArray(['foo'=>['bar'=>'baz']]); - $a->merge(['foo'=>['bar'=>false]], null, true); + $a = new SelfReferencingFlatArray(['foo' => ['bar' => 'baz']]); + $a->merge(['foo' => ['bar' => false]], null, true); $this->assertFalse($a['foo.bar']); - $a->merge(['foo'=>['bar'=>0]], null, true); + $a->merge(['foo' => ['bar' => 0]], null, true); $this->assertSame(0, $a['foo.bar']); - $a->merge(['foo'=>['bar'=>'']], null, true); + $a->merge(['foo' => ['bar' => '']], null, true); $this->assertSame('', $a['foo.bar']); - $a->merge(['foo'=>['bar'=>[]]], null, true); + $a->merge(['foo' => ['bar' => []]], null, true); $this->assertSame([], $a['foo.bar']); } + + public function testForeach() + { + $reference = [ + 'a' => 'b', + 'b' => '${a}', + 'd' => '${b}' + ]; + $arr = new SelfReferencingFlatArray($reference); + foreach ($arr as $key => $value) { + $this->assertEquals('b', $value); + } + } + + public function testPop() + { + $f = new SelfReferencingFlatArray([ + 'a' => 'b', + 'c' => [ + '${a}' + ] + ]); + $this->assertEquals('b', $f->pop('c')); + $this->assertNull($f->pop('c')); + } + + public function testShift() + { + $f = new SelfReferencingFlatArray([ + 'a' => 'b', + 'c' => [ + '${a}' + ] + ]); + $this->assertEquals('b', $f->shift('c')); + $this->assertNull($f->shift('c')); + } }