*/ public static function emptySegmentPaths(): array { return [ 'double dot' => ['a..b'], 'leading dot' => ['.a'], 'trailing dot' => ['a.'], 'empty' => [''], ]; } /** @dataProvider emptySegmentPaths */ public function testSetRejectsEmptyPathSegments(string $path): void { $this->expectException(InvalidArgumentException::class); AttrMap::set([], $path, 'z'); } public function testSetKeepsAnObjectAnObjectWhenRewrapping(): void { $attrs = ['a' => new stdClass()]; $changed = AttrMap::set($attrs, 'a.0', 'z'); self::assertInstanceOf(stdClass::class, $changed['a']); self::assertSame('z', $changed['a']->{'0'}); self::assertSame('{"a":{"0":"z"}}', json_encode($changed)); } public function testSetStillBuildsPlainArraysWhenNoObjectExisted(): void { $changed = AttrMap::set([], 'a.b', 'z'); self::assertSame(['a' => ['b' => 'z']], $changed); } /** get() must still read back through a value set() kept as an object (regression guard). */ public function testGetReadsThroughAnObjectRewrappedBySet(): void { $attrs = ['a' => new stdClass()]; $changed = AttrMap::set($attrs, 'a.b', 'z'); self::assertSame('z', AttrMap::get($changed, 'a.b')); } }