SuperSeller3000/tests/Unit/Infrastructure/AI/MistralClientTest.php

124 lines
4.1 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace App\Tests\Unit\Infrastructure\AI;
use App\Infrastructure\AI\MistralClient;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
final class MistralClientTest extends TestCase
{
private function makeClient(MockResponse $response): MistralClient
{
return new MistralClient(
new MockHttpClient($response),
'test-api-key',
'https://api.mistral.ai',
);
}
public function testGenerateReturnsParsedContent(): void
{
$body = json_encode([
'choices' => [['message' => ['content' => 'Dell Latitude 5520']]],
]);
$client = $this->makeClient(new MockResponse((string) $body));
self::assertSame('Dell Latitude 5520', $client->generate('mistral-large-latest', 'What is this?'));
}
public function testGenerateSendsAuthHeader(): void
{
$body = json_encode([
'choices' => [['message' => ['content' => 'ok']]],
]);
$response = new MockResponse((string) $body);
$client = $this->makeClient($response);
$client->generate('mistral-large-latest', 'test');
self::assertStringContainsString(
'Bearer test-api-key',
implode(', ', $response->getRequestOptions()['headers'] ?? []),
);
}
public function testGenerateWithImageReturnsParsedContent(): void
{
$tmpFile = tempnam(sys_get_temp_dir(), 'test_') . '.jpg';
file_put_contents($tmpFile, 'fake-image-data');
$body = json_encode([
'choices' => [['message' => ['content' => 'MODEL: ThinkPad X1']]],
]);
$client = $this->makeClient(new MockResponse((string) $body));
$result = $client->generateWithImage('pixtral-12b-2409', 'Read the nameplate', $tmpFile);
unlink($tmpFile);
self::assertSame('MODEL: ThinkPad X1', $result);
}
public function testGenerateWithImageEncodesImageAsBase64(): void
{
$tmpFile = tempnam(sys_get_temp_dir(), 'test_') . '.png';
$imageContent = 'fake-png-bytes';
file_put_contents($tmpFile, $imageContent);
$body = json_encode([
'choices' => [['message' => ['content' => 'ok']]],
]);
$response = new MockResponse((string) $body);
$client = $this->makeClient($response);
$client->generateWithImage('pixtral-12b-2409', 'describe', $tmpFile);
unlink($tmpFile);
$requestBody = json_decode($response->getRequestOptions()['body'], true);
$imageUrl = $requestBody['messages'][0]['content'][1]['image_url']['url'];
self::assertStringStartsWith('data:image/png;base64,', $imageUrl);
self::assertStringContainsString(base64_encode($imageContent), $imageUrl);
}
/**
* @dataProvider mimeTypeProvider
*/
public function testGuessMimeTypeFromExtension(string $filename, string $expectedMime): void
{
$tmpFile = tempnam(sys_get_temp_dir(), 'test_') . '.' . pathinfo($filename, PATHINFO_EXTENSION);
file_put_contents($tmpFile, 'x');
$body = json_encode(['choices' => [['message' => ['content' => 'ok']]]]);
$response = new MockResponse((string) $body);
$client = $this->makeClient($response);
$client->generateWithImage('pixtral-12b-2409', 'x', $tmpFile);
unlink($tmpFile);
$requestBody = json_decode($response->getRequestOptions()['body'], true);
$imageUrl = $requestBody['messages'][0]['content'][1]['image_url']['url'];
self::assertStringStartsWith('data:' . $expectedMime . ';base64,', $imageUrl);
}
/** @return array<string, array{string, string}> */
public static function mimeTypeProvider(): array
{
return [
'jpeg' => ['photo.jpg', 'image/jpeg'],
'jpeg uppercase' => ['photo.JPG', 'image/jpeg'],
'jpeg ext' => ['photo.jpeg', 'image/jpeg'],
'png' => ['photo.png', 'image/png'],
'webp' => ['photo.webp', 'image/webp'],
'unknown falls back to jpeg' => ['photo.bmp', 'image/jpeg'],
];
}
}