packages/deriver/tests/Unit/Reporter/JsonReporterTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Reporter;
6
7use Deriver\Deriver\Candidate;
8use Deriver\Deriver\Candidate\Alternative;
9use Deriver\Deriver\Candidate\CandidateCollection;
10use Deriver\Deriver\Candidate\ResultRef;
11use Deriver\Deriver\Candidate\Snapshot;
12use Deriver\Deriver\Evaluator\Evidence\EvidenceKind;
13use Deriver\Deriver\Evaluator\Evidence\Node;
14use Deriver\Deriver\Evaluator\Term;
15use Deriver\Exception\ReportingException;
16use Deriver\Reporter\JsonReporter;
17use PHPUnit\Framework\Attributes\CoversNothing;
18use PHPUnit\Framework\TestCase;
19
20#[CoversNothing]
21final class JsonReporterTest extends TestCase
22{
23    public function testReportIncludesConcreteValuesAndOrderedEvidence(): void
24    {
25        $input = new Node(EvidenceKind::Operation);
26        $node = new Node(EvidenceKind::Observation, ['value' => $input]);
27        $evidence = [new Alternative($node, $node, new Snapshot('s', [], [], new \Deriver\Deriver\Evaluator\TargetProfile(), 'environment'))];
28        $candidates = new CandidateCollection([new Candidate(Term::constant(1.0), $evidence)], new ResultRef('r'));
29        $text = (new JsonReporter())->report($candidates);
30        self::assertStringContainsString('"result": 1.0', $text);
31        self::assertStringContainsString('"interrupted": false', $text);
32        self::assertStringContainsString($node->id, $text);
33        self::assertStringContainsString($input->id, $text);
34        self::assertStringNotContainsString('sourceModes', $text);
35    }
36
37    public function testReportIncludesResidualStructure(): void
38    {
39        $node = new Node(EvidenceKind::Observation);
40        $evidence = [new Alternative($node, $node, new Snapshot('s', [], [], new \Deriver\Deriver\Evaluator\TargetProfile(), 'environment'))];
41        $candidates = new CandidateCollection([new Candidate(Term::parameter('id', 'int'), $evidence)], new ResultRef('r'), interrupted: true);
42        $text = (new JsonReporter())->report($candidates);
43        self::assertStringContainsString('"type": "partials"', $text);
44        self::assertStringContainsString('"literal": "id"', $text);
45        self::assertStringContainsString('"interrupted": true', $text);
46    }
47
48    public function testReportFailsWithoutSilentlyReplacingBinaryStrings(): void
49    {
50        $node = new Node(EvidenceKind::Observation);
51        $evidence = [new Alternative($node, $node, new Snapshot('s', [], [], new \Deriver\Deriver\Evaluator\TargetProfile(), 'environment'))];
52        $candidates = new CandidateCollection([new Candidate(Term::constant("\xff"), $evidence)], new ResultRef('r'));
53        $this->expectException(ReportingException::class);
54        $this->expectExceptionMessage('Cannot encode report as JSON');
55        (new JsonReporter())->report($candidates);
56    }
57
58    public function testReportProducesAnEmptyArrayForNoCandidates(): void
59    {
60        self::assertSame("{\n    \"interrupted\": false,\n    \"candidates\": []\n}\n", (new JsonReporter())->report(new CandidateCollection([], new ResultRef('r'))));
61    }
62}
63