Passed
Push — master ( e6d102...7dc300 )
by Eric
12:39
created

ArraysTest::testIsAssociative()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Utility - Collection of various PHP utility functions.
7
 *
8
 * @author    Eric Sizemore <[email protected]>
9
 * @version   2.0.0
10
 * @copyright (C) 2017 - 2024 Eric Sizemore
11
 * @license   The MIT License (MIT)
12
 *
13
 * Copyright (C) 2017 - 2024 Eric Sizemore <https://www.secondversion.com>.
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to
17
 * deal in the Software without restriction, including without limitation the
18
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19
 * sell copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in
23
 * all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
 * THE SOFTWARE.
32
 */
33
34
namespace Esi\Utility\Tests;
35
36
use Esi\Utility\Arrays;
37
use PHPUnit\Framework\TestCase;
38
use PHPUnit\Framework\Attributes\CoversClass;
39
40
use ArrayAccess;
41
use stdClass;
42
43
use function is_null;
44
45
/**
46
 * Array utilities tests.
47
 */
48
#[CoversClass(Arrays::class)]
49
class ArraysTest extends TestCase
50
{
51
    /**
52
     * Test Arrays::isAssociative().
53
     */
54
    public function testIsAssociative(): void
55
    {
56
        $array = [0, 1, 2, 3, 4];
57
        $arrayTwo = ['test' => 'testing', 'testing' => 'what'];
58
59
        self::assertFalse(Arrays::isAssociative($array));
60
        self::assertTrue(Arrays::isAssociative($arrayTwo));
61
    }
62
63
    /**
64
     * Test Arrays::get().
65
     */
66
    public function testGet(): void
67
    {
68
        $array = ['this' => 'is', 'a' => 'test'];
69
70
        self::assertEquals('is', Arrays::get($array, 'this'));
71
        self::assertEquals('test', Arrays::get($array, 'a'));
72
        self::assertEquals(null, Arrays::get($array, 'notexist'));
73
    }
74
75
    /**
76
     * Test Arrays::set().
77
     */
78
    public function testSet(): void
79
    {
80
        $array = ['this' => 1, 'is' => 2, 'a' => 3, 'test' => 4];
81
        $newArray = ['that' => 4, 'was' => 3, 'a' => 2, 'test' => 1];
82
83
        Arrays::set($array, 'test', 5);
84
        self::assertEquals(5, Arrays::get($array, 'test'));
85
86
        Arrays::set($array, null, $newArray);
87
        self::assertEquals(4, Arrays::get($array, 'that'));
88
    }
89
90
    /**
91
     * Test Arrays::exists().
92
     */
93
    public function testExists(): void
94
    {
95
        $array = ['test' => 1];
96
97
        $arrayAccess = new TestArrayAccess();
98
        $arrayAccess['test'] = 1;
99
100
        self::assertTrue(Arrays::exists($array, 'test'));
101
        self::assertFalse(Arrays::exists($array, 'this'));
102
103
        self::assertTrue(Arrays::exists($arrayAccess, 'test'));
104
        self::assertFalse(Arrays::exists($arrayAccess, 'this'));
105
    }
106
107
    /**
108
     * Test Arrays::flatten().
109
     */
110
    public function testFlatten(): void
111
    {
112
        self::assertEquals([
113
            0 => 'a',
114
            1 => 'b',
115
            2 => 'c',
116
            3 => 'd',
117
            '4.first'   => 'e',
118
            '4.0'       => 'f',
119
            '4.second'  => 'g',
120
            '4.1.0'     => 'h',
121
            '4.1.third' => 'i',
122
        ], Arrays::flatten([
123
            'a', 'b', 'c', 'd', ['first' => 'e', 'f', 'second' => 'g', ['h', 'third' => 'i']],
124
        ]));
125
126
        self::assertEquals(
127
            [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd', '4.0' => 'e', '4.1' => 'f', '4.2' => 'g'],
128
            Arrays::flatten(['a', 'b', 'c', 'd', ['e', 'f', 'g']])
129
        );
130
131
        self::assertEquals(
132
            ['k0' => 'a', 'k1' => 'b', 'k2' => 'c', 'k3' => 'd', 'k4.0' => 'e', 'k4.1' => 'f', 'k4.2' => 'g'],
133
            Arrays::flatten(['a', 'b', 'c', 'd', ['e', 'f', 'g']], '.', 'k')
134
        );
135
    }
136
137
    /**
138
     * Test Arrays::mapDeep().
139
     */
140
    public function testMapDeep(): void
141
    {
142
        self::assertEquals([
143
            '&lt;',
144
            'abc',
145
            '&gt;',
146
            'def',
147
            ['&amp;', 'test', '123'],
148
        ], Arrays::mapDeep([
149
            '<',
150
            'abc',
151
            '>',
152
            'def',
153
            ['&', 'test', '123'],
154
        ], 'htmlentities'));
155
156
        $var = new stdClass();
157
        $var->test = ['test' => '>'];
158
        $var->what = '<';
159
160
        $var2 = new stdClass();
161
        $var2->test = ['test' => '&gt;'];
162
        $var2->what = '&lt;';
163
164
        self::assertEquals($var2, Arrays::mapDeep($var, 'htmlentities'));
165
    }
166
167
    /**
168
     * Test Arrays::interlace().
169
     */
170
    public function testInterlace(): void
171
    {
172
        $input = Arrays::interlace([1, 2, 3], ['a', 'b', 'c']);
173
        $expect = [1, 'a', 2, 'b', 3, 'c'];
174
175
        self::assertEquals($expect, $input);
176
177
        // With no arguments
178
        self::assertFalse(Arrays::interlace());
179
180
        // With one argument
181
        self::assertEquals([1, 2, 3], Arrays::interlace([1, 2, 3]));
182
    }
183
184
    /**
185
     * Test Arrays::groupBy().
186
     */
187
    public function testGroupBy(): void
188
    {
189
        $result = Arrays::groupBy([
190
            ['id' => 1, 'category' => 'A', 'value' => 'foo'],
191
            ['id' => 2, 'category' => 'B', 'value' => 'bar'],
192
            ['id' => 3, 'category' => 'A', 'value' => 'baz'],
193
            ['id' => 4, 'category' => 'B', 'value' => 'qux'],
194
        ], 'category');
195
196
        $expected = [
197
            'A' => [
198
                ['id' => 1, 'category' => 'A', 'value' => 'foo'],
199
                ['id' => 3, 'category' => 'A', 'value' => 'baz'],
200
            ],
201
            'B' => [
202
                ['id' => 2, 'category' => 'B', 'value' => 'bar'],
203
                ['id' => 4, 'category' => 'B', 'value' => 'qux'],
204
            ],
205
        ];
206
207
        self::assertSame($expected, $result);
208
    }
209
210
    /**
211
     * Test Arrays::groupBy() with non-existent/invalid key.
212
     */
213
    public function testGroupByInvalidKey(): void
214
    {
215
        $result = Arrays::groupBy([
216
            ['id' => 1, 'category' => 'A', 'value' => 'foo'],
217
            ['id' => 2, 'category' => 'B', 'value' => 'bar'],
218
            ['id' => 3, 'category' => 'A', 'value' => 'baz'],
219
            ['id' => 4, 'category' => 'B', 'value' => 'qux'],
220
        ], 'notakey');
221
222
        $expected = [];
223
224
        self::assertSame($expected, $result);
225
    }
226
}
227
228
/**
229
 * @implements ArrayAccess<mixed, mixed>
230
 */
231
class TestArrayAccess implements ArrayAccess
232
{
233
    /**
234
     * @var array<int|string, mixed>
235
     */
236
    public array $container = [
237
        'one'   => 1,
238
        'two'   => 2,
239
        'three' => 3,
240
    ];
241
242
    /**
243
     * Set an offset.
244
     *
245
     */
246
    #[\Override]
247
    public function offsetSet(mixed $offset, mixed $value): void
248
    {
249
        if (is_null($offset)) {
250
            $this->container[] = $value;
251
        } else {
252
            $this->container[$offset] = $value;
253
        }
254
    }
255
256
    /**
257
     * Whether an offset exists.
258
     *
259
     * @return bool
260
     */
261
    #[\Override]
262
    public function offsetExists(mixed $offset): bool
263
    {
264
        return isset($this->container[$offset]);
265
    }
266
267
    /**
268
     * Unset an offset.
269
     *
270
     */
271
    #[\Override]
272
    public function offsetUnset(mixed $offset): void
273
    {
274
        unset($this->container[$offset]);
275
    }
276
277
    /**
278
     * Retrieve an offset exists.
279
     *
280
     * @return mixed
281
     */
282
    #[\Override]
283
    public function offsetGet(mixed $offset): mixed
284
    {
285
        return $this->container[$offset] ?? null;
286
    }
287
}
288