Skip to content

Commit 03f66ff

Browse files
committed
test: adds serialization tests
1 parent 0c0407c commit 03f66ff

16 files changed

+1893
-3
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WordPress\AiClient\Tests\traits;
6+
7+
/**
8+
* Trait for testing JSON serialization functionality.
9+
*
10+
* Provides common assertions for DTOs that implement WithJsonSerialization.
11+
*
12+
* @since 1.0.0
13+
*/
14+
trait JsonSerializationTestTrait
15+
{
16+
/**
17+
* Asserts that an object implements WithJsonSerialization interface.
18+
*
19+
* @param object $object The object to test.
20+
* @return void
21+
*/
22+
protected function assertImplementsJsonSerialization($object): void
23+
{
24+
$this->assertInstanceOf(
25+
\WordPress\AiClient\Common\Contracts\WithJsonSerialization::class,
26+
$object,
27+
'Object should implement WithJsonSerialization interface'
28+
);
29+
$this->assertInstanceOf(
30+
\JsonSerializable::class,
31+
$object,
32+
'Object should implement JsonSerializable interface'
33+
);
34+
}
35+
36+
/**
37+
* Asserts that jsonSerialize returns a valid array.
38+
*
39+
* @param object $object The object to test.
40+
* @return array The serialized data.
41+
*/
42+
protected function assertJsonSerializeReturnsArray($object): array
43+
{
44+
$json = $object->jsonSerialize();
45+
$this->assertIsArray($json, 'jsonSerialize() should return an array');
46+
return $json;
47+
}
48+
49+
/**
50+
* Asserts round-trip JSON serialization works correctly.
51+
*
52+
* @param object $original The original object.
53+
* @param callable $assertCallback Callback to assert equality between original and restored.
54+
* @return void
55+
*/
56+
protected function assertJsonRoundTrip($original, callable $assertCallback): void
57+
{
58+
$json = $original->jsonSerialize();
59+
$className = get_class($original);
60+
$restored = $className::fromJson($json);
61+
62+
$this->assertInstanceOf($className, $restored, 'fromJson() should return instance of ' . $className);
63+
$assertCallback($original, $restored);
64+
}
65+
66+
/**
67+
* Asserts that specific keys exist in serialized JSON.
68+
*
69+
* @param array $json The serialized JSON array.
70+
* @param array $expectedKeys The keys that should exist.
71+
* @return void
72+
*/
73+
protected function assertJsonHasKeys(array $json, array $expectedKeys): void
74+
{
75+
foreach ($expectedKeys as $key) {
76+
$this->assertArrayHasKey($key, $json, "JSON should contain key: {$key}");
77+
}
78+
}
79+
80+
/**
81+
* Asserts that specific keys do not exist in serialized JSON.
82+
*
83+
* @param array $json The serialized JSON array.
84+
* @param array $unexpectedKeys The keys that should not exist.
85+
* @return void
86+
*/
87+
protected function assertJsonNotHasKeys(array $json, array $unexpectedKeys): void
88+
{
89+
foreach ($unexpectedKeys as $key) {
90+
$this->assertArrayNotHasKey($key, $json, "JSON should not contain key: {$key}");
91+
}
92+
}
93+
}

tests/unit/Files/DTO/FileTest.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,4 +267,131 @@ public function testUrlWithUnknownExtension(): void
267267

268268
new File('https://example.com/file.unknown');
269269
}
270+
271+
/**
272+
* Tests JSON serialization for remote file.
273+
*
274+
* @return void
275+
*/
276+
public function testJsonSerializeRemoteFile(): void
277+
{
278+
$file = new File('https://example.com/image.jpg', 'image/jpeg');
279+
$json = $file->jsonSerialize();
280+
281+
$this->assertIsArray($json);
282+
$this->assertEquals(\WordPress\AiClient\Files\Enums\FileTypeEnum::remote()->value, $json['fileType']);
283+
$this->assertEquals('image/jpeg', $json['mimeType']);
284+
$this->assertEquals('https://example.com/image.jpg', $json['url']);
285+
$this->assertArrayNotHasKey('base64Data', $json);
286+
}
287+
288+
/**
289+
* Tests JSON serialization for inline file.
290+
*
291+
* @return void
292+
*/
293+
public function testJsonSerializeInlineFile(): void
294+
{
295+
$base64Data = 'SGVsbG8gV29ybGQ=';
296+
$dataUri = 'data:text/plain;base64,' . $base64Data;
297+
$file = new File($dataUri);
298+
$json = $file->jsonSerialize();
299+
300+
$this->assertIsArray($json);
301+
$this->assertEquals(\WordPress\AiClient\Files\Enums\FileTypeEnum::inline()->value, $json['fileType']);
302+
$this->assertEquals('text/plain', $json['mimeType']);
303+
$this->assertEquals($base64Data, $json['base64Data']);
304+
$this->assertArrayNotHasKey('url', $json);
305+
}
306+
307+
/**
308+
* Tests fromJson for remote file.
309+
*
310+
* @return void
311+
*/
312+
public function testFromJsonRemoteFile(): void
313+
{
314+
$json = [
315+
'fileType' => \WordPress\AiClient\Files\Enums\FileTypeEnum::remote()->value,
316+
'mimeType' => 'image/png',
317+
'url' => 'https://example.com/test.png'
318+
];
319+
320+
$file = File::fromJson($json);
321+
322+
$this->assertInstanceOf(File::class, $file);
323+
$this->assertTrue($file->getFileType()->isRemote());
324+
$this->assertEquals('image/png', $file->getMimeType());
325+
$this->assertEquals('https://example.com/test.png', $file->getUrl());
326+
$this->assertNull($file->getBase64Data());
327+
}
328+
329+
/**
330+
* Tests fromJson for inline file.
331+
*
332+
* @return void
333+
*/
334+
public function testFromJsonInlineFile(): void
335+
{
336+
$base64Data = 'SGVsbG8gV29ybGQ=';
337+
$json = [
338+
'fileType' => \WordPress\AiClient\Files\Enums\FileTypeEnum::inline()->value,
339+
'mimeType' => 'text/plain',
340+
'base64Data' => $base64Data
341+
];
342+
343+
$file = File::fromJson($json);
344+
345+
$this->assertInstanceOf(File::class, $file);
346+
$this->assertTrue($file->getFileType()->isInline());
347+
$this->assertEquals('text/plain', $file->getMimeType());
348+
$this->assertEquals($base64Data, $file->getBase64Data());
349+
$this->assertNull($file->getUrl());
350+
}
351+
352+
/**
353+
* Tests round-trip JSON serialization.
354+
*
355+
* @return void
356+
*/
357+
public function testJsonRoundTrip(): void
358+
{
359+
// Test remote file
360+
$remoteFile = new File('https://example.com/doc.pdf', 'application/pdf');
361+
$remoteJson = $remoteFile->jsonSerialize();
362+
$restoredRemote = File::fromJson($remoteJson);
363+
364+
$this->assertEquals($remoteFile->getFileType()->value, $restoredRemote->getFileType()->value);
365+
$this->assertEquals($remoteFile->getMimeType(), $restoredRemote->getMimeType());
366+
$this->assertEquals($remoteFile->getUrl(), $restoredRemote->getUrl());
367+
368+
// Test inline file
369+
$dataUri = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
370+
$inlineFile = new File($dataUri);
371+
$inlineJson = $inlineFile->jsonSerialize();
372+
$restoredInline = File::fromJson($inlineJson);
373+
374+
$this->assertEquals($inlineFile->getFileType()->value, $restoredInline->getFileType()->value);
375+
$this->assertEquals($inlineFile->getMimeType(), $restoredInline->getMimeType());
376+
$this->assertEquals($inlineFile->getBase64Data(), $restoredInline->getBase64Data());
377+
}
378+
379+
/**
380+
* Tests File implements WithJsonSerialization.
381+
*
382+
* @return void
383+
*/
384+
public function testImplementsWithJsonSerialization(): void
385+
{
386+
$file = new File('https://example.com/test.jpg');
387+
388+
$this->assertInstanceOf(
389+
\WordPress\AiClient\Common\Contracts\WithJsonSerialization::class,
390+
$file
391+
);
392+
$this->assertInstanceOf(
393+
\JsonSerializable::class,
394+
$file
395+
);
396+
}
270397
}

tests/unit/Messages/DTO/MessagePartTest.php

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use PHPUnit\Framework\TestCase;
88
use WordPress\AiClient\Files\DTO\File;
9+
use WordPress\AiClient\Files\Enums\FileTypeEnum;
910
use WordPress\AiClient\Messages\DTO\MessagePart;
1011
use WordPress\AiClient\Messages\Enums\MessagePartTypeEnum;
1112
use WordPress\AiClient\Tools\DTO\FunctionCall;
@@ -230,4 +231,135 @@ public function testWithUnicodeText(): void
230231

231232
$this->assertEquals($unicodeText, $part->getText());
232233
}
234+
235+
/**
236+
* Tests JSON serialization with text content.
237+
*
238+
* @return void
239+
*/
240+
public function testJsonSerializeWithText(): void
241+
{
242+
$part = new MessagePart('Hello, world!');
243+
$json = $part->jsonSerialize();
244+
245+
$this->assertIsArray($json);
246+
$this->assertArrayHasKey('type', $json);
247+
$this->assertArrayHasKey('text', $json);
248+
$this->assertEquals(MessagePartTypeEnum::text()->value, $json['type']);
249+
$this->assertEquals('Hello, world!', $json['text']);
250+
251+
// Ensure other fields are not present
252+
$this->assertArrayNotHasKey('file', $json);
253+
$this->assertArrayNotHasKey('functionCall', $json);
254+
$this->assertArrayNotHasKey('functionResponse', $json);
255+
}
256+
257+
/**
258+
* Tests JSON serialization with file content.
259+
*
260+
* @return void
261+
*/
262+
public function testJsonSerializeWithFile(): void
263+
{
264+
$file = new File('https://example.com/image.jpg', 'image/jpeg');
265+
$part = new MessagePart($file);
266+
$json = $part->jsonSerialize();
267+
268+
$this->assertIsArray($json);
269+
$this->assertArrayHasKey('type', $json);
270+
$this->assertArrayHasKey('file', $json);
271+
$this->assertEquals(MessagePartTypeEnum::file()->value, $json['type']);
272+
$this->assertIsArray($json['file']);
273+
}
274+
275+
/**
276+
* Tests fromJson with text content.
277+
*
278+
* @return void
279+
*/
280+
public function testFromJsonWithText(): void
281+
{
282+
$json = [
283+
'type' => MessagePartTypeEnum::text()->value,
284+
'text' => 'Test message'
285+
];
286+
287+
$part = MessagePart::fromJson($json);
288+
289+
$this->assertEquals(MessagePartTypeEnum::text(), $part->getType());
290+
$this->assertEquals('Test message', $part->getText());
291+
}
292+
293+
/**
294+
* Tests fromJson with file content.
295+
*
296+
* @return void
297+
*/
298+
public function testFromJsonWithFile(): void
299+
{
300+
$json = [
301+
'type' => MessagePartTypeEnum::file()->value,
302+
'file' => [
303+
'fileType' => FileTypeEnum::remote()->value,
304+
'mimeType' => 'image/jpeg',
305+
'url' => 'https://example.com/image.jpg'
306+
]
307+
];
308+
309+
$part = MessagePart::fromJson($json);
310+
311+
$this->assertEquals(MessagePartTypeEnum::file(), $part->getType());
312+
$this->assertInstanceOf(File::class, $part->getFile());
313+
$this->assertEquals('https://example.com/image.jpg', $part->getFile()->getUrl());
314+
}
315+
316+
/**
317+
* Tests round-trip JSON serialization with different content types.
318+
*
319+
* @return void
320+
*/
321+
public function testJsonRoundTrip(): void
322+
{
323+
// Test with text
324+
$textPart = new MessagePart('Test text');
325+
$textJson = $textPart->jsonSerialize();
326+
$restoredText = MessagePart::fromJson($textJson);
327+
$this->assertEquals($textPart->getText(), $restoredText->getText());
328+
329+
// Test with file
330+
$file = new File('https://example.com/doc.pdf', 'application/pdf');
331+
$filePart = new MessagePart($file);
332+
$fileJson = $filePart->jsonSerialize();
333+
$restoredFile = MessagePart::fromJson($fileJson);
334+
$this->assertEquals($file->getUrl(), $restoredFile->getFile()->getUrl());
335+
$this->assertEquals($file->getMimeType(), $restoredFile->getFile()->getMimeType());
336+
337+
// Test with function call
338+
$functionCall = new FunctionCall('id_123', 'getData', ['key' => 'value']);
339+
$funcPart = new MessagePart($functionCall);
340+
$funcJson = $funcPart->jsonSerialize();
341+
$restoredFunc = MessagePart::fromJson($funcJson);
342+
$this->assertEquals($functionCall->getId(), $restoredFunc->getFunctionCall()->getId());
343+
$this->assertEquals($functionCall->getName(), $restoredFunc->getFunctionCall()->getName());
344+
$this->assertEquals($functionCall->getArgs(), $restoredFunc->getFunctionCall()->getArgs());
345+
}
346+
347+
/**
348+
* Tests MessagePart implements WithJsonSerialization.
349+
*
350+
* @return void
351+
*/
352+
public function testImplementsWithJsonSerialization(): void
353+
{
354+
$part = new MessagePart('test');
355+
356+
$this->assertInstanceOf(
357+
\WordPress\AiClient\Common\Contracts\WithJsonSerialization::class,
358+
$part
359+
);
360+
$this->assertInstanceOf(
361+
\JsonSerializable::class,
362+
$part
363+
);
364+
}
233365
}

0 commit comments

Comments
 (0)