• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 14024978163

23 Mar 2025 05:55PM UTC coverage: 79.391% (-0.05%) from 79.441%
14024978163

push

github

web-flow
feat(view): cache Blade and Twig templates in internal storage (#1061)

2 of 2 new or added lines in 2 files covered. (100.0%)

912 existing lines in 110 files now uncovered.

10478 of 13198 relevant lines covered (79.39%)

91.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.21
/src/Tempest/Console/src/Testing/ConsoleTester.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\Console\Testing;
6

7
use Closure;
8
use Fiber;
9
use PHPUnit\Framework\Assert;
10
use Tempest\Console\Actions\ExecuteConsoleCommand;
11
use Tempest\Console\Components\InteractiveComponentRenderer;
12
use Tempest\Console\Console;
13
use Tempest\Console\Exceptions\ConsoleErrorHandler;
14
use Tempest\Console\ExitCode;
15
use Tempest\Console\GenericConsole;
16
use Tempest\Console\Input\ConsoleArgumentBag;
17
use Tempest\Console\Input\MemoryInputBuffer;
18
use Tempest\Console\InputBuffer;
19
use Tempest\Console\Key;
20
use Tempest\Console\Output\MemoryOutputBuffer;
21
use Tempest\Console\OutputBuffer;
22
use Tempest\Container\Container;
23
use Tempest\Core\AppConfig;
24
use Tempest\Highlight\Highlighter;
25

26
final class ConsoleTester
27
{
28
    private (OutputBuffer&MemoryOutputBuffer)|null $output = null;
29

30
    private (InputBuffer&MemoryInputBuffer)|null $input = null;
31

32
    private ?InteractiveComponentRenderer $componentRenderer = null;
33

34
    private ?ExitCode $exitCode = null;
35

36
    private bool $withPrompting = true;
37

38
    public function __construct(
657✔
39
        private readonly Container $container,
40
    ) {
41
    }
657✔
42

43
    public function call(string|Closure|array $command, string|array $arguments = []): self
172✔
44
    {
45
        $clone = clone $this;
172✔
46

47
        $memoryOutputBuffer = new MemoryOutputBuffer();
172✔
48
        $clone->container->singleton(OutputBuffer::class, $memoryOutputBuffer);
172✔
49

50
        $memoryInputBuffer = new MemoryInputBuffer();
172✔
51
        $clone->container->singleton(InputBuffer::class, $memoryInputBuffer);
172✔
52

53
        $console = new GenericConsole(
172✔
54
            output: $memoryOutputBuffer,
172✔
55
            input: $memoryInputBuffer,
172✔
56
            highlighter: $clone->container->get(Highlighter::class, 'console'),
172✔
57
            executeConsoleCommand: $clone->container->get(ExecuteConsoleCommand::class),
172✔
58
            argumentBag: $clone->container->get(ConsoleArgumentBag::class),
172✔
59
        );
172✔
60

61
        if ($this->withPrompting === false) {
172✔
62
            $console->disablePrompting();
39✔
63
        }
64

65
        if ($this->componentRenderer !== null) {
172✔
UNCOV
66
            $console->setComponentRenderer($this->componentRenderer);
×
67
        }
68

69
        $clone->container->singleton(Console::class, $console);
172✔
70

71
        $appConfig = $this->container->get(AppConfig::class);
172✔
72
        $appConfig->errorHandlers[] = $clone->container->get(ConsoleErrorHandler::class);
172✔
73

74
        $clone->output = $memoryOutputBuffer;
172✔
75
        $clone->input = $memoryInputBuffer;
172✔
76

77
        if ($command instanceof Closure) {
172✔
78
            $fiber = new Fiber(function () use ($clone, $command, $console): void {
69✔
79
                $clone->exitCode = $command($console) ?? ExitCode::SUCCESS;
69✔
80
            });
69✔
81
        } else {
82
            $fiber = new Fiber(function () use ($command, $arguments, $clone): void {
103✔
83
                $clone->container->singleton(ConsoleArgumentBag::class, new ConsoleArgumentBag(['tempest']));
103✔
84
                $clone->exitCode = $this->container->invoke(
103✔
85
                    ExecuteConsoleCommand::class,
103✔
86
                    command: $command,
103✔
87
                    arguments: $arguments,
103✔
88
                );
103✔
89
            });
103✔
90
        }
91

92
        $fiber->start();
172✔
93

94
        if ($clone->componentRenderer !== null) {
172✔
95
            $clone->input("\e[1;1R"); // Set cursor for interactive testing
×
96
        }
97

98
        return $clone;
172✔
99
    }
100

101
    public function complete(?string $command = null): self
6✔
102
    {
103
        if ($command) {
6✔
104
            $input = explode(' ', $command);
5✔
105

106
            $inputString = implode(' ', array_map(
5✔
107
                fn (string $item) => "--input=\"{$item}\"",
5✔
108
                $input,
5✔
109
            ));
5✔
110
        } else {
111
            $inputString = '';
1✔
112
        }
113

114
        return $this->call("_complete --current=0 --input=\"./tempest\" {$inputString}");
6✔
115
    }
116

117
    public function input(int|string|Key $input): self
70✔
118
    {
119
        $this->output->clear();
70✔
120

121
        $this->input->add($input);
70✔
122

123
        return $this;
70✔
124
    }
125

126
    public function submit(int|string $input = ''): self
65✔
127
    {
128
        $input = (string) $input;
65✔
129

130
        $this->input($input . Key::ENTER->value);
65✔
131

132
        return $this;
65✔
133
    }
134

UNCOV
135
    public function confirm(): self
×
136
    {
UNCOV
137
        return $this->submit('yes');
×
138
    }
139

UNCOV
140
    public function deny(): self
×
141
    {
UNCOV
142
        return $this->submit('no');
×
143
    }
144

UNCOV
145
    public function print(): self
×
146
    {
UNCOV
147
        echo 'OUTPUT:' . PHP_EOL;
×
UNCOV
148
        echo $this->output->asUnformattedString();
×
149

UNCOV
150
        return $this;
×
151
    }
152

UNCOV
153
    public function printFormatted(): self
×
154
    {
155
        echo $this->output->asFormattedString();
×
156

157
        return $this;
×
158
    }
159

160
    public function getBuffer(?callable $callback = null): array
1✔
161
    {
162
        $buffer = array_map('trim', $this->output->getBufferWithoutFormatting());
1✔
163

164
        $this->output->clear();
1✔
165

166
        if ($callback !== null) {
1✔
167
            return $callback($buffer);
1✔
168
        }
169

UNCOV
170
        return $buffer;
×
171
    }
172

UNCOV
173
    public function useInteractiveTerminal(): self
×
174
    {
UNCOV
175
        $this->componentRenderer = new InteractiveComponentRenderer();
×
176

UNCOV
177
        return $this;
×
178
    }
179

180
    public function assertSee(string $text): self
11✔
181
    {
182
        return $this->assertContains($text);
11✔
183
    }
184

185
    public function assertSeeCount(string $text, int $expectedCount): self
1✔
186
    {
187
        $actualCount = substr_count($this->output->asUnformattedString(), $text);
1✔
188

189
        Assert::assertSame(
1✔
190
            $expectedCount,
1✔
191
            $actualCount,
1✔
192
            sprintf(
1✔
193
                'Failed to assert that console output counted: %s exactly %d times. These lines were printed: %s',
1✔
194
                $text,
1✔
195
                $expectedCount,
1✔
196
                PHP_EOL . PHP_EOL . $this->output->asUnformattedString() . PHP_EOL,
1✔
197
            ),
1✔
198
        );
1✔
199

200
        return $this;
1✔
201
    }
202

203
    public function assertNotSee(string $text): self
3✔
204
    {
205
        return $this->assertDoesNotContain($text);
3✔
206
    }
207

208
    public function assertContains(string $text, bool $ignoreLineEndings = true): self
77✔
209
    {
210
        $method = $ignoreLineEndings ? 'assertStringContainsStringIgnoringLineEndings' : 'assertStringContainsString';
77✔
211

212
        Assert::$method(
77✔
213
            $text,
77✔
214
            $this->output->asUnformattedString(),
77✔
215
            sprintf(
77✔
216
                'Failed to assert that console output included text: %s. These lines were printed: %s',
77✔
217
                $text,
77✔
218
                PHP_EOL . PHP_EOL . $this->output->asUnformattedString() . PHP_EOL,
77✔
219
            ),
77✔
220
        );
77✔
221

222
        return $this;
77✔
223
    }
224

225
    public function assertDoesNotContain(string $text): self
11✔
226
    {
227
        Assert::assertStringNotContainsString(
11✔
228
            $text,
11✔
229
            $this->output->asUnformattedString(),
11✔
230
            sprintf(
11✔
231
                'Failed to assert that console output did not include text: %s. These lines were printed: %s',
11✔
232
                $text,
11✔
233
                PHP_EOL . PHP_EOL . $this->output->asUnformattedString() . PHP_EOL,
11✔
234
            ),
11✔
235
        );
11✔
236

237
        return $this;
11✔
238
    }
239

240
    public function assertContainsFormattedText(string $text): self
×
241
    {
UNCOV
242
        Assert::assertStringContainsString(
×
243
            $text,
×
UNCOV
244
            $this->output->asFormattedString(),
×
UNCOV
245
            sprintf(
×
UNCOV
246
                'Failed to assert that console output included formatted text: %s. These lines were printed: %s',
×
UNCOV
247
                $text,
×
UNCOV
248
                PHP_EOL . $this->output->asFormattedString(),
×
UNCOV
249
            ),
×
UNCOV
250
        );
×
251

UNCOV
252
        return $this;
×
253
    }
254

255
    public function assertJson(): self
2✔
256
    {
257
        Assert::assertJson($this->output->asUnformattedString());
2✔
258

259
        return $this;
2✔
260
    }
261

262
    public function assertExitCode(ExitCode $exitCode): self
6✔
263
    {
264
        Assert::assertNotNull($this->exitCode, "Expected {$exitCode->name}, but instead no exit code was set — maybe you missed providing some input?");
6✔
265

266
        Assert::assertSame($exitCode, $this->exitCode, "Expected the exit code to be {$exitCode->name}, instead got {$this->exitCode->name}");
6✔
267

268
        return $this;
6✔
269
    }
270

271
    public function assertSuccess(): self
3✔
272
    {
273
        $this->assertExitCode(ExitCode::SUCCESS);
3✔
274

275
        return $this;
3✔
276
    }
277

278
    public function assertError(): self
1✔
279
    {
280
        $this->assertExitCode(ExitCode::ERROR);
1✔
281

282
        return $this;
1✔
283
    }
284

285
    public function assertCancelled(): self
1✔
286
    {
287
        $this->assertExitCode(ExitCode::CANCELLED);
1✔
288

289
        return $this;
1✔
290
    }
291

292
    public function assertInvalid(): self
1✔
293
    {
294
        $this->assertExitCode(ExitCode::INVALID);
1✔
295

296
        return $this;
1✔
297
    }
298

299
    public function withoutPrompting(): self
39✔
300
    {
301
        $this->withPrompting = false;
39✔
302

303
        return $this;
39✔
304
    }
305

306
    public function withPrompting(): self
×
307
    {
308
        $this->withPrompting = true;
×
309

UNCOV
310
        return $this;
×
311
    }
312

UNCOV
313
    public function dd(): self
×
314
    {
UNCOV
315
        ld($this->output->asFormattedString());
×
316

UNCOV
317
        return $this;
×
318
    }
319
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc