Skip to content

Commit 13d2886

Browse files
authored
Pass iterable keys to withProgressBar in InteractsWithIO (#52623)
1 parent befe9b9 commit 13d2886

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

src/Illuminate/Console/Concerns/InteractsWithIO.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ public function withProgressBar($totalSteps, Closure $callback)
263263
$bar->start();
264264

265265
if (is_iterable($totalSteps)) {
266-
foreach ($totalSteps as $value) {
267-
$callback($value, $bar);
266+
foreach ($totalSteps as $key => $value) {
267+
$callback($value, $bar, $key);
268268

269269
$bar->advance();
270270
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Console\Concerns;
4+
5+
use Generator;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Console\Concerns\InteractsWithIO;
8+
use Illuminate\Console\OutputStyle;
9+
use Mockery as m;
10+
use PHPUnit\Framework\Attributes\DataProvider;
11+
use PHPUnit\Framework\TestCase;
12+
use Symfony\Component\Console\Helper\ProgressBar;
13+
use Symfony\Component\Console\Input\ArgvInput;
14+
use Symfony\Component\Console\Output\BufferedOutput;
15+
16+
class InteractsWithIOTest extends TestCase
17+
{
18+
protected function tearDown(): void
19+
{
20+
m::close();
21+
}
22+
23+
#[DataProvider('iterableDataProvider')]
24+
public function testWithProgressBarIterable($iterable)
25+
{
26+
$command = new CommandInteractsWithIO;
27+
$bufferedOutput = new BufferedOutput();
28+
$output = m::mock(OutputStyle::class, [new ArgvInput(), $bufferedOutput])->makePartial();
29+
$command->setOutput($output);
30+
31+
$output->shouldReceive('createProgressBar')
32+
->once()
33+
->with(count($iterable))
34+
->andReturnUsing(function ($steps) use ($bufferedOutput) {
35+
// we can't mock ProgressBar because it's final, so return a real one
36+
return new ProgressBar($bufferedOutput, $steps);
37+
});
38+
39+
$calledTimes = 0;
40+
$result = $command->withProgressBar($iterable, function ($value, $bar, $key) use (&$calledTimes, $iterable) {
41+
$this->assertInstanceOf(ProgressBar::class, $bar);
42+
$this->assertSame(array_values($iterable)[$calledTimes], $value);
43+
$this->assertSame(array_keys($iterable)[$calledTimes], $key);
44+
$calledTimes++;
45+
});
46+
47+
$this->assertSame(count($iterable), $calledTimes);
48+
$this->assertSame($iterable, $result);
49+
}
50+
51+
public static function iterableDataProvider(): Generator
52+
{
53+
yield [['a', 'b', 'c']];
54+
55+
yield [['foo' => 'a', 'bar' => 'b', 'baz' => 'c']];
56+
}
57+
58+
public function testWithProgressBarInteger()
59+
{
60+
$command = new CommandInteractsWithIO;
61+
$bufferedOutput = new BufferedOutput();
62+
$output = m::mock(OutputStyle::class, [new ArgvInput(), $bufferedOutput])->makePartial();
63+
$command->setOutput($output);
64+
65+
$totalSteps = 5;
66+
67+
$output->shouldReceive('createProgressBar')
68+
->once()
69+
->with($totalSteps)
70+
->andReturnUsing(function ($steps) use ($bufferedOutput) {
71+
// we can't mock ProgressBar because it's final, so return a real one
72+
return new ProgressBar($bufferedOutput, $steps);
73+
});
74+
75+
$called = false;
76+
$command->withProgressBar($totalSteps, function ($bar) use (&$called) {
77+
$this->assertInstanceOf(ProgressBar::class, $bar);
78+
$called = true;
79+
});
80+
81+
$this->assertTrue($called);
82+
}
83+
}
84+
85+
class CommandInteractsWithIO extends Command
86+
{
87+
use InteractsWithIO;
88+
}

0 commit comments

Comments
 (0)