From 94c1df98cf3705a61e52c8efbad57452b0188684 Mon Sep 17 00:00:00 2001 From: Aydin Hassan Date: Wed, 16 May 2018 14:19:04 +0200 Subject: [PATCH] Selected item bugs --- src/CliMenu.php | 30 ++++++++++------- test/CliMenuTest.php | 78 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/src/CliMenu.php b/src/CliMenu.php index ce6dd011..569fd55b 100644 --- a/src/CliMenu.php +++ b/src/CliMenu.php @@ -51,7 +51,7 @@ class CliMenu protected $items = []; /** - * @var int + * @var int|null */ protected $selectedItem; @@ -164,9 +164,7 @@ public function addItem(MenuItemInterface $item) : void { $this->items[] = $item; - if (count($this->items) === 1) { - $this->selectFirstItem(); - } + $this->selectFirstItem(); } /** @@ -178,9 +176,7 @@ public function addItems(array $items) : void $this->items[] = $item; } - if (count($this->items) === count($items)) { - $this->selectFirstItem(); - } + $this->selectFirstItem(); } /** @@ -188,6 +184,7 @@ public function addItems(array $items) : void */ public function setItems(array $items) : void { + $this->selectedItem = null; $this->items = $items; $this->selectFirstItem(); @@ -198,10 +195,12 @@ public function setItems(array $items) : void */ private function selectFirstItem() : void { - foreach ($this->items as $key => $item) { - if ($item->canSelect()) { - $this->selectedItem = $key; - break; + if (null === $this->selectedItem) { + foreach ($this->items as $key => $item) { + if ($item->canSelect()) { + $this->selectedItem = $key; + break; + } } } } @@ -348,6 +347,10 @@ private function canSelect() : bool */ public function getSelectedItem() : MenuItemInterface { + if (null === $this->selectedItem) { + throw new \RuntimeException('No selected item'); + } + $item = $this->items[$this->selectedItem]; return $item instanceof SplitItem ? $item->getSelectedItem() @@ -543,6 +546,11 @@ public function removeItem(MenuItemInterface $item) : void unset($this->items[$key]); $this->items = array_values($this->items); + + if ($this->selectedItem === $key) { + $this->selectedItem = null; + $this->selectFirstItem(); + } } public function getStyle() : MenuStyle diff --git a/test/CliMenuTest.php b/test/CliMenuTest.php index 1f6df128..4656eea5 100644 --- a/test/CliMenuTest.php +++ b/test/CliMenuTest.php @@ -842,6 +842,84 @@ public function testSelectableCallableReceivesSelectableAndNotSplitItem() : void self::assertSame($expectedSelectedItem, $actualSelectedItem); } + public function testAddItemSelectsFirstSelectableItemWhenItemsExistButNoneAreSelectable() : void + { + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + + self::assertNull(self::readAttribute($menu, 'selectedItem')); + + $menu->addItem($item = new SelectableItem('Selectable', function () { + })); + + self::assertEquals($item, $menu->getSelectedItem()); + } + + public function testAddItemsSelectsFirstSelectableItemWhenItemsExistButNoneAreSelectable() : void + { + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + + self::assertNull(self::readAttribute($menu, 'selectedItem')); + + $menu->addItems([$item = new SelectableItem('Selectable', function () { + })]); + + self::assertEquals($item, $menu->getSelectedItem()); + } + + public function testSetItemsReSelectsFirstSelectableItem() : void + { + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + $menu->addItem($item = new SelectableItem('Selectable', function () { + })); + + self::assertEquals($item, $menu->getSelectedItem()); + + $menu->setItems([$item2 = new SelectableItem('Selectable', function () { + })]); + + self::assertEquals($item2, $menu->getSelectedItem()); + } + + public function testRemoveItemReSelectsFirstSelectableItemIfSelectedItemRemoved() : void + { + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + $menu->addItem($item = new SelectableItem('Selectable', function () { + })); + + self::assertEquals($item, $menu->getSelectedItem()); + + $menu->removeItem($item); + + self::assertNull(self::readAttribute($menu, 'selectedItem')); + + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + $menu->addItem($item1 = new SelectableItem('Selectable', function () { + })); + $menu->addItem($item2 = new SelectableItem('Selectable', function () { + })); + + self::assertEquals($item1, $menu->getSelectedItem()); + + $menu->removeItem($item1); + + self::assertEquals($item2, $menu->getSelectedItem()); + } + + public function testGetSelectedItemThrowsExceptionIfNoSelectedItem() : void + { + self::expectException(\RuntimeException::class); + self::expectExceptionMessage('No selected item'); + + $menu = new CliMenu('PHP School FTW', [], $this->terminal); + $menu->addItem(new StaticItem('No Selectable')); + $menu->getSelectedItem(); + } + private function getTestFile() : string { return sprintf('%s/res/%s.txt', __DIR__, $this->getName());