This commit is contained in:
Doar Mihai
2026-10-17 02:01:43 +03:00
parent 402fd63721
commit 579d487460
5 changed files with 226 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\HttpFactory;
use GuzzleHttp\Psr7\Response;
use Laya\Exception\UnexpectedResponseException;
use Laya\Laya;
use Laya\LayaClient;
use Laya\Question\QuestionSet;
use Laya\Question\YesNoQuestion;
/** @return array{LayaClient, ArrayObject} client and the recorded request history */
function fakeClient(array $responses): array
{
$history = new ArrayObject();
$stack = HandlerStack::create(new MockHandler($responses));
$stack->push(Middleware::history($history));
$factory = new HttpFactory();
return [new LayaClient(new Client(['handler' => $stack]), $factory, $factory, 'http://laya.test'), $history];
}
function json(array $body, int $status = 200): Response
{
return new Response($status, ['Content-Type' => 'application/json'], json_encode($body));
}
function questions(): QuestionSet
{
return QuestionSet::make()->add(new YesNoQuestion('angry', 'Upset?'));
}
it('posts the state and questions to /predict', function () {
[$client, $history] = fakeClient([json(['answers' => ['angry' => ['type' => 'noul', 'noul' => 0.8]]])]);
$result = $client->decide('hello', questions());
$request = $history[0]['request'];
expect($request->getMethod())->toBe('POST')
->and((string) $request->getUri())->toBe('http://laya.test/predict')
->and($request->getHeaderLine('Content-Type'))->toBe('application/json')
->and($request->getHeaderLine('Accept'))->toBe('application/json')
->and(json_decode((string) $request->getBody(), true))->toBe([
'state' => ['body' => 'hello'],
'questions' => ['angry' => ['type' => 'noul', 'instructions' => 'Upset?']],
])
->and($result->get('angry')->probability())->toBe(0.8);
});
it('sends an array state unchanged and includes the model when given', function () {
[$client, $history] = fakeClient([json(['answers' => []])]);
$client->decide(['subject' => 's', 'body' => 'b'], questions(), 'my-model');
$sent = json_decode((string) $history[0]['request']->getBody(), true);
expect($sent['state'])->toBe(['subject' => 's', 'body' => 'b'])
->and($sent['model'])->toBe('my-model');
});
it('omits model when none is given', function () {
[$client, $history] = fakeClient([json(['answers' => []])]);
$client->decide('x', questions());
expect(json_decode((string) $history[0]['request']->getBody(), true))->not->toHaveKey('model');
});
it('gets /models', function () {
[$client, $history] = fakeClient([json(['models' => ['a', 'b']])]);
expect($client->models())->toBe(['models' => ['a', 'b']])
->and($history[0]['request']->getMethod())->toBe('GET')
->and((string) $history[0]['request']->getUri())->toBe('http://laya.test/models');
});
it('throws UnexpectedResponseException with the server detail on HTTP errors', function () {
[$client] = fakeClient([json(['detail' => 'bad model'], 422)]);
try {
$client->decide('x', questions());
$this->fail('expected exception');
} catch (UnexpectedResponseException $e) {
expect($e->statusCode())->toBe(422)
->and($e->getMessage())->toBe('Laya returned HTTP 422: bad model');
}
});
it('throws JsonException when the body is not JSON', function () {
[$client] = fakeClient([new Response(200, [], 'not json')]);
$client->models();
})->throws(JsonException::class);
it('builds a client through discovery', function () {
expect(Laya::client('http://laya.test'))->toBeInstanceOf(LayaClient::class);
});