22// Licensed under the MIT License.
33
44using System ;
5+ using System . ClientModel ;
6+ using System . Collections . Generic ;
7+ using System . IO ;
8+ using System . Runtime . CompilerServices ;
9+ using System . Text ;
10+ using System . Text . Json ;
11+ using System . Threading ;
512using System . Threading . Tasks ;
613using NUnit . Framework ;
714using Streaming . Jsonl ;
@@ -10,13 +17,17 @@ namespace TestProjects.Spector.Tests.Http.Streaming.Jsonl
1017{
1118 public class JsonlTests : SpectorTestBase
1219 {
13- private const string ExpectedJsonl = "{\" desc\" : \" one\" }\n {\" desc\" : \" two\" }\n {\" desc\" : \" three\" }" ;
14-
1520 [ SpectorTest ]
1621 public Task BasicSend ( ) => Test ( async ( host ) =>
1722 {
1823 var client = new JsonlClient ( host , null ) . GetBasicClient ( ) ;
19- var stream = StreamingJsonlModelFactory . JsonlStreamInfo ( BinaryData . FromString ( ExpectedJsonl ) ) ;
24+
25+ // Build the JSONL payload line-by-line from Info objects, demonstrating
26+ // the streaming-friendly pattern: each line is independently serialized.
27+ var items = new [ ] { new Info ( "one" ) , new Info ( "two" ) , new Info ( "three" ) } ;
28+ var jsonlPayload = string . Join ( "\n " , Array . ConvertAll ( items , i => JsonSerializer . Serialize ( i ) ) ) ;
29+
30+ var stream = StreamingJsonlModelFactory . JsonlStreamInfo ( BinaryData . FromString ( jsonlPayload ) ) ;
2031 var response = await client . SendAsync ( stream ) ;
2132
2233 Assert . AreEqual ( 204 , response . GetRawResponse ( ) . Status ) ;
@@ -26,10 +37,64 @@ public Task BasicSend() => Test(async (host) =>
2637 public Task BasicReceive ( ) => Test ( async ( host ) =>
2738 {
2839 var client = new JsonlClient ( host , null ) . GetBasicClient ( ) ;
29- var response = await client . ReceiveAsync ( ) ;
3040
31- Assert . AreEqual ( 200 , response . GetRawResponse ( ) . Status ) ;
32- BinaryDataAssert . AreEqual ( BinaryData . FromString ( ExpectedJsonl ) , response . Value ) ;
41+ // Use the protocol method to get the raw response stream, then
42+ // enumerate JSONL lines as IAsyncEnumerable<Info> without buffering
43+ // the entire payload into memory.
44+ ClientResult result = await client . ReceiveAsync ( options : null ) ;
45+ var rawResponse = result . GetRawResponse ( ) ;
46+ Assert . AreEqual ( 200 , rawResponse . Status ) ;
47+ Assert . IsNotNull ( rawResponse . ContentStream ) ;
48+
49+ var received = new List < Info > ( ) ;
50+ await foreach ( var info in EnumerateJsonlAsync < Info > ( rawResponse . ContentStream ! ) )
51+ {
52+ received . Add ( info ) ;
53+ }
54+
55+ Assert . AreEqual ( 3 , received . Count ) ;
56+ Assert . AreEqual ( "one" , received [ 0 ] . Desc ) ;
57+ Assert . AreEqual ( "two" , received [ 1 ] . Desc ) ;
58+ Assert . AreEqual ( "three" , received [ 2 ] . Desc ) ;
3359 } ) ;
60+
61+ /// <summary>
62+ /// Reads a stream of JSONL (JSON Lines) data and yields each line as a
63+ /// deserialized <typeparamref name="T"/> instance. This demonstrates the
64+ /// <see cref="IAsyncEnumerable{T}"/> pattern that the generator should
65+ /// eventually emit for streaming operations — reading line-by-line avoids
66+ /// buffering the entire payload into memory.
67+ /// </summary>
68+ private static async IAsyncEnumerable < T > EnumerateJsonlAsync < T > (
69+ Stream contentStream ,
70+ [ EnumeratorCancellation ] CancellationToken cancellationToken = default )
71+ {
72+ using var reader = new StreamReader ( contentStream , Encoding . UTF8 ) ;
73+ string ? line ;
74+ while ( ( line = await reader . ReadLineAsync ( cancellationToken ) ) is not null )
75+ {
76+ if ( string . IsNullOrWhiteSpace ( line ) )
77+ continue ;
78+ yield return JsonSerializer . Deserialize < T > ( line ) ! ;
79+ }
80+ }
81+
82+ /// <summary>
83+ /// Local representation of the Streaming.Jsonl.Basic.Info model for test
84+ /// deserialization. The generator does not yet emit this type because the
85+ /// JSONL body is treated as raw bytes in the current code model.
86+ /// </summary>
87+ private sealed class Info
88+ {
89+ public Info ( ) { }
90+
91+ public Info ( string desc )
92+ {
93+ Desc = desc ;
94+ }
95+
96+ [ System . Text . Json . Serialization . JsonPropertyName ( "desc" ) ]
97+ public string ? Desc { get ; set ; }
98+ }
3499 }
35100}
0 commit comments