128 lines
4.2 KiB
PHP
128 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Support\Diff\DiffPresenter;
|
|
use App\Support\Diff\DiffRowStatus;
|
|
|
|
it('classifies rows across all shared states and derives matching summary counts', function (): void {
|
|
$presentation = app(DiffPresenter::class)->present(
|
|
baseline: [
|
|
'description' => 'Before',
|
|
'display_name' => 'TenantPilot',
|
|
'retired_setting' => 'Legacy',
|
|
],
|
|
current: [
|
|
'description' => 'After',
|
|
'display_name' => 'TenantPilot',
|
|
'new_setting' => 'Enabled',
|
|
],
|
|
labels: [
|
|
'description' => 'Description',
|
|
'display_name' => 'Display name',
|
|
'new_setting' => 'New setting',
|
|
'retired_setting' => 'Retired setting',
|
|
],
|
|
);
|
|
|
|
$rows = collect($presentation->rows)->keyBy('key');
|
|
|
|
expect($presentation->summary->changedCount)->toBe(1)
|
|
->and($presentation->summary->addedCount)->toBe(1)
|
|
->and($presentation->summary->removedCount)->toBe(1)
|
|
->and($presentation->summary->unchangedCount)->toBe(1)
|
|
->and($presentation->summary->hasRows)->toBeTrue()
|
|
->and($rows->get('description')?->status)->toBe(DiffRowStatus::Changed)
|
|
->and($rows->get('display_name')?->status)->toBe(DiffRowStatus::Unchanged)
|
|
->and($rows->get('new_setting')?->status)->toBe(DiffRowStatus::Added)
|
|
->and($rows->get('retired_setting')?->status)->toBe(DiffRowStatus::Removed);
|
|
});
|
|
|
|
it('returns rows in deterministic label order', function (): void {
|
|
$presentation = app(DiffPresenter::class)->present(
|
|
baseline: [
|
|
'zeta_value' => 'same',
|
|
'alpha_value' => 'before',
|
|
],
|
|
current: [
|
|
'alpha_value' => 'after',
|
|
'middle_value' => 'new',
|
|
'zeta_value' => 'same',
|
|
],
|
|
labels: [
|
|
'alpha_value' => 'Alpha value',
|
|
'middle_value' => 'Middle value',
|
|
'zeta_value' => 'Zeta value',
|
|
],
|
|
);
|
|
|
|
expect(array_map(
|
|
static fn ($row): string => $row->label,
|
|
$presentation->rows,
|
|
))->toBe([
|
|
'Alpha value',
|
|
'Middle value',
|
|
'Zeta value',
|
|
]);
|
|
});
|
|
|
|
it('prepares inline list fragments for simple list comparisons', function (): void {
|
|
$presentation = app(DiffPresenter::class)->present(
|
|
baseline: [
|
|
'scope_tags' => ['Default', 'Legacy', 'Shared'],
|
|
],
|
|
current: [
|
|
'scope_tags' => ['Default', 'Shared', 'Workspace'],
|
|
],
|
|
labels: [
|
|
'scope_tags' => 'Scope tags',
|
|
],
|
|
);
|
|
|
|
$row = $presentation->rows[0] ?? null;
|
|
|
|
expect($row)->not->toBeNull()
|
|
->and($row?->isListLike)->toBeTrue()
|
|
->and($row?->addedItems)->toBe(['Workspace'])
|
|
->and($row?->removedItems)->toBe(['Legacy'])
|
|
->and($row?->unchangedItems)->toBe(['Default', 'Shared']);
|
|
});
|
|
|
|
it('falls back to generated labels and safe empty meta when optional metadata is missing or invalid', function (): void {
|
|
$presentation = app(DiffPresenter::class)->present(
|
|
baseline: [
|
|
'customSettingFoo' => 'Before',
|
|
],
|
|
current: [
|
|
'customSettingFoo' => 'After',
|
|
],
|
|
meta: [
|
|
'customSettingFoo' => 'invalid-meta-shape',
|
|
],
|
|
);
|
|
|
|
$row = $presentation->rows[0] ?? null;
|
|
|
|
expect($row)->not->toBeNull()
|
|
->and($row?->label)->toBe('Custom Setting Foo')
|
|
->and($row?->meta)->toBe([]);
|
|
});
|
|
|
|
it('returns a no-data presentation for empty or sparse compare payloads', function (): void {
|
|
$presentation = app(DiffPresenter::class)->present(
|
|
baseline: [],
|
|
current: [],
|
|
changedKeys: ['ghost_key'],
|
|
labels: ['ghost_key' => 'Ghost key'],
|
|
meta: ['ghost_key' => ['note' => 'unused']],
|
|
);
|
|
|
|
expect($presentation->rows)->toBe([])
|
|
->and($presentation->summary->hasRows)->toBeFalse()
|
|
->and($presentation->summary->changedCount)->toBe(0)
|
|
->and($presentation->summary->addedCount)->toBe(0)
|
|
->and($presentation->summary->removedCount)->toBe(0)
|
|
->and($presentation->summary->unchangedCount)->toBe(0)
|
|
->and($presentation->summary->message)->toBe('No diff data available.');
|
|
});
|