Passed
Push — master ( 93b1f5...93d042 )
by Eric
14:02 queued 01:23
created

ArraysTest::testKeyExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 12
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
 * @internal
48
 */
49
#[CoversClass(Arrays::class)]
50
class ArraysTest extends TestCase
51
{
52
    /**
53
     * Test Arrays::isAssociative().
54
     */
55
    public function testIsAssociative(): void
56
    {
57
        $array    = [0, 1, 2, 3, 4];
58
        $arrayTwo = ['test' => 'testing', 'testing' => 'what'];
59
60
        self::assertFalse(Arrays::isAssociative($array));
61
        self::assertTrue(Arrays::isAssociative($arrayTwo));
62
    }
63
64
    /**
65
     * Test Arrays::get().
66
     */
67
    public function testGet(): void
68
    {
69
        $array = ['this' => 'is', 'a' => 'test'];
70
71
        self::assertSame('is', Arrays::get($array, 'this'));
72
        self::assertSame('test', Arrays::get($array, 'a'));
73
        self::assertNull(Arrays::get($array, 'notexist'));
74
    }
75
76
    /**
77
     * Test Arrays::set().
78
     */
79
    public function testSet(): void
80
    {
81
        $array    = ['this' => 1, 'is' => 2, 'a' => 3, 'test' => 4];
82
        $newArray = ['that' => 4, 'was' => 3, 'a' => 2, 'test' => 1];
83
84
        Arrays::set($array, 'test', 5);
85
        self::assertSame(5, Arrays::get($array, 'test'));
86
87
        Arrays::set($array, null, $newArray);
88
        self::assertSame(4, Arrays::get($array, 'that'));
89
    }
90
91
    /**
92
     * Test Arrays::keyExists().
93
     */
94
    public function testKeyExists(): void
95
    {
96
        $array = ['test' => 1];
97
98
        $arrayAccess         = new TestArrayAccess();
99
        $arrayAccess['test'] = 1;
100
101
        self::assertTrue(Arrays::keyExists($array, 'test'));
102
        self::assertFalse(Arrays::keyExists($array, 'this'));
103
104
        self::assertTrue(Arrays::keyExists($arrayAccess, 'test'));
105
        self::assertFalse(Arrays::keyExists($arrayAccess, 'this'));
106
    }
107
108
    /**
109
     * Test Arrays::valueExists().
110
     */
111
    public function testValueExists(): void
112
    {
113
        $array = ['test' => 1, 1 => 'foo', 'bar' => 2];
114
115
        self::assertTrue(Arrays::valueExists($array, 1));
116
        self::assertFalse(Arrays::valueExists($array, 'test'));
117
118
        self::assertTrue(Arrays::valueExists($array, 'foo'));
119
        self::assertFalse(Arrays::valueExists($array, 'bar'));
120
    }
121
122
    public function testExistsDeprecation(): void
123
    {
124
        $array = ['test' => 1];
125
126
        $arrayAccess         = new TestArrayAccess();
127
        $arrayAccess['test'] = 1;
128
129
        $this->expectUserDeprecationMessage('Esi\Utility\Arrays::exists is deprecated and will be removed in v2.1.0, use Esi\Utility\Arrays::keyExists instead.');
130
        self::assertTrue(Arrays::exists($array, 'test'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Arrays::exists() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

130
        self::assertTrue(/** @scrutinizer ignore-deprecated */ Arrays::exists($array, 'test'));
Loading history...
131
        self::assertFalse(Arrays::exists($array, 'this'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Arrays::exists() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

131
        self::assertFalse(/** @scrutinizer ignore-deprecated */ Arrays::exists($array, 'this'));
Loading history...
132
133
        self::assertTrue(Arrays::exists($arrayAccess, 'test'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Arrays::exists() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

133
        self::assertTrue(/** @scrutinizer ignore-deprecated */ Arrays::exists($arrayAccess, 'test'));
Loading history...
134
        self::assertFalse(Arrays::exists($arrayAccess, 'this'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Arrays::exists() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

134
        self::assertFalse(/** @scrutinizer ignore-deprecated */ Arrays::exists($arrayAccess, 'this'));
Loading history...
135
    }
136
137
    /**
138
     * Test Arrays::flatten().
139
     */
140
    public function testFlatten(): void
141
    {
142
        self::assertSame([
143
            0           => 'a',
144
            1           => 'b',
145
            2           => 'c',
146
            3           => 'd',
147
            '4.first'   => 'e',
148
            '4.0'       => 'f',
149
            '4.second'  => 'g',
150
            '4.1.0'     => 'h',
151
            '4.1.third' => 'i',
152
        ], Arrays::flatten([
153
            'a', 'b', 'c', 'd', ['first' => 'e', 'f', 'second' => 'g', ['h', 'third' => 'i']],
154
        ]));
155
156
        self::assertSame(
157
            [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd', '4.0' => 'e', '4.1' => 'f', '4.2' => 'g'],
158
            Arrays::flatten(['a', 'b', 'c', 'd', ['e', 'f', 'g']])
159
        );
160
161
        self::assertSame(
162
            ['k0' => 'a', 'k1' => 'b', 'k2' => 'c', 'k3' => 'd', 'k4.0' => 'e', 'k4.1' => 'f', 'k4.2' => 'g'],
163
            Arrays::flatten(['a', 'b', 'c', 'd', ['e', 'f', 'g']], '.', 'k')
164
        );
165
    }
166
167
    /**
168
     * Test Arrays::mapDeep().
169
     */
170
    public function testMapDeep(): void
171
    {
172
        self::assertSame([
173
            '&lt;',
174
            'abc',
175
            '&gt;',
176
            'def',
177
            ['&amp;', 'test', '123'],
178
        ], Arrays::mapDeep([
179
            '<',
180
            'abc',
181
            '>',
182
            'def',
183
            ['&', 'test', '123'],
184
        ], 'htmlentities'));
185
186
        $var       = new stdClass();
187
        $var->test = ['test' => '>'];
188
        $var->what = '<';
189
190
        $var2       = new stdClass();
191
        $var2->test = ['test' => '&gt;'];
192
        $var2->what = '&lt;';
193
194
        self::assertEquals($var2, Arrays::mapDeep($var, 'htmlentities'));
195
    }
196
197
    /**
198
     * Test Arrays::interlace().
199
     */
200
    public function testInterlace(): void
201
    {
202
        $input  = Arrays::interlace([1, 2, 3], ['a', 'b', 'c']);
203
        $expect = [1, 'a', 2, 'b', 3, 'c'];
204
205
        self::assertSame($expect, $input);
206
207
        // With one argument
208
        self::assertSame([1, 2, 3], Arrays::interlace([1, 2, 3]));
209
210
        // With no arguments
211
        self::assertFalse(Arrays::interlace());
212
    }
213
214
    /**
215
     * Test Arrays::groupBy().
216
     */
217
    public function testGroupBy(): void
218
    {
219
        $result = Arrays::groupBy([
220
            ['id' => 1, 'category' => 'A', 'value' => 'foo'],
221
            ['id' => 2, 'category' => 'B', 'value' => 'bar'],
222
            ['id' => 3, 'category' => 'A', 'value' => 'baz'],
223
            ['id' => 4, 'category' => 'B', 'value' => 'qux'],
224
        ], 'category');
225
226
        $expected = [
227
            'A' => [
228
                ['id' => 1, 'category' => 'A', 'value' => 'foo'],
229
                ['id' => 3, 'category' => 'A', 'value' => 'baz'],
230
            ],
231
            'B' => [
232
                ['id' => 2, 'category' => 'B', 'value' => 'bar'],
233
                ['id' => 4, 'category' => 'B', 'value' => 'qux'],
234
            ],
235
        ];
236
237
        self::assertSame($expected, $result);
238
    }
239
240
    /**
241
     * Test Arrays::groupBy() with non-existent/invalid key.
242
     */
243
    public function testGroupByInvalidKey(): void
244
    {
245
        $result = Arrays::groupBy([
246
            ['id' => 1, 'category' => 'A', 'value' => 'foo'],
247
            ['id' => 2, 'category' => 'B', 'value' => 'bar'],
248
            ['id' => 3, 'category' => 'A', 'value' => 'baz'],
249
            ['id' => 4, 'category' => 'B', 'value' => 'qux'],
250
        ], 'notakey');
251
252
        $expected = [];
253
254
        self::assertSame($expected, $result);
255
    }
256
}
257
258
/**
259
 * @implements ArrayAccess<mixed, mixed>
260
 */
261
class TestArrayAccess implements ArrayAccess
262
{
263
    /**
264
     * @var array<int|string, mixed>
265
     */
266
    public array $container = [
267
        'one'   => 1,
268
        'two'   => 2,
269
        'three' => 3,
270
    ];
271
272
    /**
273
     * Set an offset.
274
     *
275
     */
276
    #[\Override]
277
    public function offsetSet(mixed $offset, mixed $value): void
278
    {
279
        if (is_null($offset)) {
280
            $this->container[] = $value;
281
        } else {
282
            $this->container[$offset] = $value;
283
        }
284
    }
285
286
    /**
287
     * Whether an offset exists.
288
     *
289
     */
290
    #[\Override]
291
    public function offsetExists(mixed $offset): bool
292
    {
293
        return isset($this->container[$offset]);
294
    }
295
296
    /**
297
     * Unset an offset.
298
     *
299
     */
300
    #[\Override]
301
    public function offsetUnset(mixed $offset): void
302
    {
303
        unset($this->container[$offset]);
304
    }
305
306
    /**
307
     * Retrieve an offset exists.
308
     *
309
     */
310
    #[\Override]
311
    public function offsetGet(mixed $offset): mixed
312
    {
313
        return $this->container[$offset] ?? null;
314
    }
315
}
316