Skip to content

Commit 641f6be

Browse files
committed
minor #455 [Platform][HuggingFace] Add tests for normalizers (OskarStark)
This PR was squashed before being merged into the main branch. Discussion ---------- [Platform][HuggingFace] Add tests for normalizers | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | Docs? | no | Issues | -- | License | MIT Commits ------- b7e3338 [Platform][HuggingFace] Add tests for normalizers
2 parents 2b4d168 + b7e3338 commit 641f6be

File tree

5 files changed

+226
-0
lines changed

5 files changed

+226
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Platform\Tests\Bridge\HuggingFace\Contract;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\DataProvider;
16+
use PHPUnit\Framework\Attributes\Medium;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\AI\Platform\Bridge\HuggingFace\Contract\FileNormalizer;
19+
use Symfony\AI\Platform\Contract;
20+
use Symfony\AI\Platform\Message\Content\File;
21+
use Symfony\AI\Platform\Model;
22+
23+
#[Medium]
24+
#[CoversClass(FileNormalizer::class)]
25+
final class FileNormalizerTest extends TestCase
26+
{
27+
public function testSupportsNormalization()
28+
{
29+
$normalizer = new FileNormalizer();
30+
31+
$this->assertTrue($normalizer->supportsNormalization(new File('some content', 'image/jpeg'), context: [
32+
Contract::CONTEXT_MODEL => new Model('test-model'),
33+
]));
34+
$this->assertFalse($normalizer->supportsNormalization('not a file'));
35+
}
36+
37+
public function testGetSupportedTypes()
38+
{
39+
$normalizer = new FileNormalizer();
40+
41+
$expected = [
42+
File::class => true,
43+
];
44+
45+
$this->assertSame($expected, $normalizer->getSupportedTypes(null));
46+
}
47+
48+
#[DataProvider('normalizeDataProvider')]
49+
public function testNormalize(File $file, array $expected)
50+
{
51+
$normalizer = new FileNormalizer();
52+
53+
$normalized = $normalizer->normalize($file);
54+
55+
$this->assertEquals($expected, $normalized);
56+
}
57+
58+
public static function normalizeDataProvider(): iterable
59+
{
60+
yield 'image from file' => [
61+
File::fromFile(\dirname(__DIR__, 3).'/fixtures/image.jpg'),
62+
[
63+
'headers' => ['Content-Type' => 'image/jpeg'],
64+
'body' => file_get_contents(\dirname(__DIR__, 3).'/fixtures/image.jpg'),
65+
],
66+
];
67+
68+
yield 'pdf document from file' => [
69+
File::fromFile(\dirname(__DIR__, 3).'/fixtures/document.pdf'),
70+
[
71+
'headers' => ['Content-Type' => 'application/pdf'],
72+
'body' => file_get_contents(\dirname(__DIR__, 3).'/fixtures/document.pdf'),
73+
],
74+
];
75+
76+
yield 'audio from file' => [
77+
File::fromFile(\dirname(__DIR__, 3).'/fixtures/audio.mp3'),
78+
[
79+
'headers' => ['Content-Type' => 'audio/mpeg'],
80+
'body' => file_get_contents(\dirname(__DIR__, 3).'/fixtures/audio.mp3'),
81+
],
82+
];
83+
84+
yield 'text file from content' => [
85+
new File('Hello World', 'text/plain'),
86+
[
87+
'headers' => ['Content-Type' => 'text/plain'],
88+
'body' => 'Hello World',
89+
],
90+
];
91+
}
92+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Platform\Tests\Bridge\HuggingFace\Contract;
13+
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\DataProvider;
16+
use PHPUnit\Framework\Attributes\Medium;
17+
use PHPUnit\Framework\TestCase;
18+
use Symfony\AI\Platform\Bridge\HuggingFace\Contract\MessageBagNormalizer;
19+
use Symfony\AI\Platform\Contract;
20+
use Symfony\AI\Platform\Contract\Normalizer\Message\UserMessageNormalizer;
21+
use Symfony\AI\Platform\Message\Content\Text;
22+
use Symfony\AI\Platform\Message\Message;
23+
use Symfony\AI\Platform\Message\MessageBag;
24+
use Symfony\AI\Platform\Message\UserMessage;
25+
use Symfony\AI\Platform\Model;
26+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
27+
28+
#[Medium]
29+
#[CoversClass(MessageBagNormalizer::class)]
30+
final class MessageBagNormalizerTest extends TestCase
31+
{
32+
public function testSupportsNormalization()
33+
{
34+
$normalizer = new MessageBagNormalizer();
35+
36+
$this->assertTrue($normalizer->supportsNormalization(new MessageBag(), context: [
37+
Contract::CONTEXT_MODEL => new Model('test-model'),
38+
]));
39+
$this->assertFalse($normalizer->supportsNormalization('not a message bag'));
40+
}
41+
42+
public function testGetSupportedTypes()
43+
{
44+
$normalizer = new MessageBagNormalizer();
45+
46+
$expected = [
47+
MessageBag::class => true,
48+
];
49+
50+
$this->assertSame($expected, $normalizer->getSupportedTypes(null));
51+
}
52+
53+
#[DataProvider('provideMessageBagData')]
54+
public function testNormalize(MessageBag $bag, array $expected)
55+
{
56+
$normalizer = new MessageBagNormalizer();
57+
58+
// Set up the concrete user message normalizer
59+
$userMessageNormalizer = new UserMessageNormalizer();
60+
61+
// Mock a normalizer that delegates to the concrete normalizer
62+
$mockNormalizer = $this->createMock(NormalizerInterface::class);
63+
$mockNormalizer->method('normalize')
64+
->willReturnCallback(function ($messages) use ($userMessageNormalizer): array {
65+
$result = [];
66+
foreach ($messages as $message) {
67+
if ($message instanceof UserMessage) {
68+
$result[] = $userMessageNormalizer->normalize($message);
69+
}
70+
}
71+
72+
return $result;
73+
});
74+
75+
$normalizer->setNormalizer($mockNormalizer);
76+
77+
$normalized = $normalizer->normalize($bag);
78+
79+
$this->assertEquals($expected, $normalized);
80+
}
81+
82+
/**
83+
* @return iterable<array{0: MessageBag, 1: array}>
84+
*/
85+
public static function provideMessageBagData(): iterable
86+
{
87+
yield 'simple text message' => [
88+
new MessageBag(Message::ofUser('Hello, how are you?')),
89+
[
90+
'headers' => ['Content-Type' => 'application/json'],
91+
'json' => [
92+
'messages' => [
93+
[
94+
'role' => 'user',
95+
'content' => 'Hello, how are you?',
96+
],
97+
],
98+
],
99+
],
100+
];
101+
102+
yield 'multiple messages' => [
103+
new MessageBag(
104+
Message::ofUser('What is the capital of France?'),
105+
new UserMessage(new Text('Please provide a detailed answer.'))
106+
),
107+
[
108+
'headers' => ['Content-Type' => 'application/json'],
109+
'json' => [
110+
'messages' => [
111+
[
112+
'role' => 'user',
113+
'content' => 'What is the capital of France?',
114+
],
115+
[
116+
'role' => 'user',
117+
'content' => 'Please provide a detailed answer.',
118+
],
119+
],
120+
],
121+
],
122+
];
123+
124+
yield 'empty message bag' => [
125+
new MessageBag(),
126+
[
127+
'headers' => ['Content-Type' => 'application/json'],
128+
'json' => [
129+
'messages' => [],
130+
],
131+
],
132+
];
133+
}
134+
}
49.8 KB
Binary file not shown.
18 KB
Binary file not shown.
58.7 KB
Loading

0 commit comments

Comments
 (0)