138 lines
4.5 KiB
PHP
138 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Exceptions\PromptRenderException;
|
|
use App\Services\PromptRenderer;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class PromptRendererTest extends TestCase
|
|
{
|
|
private PromptRenderer $renderer;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->renderer = new PromptRenderer();
|
|
}
|
|
|
|
public function test_extract_variables_returns_empty_list_without_variables(): void
|
|
{
|
|
$this->assertSame([], $this->renderer->extractVariables(''));
|
|
$this->assertSame([], $this->renderer->extractVariables('Plain text, no placeholders at all.'));
|
|
}
|
|
|
|
public function test_extract_variables_returns_unique_names_in_first_occurrence_order(): void
|
|
{
|
|
$body = 'Hello {{name}}, here is {{content}}. Again: {{name}} and {{extra}}.';
|
|
|
|
$this->assertSame(['name', 'content', 'extra'], $this->renderer->extractVariables($body));
|
|
}
|
|
|
|
public function test_extract_variables_tolerates_inner_whitespace(): void
|
|
{
|
|
$this->assertSame(
|
|
['content'],
|
|
$this->renderer->extractVariables('{{content}} {{ content }}')
|
|
);
|
|
$this->assertSame(
|
|
['a_b', 'A-B'],
|
|
$this->renderer->extractVariables('{{a_b}} and {{ A-B }}')
|
|
);
|
|
|
|
// `$` is not in the variable charset, so this stays literal.
|
|
$this->assertSame([], $this->renderer->extractVariables('{{$a_b}}'));
|
|
}
|
|
|
|
public function test_invalid_tokens_are_not_treated_as_variables(): void
|
|
{
|
|
$body = '{{}} and {{a b}} and {{a!b}} and {{ }} stay literal';
|
|
|
|
$this->assertSame([], $this->renderer->extractVariables($body));
|
|
}
|
|
|
|
public function test_render_replaces_every_occurrence(): void
|
|
{
|
|
$rendered = $this->renderer->render(
|
|
'Hi {{name}}! Send {{name}} the file.',
|
|
['name' => 'Ada']
|
|
);
|
|
|
|
$this->assertSame('Hi Ada! Send Ada the file.', $rendered);
|
|
}
|
|
|
|
public function test_render_returns_body_unchanged_without_variables(): void
|
|
{
|
|
$body = 'Nothing to do here.';
|
|
|
|
$this->assertSame($body, $this->renderer->render($body, ['ignored' => 'x']));
|
|
}
|
|
|
|
public function test_render_is_strict_about_missing_variables(): void
|
|
{
|
|
try {
|
|
$this->renderer->render('A: {{alpha}} B: {{beta}} C: {{gamma}}', ['beta' => 'b']);
|
|
$this->fail('Expected PromptRenderException was not thrown.');
|
|
} catch (PromptRenderException $exception) {
|
|
$this->assertSame(['alpha', 'gamma'], $exception->missingVariables);
|
|
$this->assertSame('Missing variables: alpha, gamma', $exception->getMessage());
|
|
}
|
|
}
|
|
|
|
public function test_render_treats_non_string_values_as_missing(): void
|
|
{
|
|
try {
|
|
$this->renderer->render('Count: {{count}}', ['count' => 42]);
|
|
$this->fail('Expected PromptRenderException was not thrown.');
|
|
} catch (PromptRenderException $exception) {
|
|
$this->assertSame(['count'], $exception->missingVariables);
|
|
}
|
|
|
|
try {
|
|
$this->renderer->render('Count: {{count}}', ['count' => null]);
|
|
$this->fail('Expected PromptRenderException was not thrown.');
|
|
} catch (PromptRenderException $exception) {
|
|
$this->assertSame(['count'], $exception->missingVariables);
|
|
}
|
|
}
|
|
|
|
public function test_render_accepts_empty_string_values(): void
|
|
{
|
|
$this->assertSame(
|
|
'Title: ',
|
|
$this->renderer->render('Title: {{title}}', ['title' => ''])
|
|
);
|
|
}
|
|
|
|
public function test_render_ignores_extra_values(): void
|
|
{
|
|
$rendered = $this->renderer->render(
|
|
'Only {{used}}',
|
|
['used' => 'yes', 'extra' => 'no']
|
|
);
|
|
|
|
$this->assertSame('Only yes', $rendered);
|
|
}
|
|
|
|
public function test_inserted_values_are_not_re_scanned_for_variables(): void
|
|
{
|
|
$rendered = $this->renderer->render(
|
|
'Hello {{name}}, and {{other}}.',
|
|
['name' => '{{other}}', 'other' => 'world']
|
|
);
|
|
|
|
$this->assertSame('Hello {{other}}, and world.', $rendered);
|
|
}
|
|
|
|
public function test_missing_variables_are_reported_in_template_order(): void
|
|
{
|
|
try {
|
|
$this->renderer->render('{{zulu}} {{alpha}} {{zulu}}', []);
|
|
$this->fail('Expected PromptRenderException was not thrown.');
|
|
} catch (PromptRenderException $exception) {
|
|
$this->assertSame(['zulu', 'alpha'], $exception->missingVariables);
|
|
}
|
|
}
|
|
}
|