Skip to content

Commit

Permalink
Pass iterable keys to withProgressBar in InteractsWithIO (#52623)
Browse files Browse the repository at this point in the history
  • Loading branch information
robinmoisson authored Sep 2, 2024
1 parent befe9b9 commit 13d2886
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/Illuminate/Console/Concerns/InteractsWithIO.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ public function withProgressBar($totalSteps, Closure $callback)
$bar->start();

if (is_iterable($totalSteps)) {
foreach ($totalSteps as $value) {
$callback($value, $bar);
foreach ($totalSteps as $key => $value) {
$callback($value, $bar, $key);

$bar->advance();
}
Expand Down
88 changes: 88 additions & 0 deletions tests/Console/Concerns/InteractsWithIOTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace Illuminate\Tests\Console\Concerns;

use Generator;
use Illuminate\Console\Command;
use Illuminate\Console\Concerns\InteractsWithIO;
use Illuminate\Console\OutputStyle;
use Mockery as m;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\BufferedOutput;

class InteractsWithIOTest extends TestCase
{
protected function tearDown(): void
{
m::close();
}

#[DataProvider('iterableDataProvider')]
public function testWithProgressBarIterable($iterable)
{
$command = new CommandInteractsWithIO;
$bufferedOutput = new BufferedOutput();
$output = m::mock(OutputStyle::class, [new ArgvInput(), $bufferedOutput])->makePartial();
$command->setOutput($output);

$output->shouldReceive('createProgressBar')
->once()
->with(count($iterable))
->andReturnUsing(function ($steps) use ($bufferedOutput) {
// we can't mock ProgressBar because it's final, so return a real one
return new ProgressBar($bufferedOutput, $steps);
});

$calledTimes = 0;
$result = $command->withProgressBar($iterable, function ($value, $bar, $key) use (&$calledTimes, $iterable) {
$this->assertInstanceOf(ProgressBar::class, $bar);
$this->assertSame(array_values($iterable)[$calledTimes], $value);
$this->assertSame(array_keys($iterable)[$calledTimes], $key);
$calledTimes++;
});

$this->assertSame(count($iterable), $calledTimes);
$this->assertSame($iterable, $result);
}

public static function iterableDataProvider(): Generator
{
yield [['a', 'b', 'c']];

yield [['foo' => 'a', 'bar' => 'b', 'baz' => 'c']];
}

public function testWithProgressBarInteger()
{
$command = new CommandInteractsWithIO;
$bufferedOutput = new BufferedOutput();
$output = m::mock(OutputStyle::class, [new ArgvInput(), $bufferedOutput])->makePartial();
$command->setOutput($output);

$totalSteps = 5;

$output->shouldReceive('createProgressBar')
->once()
->with($totalSteps)
->andReturnUsing(function ($steps) use ($bufferedOutput) {
// we can't mock ProgressBar because it's final, so return a real one
return new ProgressBar($bufferedOutput, $steps);
});

$called = false;
$command->withProgressBar($totalSteps, function ($bar) use (&$called) {
$this->assertInstanceOf(ProgressBar::class, $bar);
$called = true;
});

$this->assertTrue($called);
}
}

class CommandInteractsWithIO extends Command
{
use InteractsWithIO;
}

0 comments on commit 13d2886

Please sign in to comment.