add('a', $a); $registry->add('b', $b); $this->assertSame($a, $registry->get('a')); $this->assertTrue($registry->has('b')); $this->assertFalse($registry->has('c')); $this->assertNull($registry->get('c')); $this->assertCount(2, $registry); $this->assertSame(['a', 'b'], $registry->ids()); } public function test_remove_is_idempotent_and_fires_listeners_once(): void { $registry = new ConnectionRegistry; $removed = []; $registry->onRemove(function (string $id) use (&$removed) { $removed[] = $id; }); $registry->add('a', new \stdClass); $registry->remove('a'); $registry->remove('a'); // no-op — must not fire again $this->assertSame(['a'], $removed); $this->assertCount(0, $registry); } public function test_on_add_listener_fires(): void { $registry = new ConnectionRegistry; $added = []; $registry->onAdd(function (string $id) use (&$added) { $added[] = $id; }); $registry->add('x', new \stdClass); $this->assertSame(['x'], $added); } public function test_each_visits_every_connection(): void { $registry = new ConnectionRegistry; $registry->add('a', new \stdClass); $registry->add('b', new \stdClass); $seen = []; $registry->each(function (object $conn, string $id) use (&$seen) { $seen[] = $id; }); $this->assertSame(['a', 'b'], $seen); } public function test_clear_removes_all_and_fires_remove_for_each(): void { $registry = new ConnectionRegistry; $removed = []; $registry->onRemove(function (string $id) use (&$removed) { $removed[] = $id; }); $registry->add('a', new \stdClass); $registry->add('b', new \stdClass); $registry->clear(); $this->assertCount(0, $registry); $this->assertSame(['a', 'b'], $removed); } }