@@ -287,54 +287,59 @@ public async Task ReceiveData_ReceivesDataThenTimesout_StreamDisposed()
287287 Assert . False ( success ) ;
288288 }
289289
290- [ Fact ]
291- public async Task ReadAsync_ByteArray_DisposesCancellationTokenSource ( )
290+ [ Theory ]
291+ [ InlineData ( false ) ]
292+ [ InlineData ( true ) ]
293+ public void ValueLinkedCts_Works_WhenOneTokenCannotBeCanceled ( bool isToken1Cancelable )
292294 {
293- // Arrange
294- var jsStreamReference = Mock . Of < IJSStreamReference > ( ) ;
295- var remoteJSDataStream = await RemoteJSDataStream . CreateRemoteJSDataStreamAsync ( _jsRuntime , jsStreamReference , totalLength : 100 , signalRMaximumIncomingBytes : 10_000 , jsInteropDefaultCallTimeout : TimeSpan . FromMinutes ( 1 ) , cancellationToken : CancellationToken . None ) . DefaultTimeout ( ) ;
296- var buffer = new byte [ 100 ] ;
297- var chunk = new byte [ 100 ] ;
298- new Random ( ) . NextBytes ( chunk ) ;
299-
300- // Act
301295 var cts = new CancellationTokenSource ( ) ;
302- var sendDataTask = Task . Run ( async ( ) =>
303- {
304- await RemoteJSDataStream . ReceiveData ( _jsRuntime , GetStreamId ( remoteJSDataStream , _jsRuntime ) , chunkId : 0 , chunk , error : null ) ;
305- } ) ;
296+ var token1 = isToken1Cancelable ? cts . Token : CancellationToken . None ;
297+ var token2 = isToken1Cancelable ? CancellationToken . None : cts . Token ;
306298
307- await sendDataTask ;
308- var result = await remoteJSDataStream . ReadAsync ( buffer , 0 , buffer . Length , cts . Token ) ;
299+ using var linkedCts = RemoteJSDataStream . ValueLinkedCancellationTokenSource . Create ( token1 , token2 ) ;
309300
310- // Assert
311- Assert . True ( cts . Token . CanBeCanceled ) ;
312- Assert . False ( cts . IsCancellationRequested ) ;
301+ Assert . False ( linkedCts . HasLinkedCancellationTokenSource ) ;
302+ Assert . False ( linkedCts . Token . IsCancellationRequested ) ;
303+
304+ cts . Cancel ( ) ;
305+
306+ Assert . True ( linkedCts . Token . IsCancellationRequested ) ;
313307 }
314308
315309 [ Fact ]
316- public async Task ReadAsync_Memory_DisposesCancellationTokenSource ( )
310+ public void ValueLinkedCts_Works_WhenBothTokensCannotBeCanceled ( )
317311 {
318- // Arrange
319- var jsStreamReference = Mock . Of < IJSStreamReference > ( ) ;
320- var remoteJSDataStream = await RemoteJSDataStream . CreateRemoteJSDataStreamAsync ( _jsRuntime , jsStreamReference , totalLength : 100 , signalRMaximumIncomingBytes : 10_000 , jsInteropDefaultCallTimeout : TimeSpan . FromMinutes ( 1 ) , cancellationToken : CancellationToken . None ) . DefaultTimeout ( ) ;
321- var buffer = new Memory < byte > ( new byte [ 100 ] ) ;
322- var chunk = new byte [ 100 ] ;
323- new Random ( ) . NextBytes ( chunk ) ;
312+ using var linkedCts = RemoteJSDataStream . ValueLinkedCancellationTokenSource . Create (
313+ CancellationToken . None ,
314+ CancellationToken . None ) ;
324315
325- // Act
326- var cts = new CancellationTokenSource ( ) ;
327- var sendDataTask = Task . Run ( async ( ) =>
328- {
329- await RemoteJSDataStream . ReceiveData ( _jsRuntime , GetStreamId ( remoteJSDataStream , _jsRuntime ) , chunkId : 0 , chunk , error : null ) ;
330- } ) ;
316+ Assert . False ( linkedCts . HasLinkedCancellationTokenSource ) ;
317+ Assert . False ( linkedCts . Token . IsCancellationRequested ) ;
318+ }
331319
332- await sendDataTask ;
333- var result = await remoteJSDataStream . ReadAsync ( buffer , cts . Token ) ;
320+ [ Theory ]
321+ [ InlineData ( false , true ) ]
322+ [ InlineData ( true , false ) ]
323+ [ InlineData ( true , true ) ]
324+ public void ValueLinkedCts_Works_WhenBothTokensCanBeCanceled ( bool shouldCancelToken1 , bool shouldCancelToken2 )
325+ {
326+ var cts1 = new CancellationTokenSource ( ) ;
327+ var cts2 = new CancellationTokenSource ( ) ;
328+ using var linkedCts = RemoteJSDataStream . ValueLinkedCancellationTokenSource . Create ( cts1 . Token , cts2 . Token ) ;
334329
335- // Assert
336- Assert . True ( cts . Token . CanBeCanceled ) ;
337- Assert . False ( cts . IsCancellationRequested ) ;
330+ Assert . True ( linkedCts . HasLinkedCancellationTokenSource ) ;
331+ Assert . False ( linkedCts . Token . IsCancellationRequested ) ;
332+
333+ if ( shouldCancelToken1 )
334+ {
335+ cts1 . Cancel ( ) ;
336+ }
337+ if ( shouldCancelToken2 )
338+ {
339+ cts2 . Cancel ( ) ;
340+ }
341+
342+ Assert . True ( linkedCts . Token . IsCancellationRequested ) ;
338343 }
339344
340345 private static async Task < RemoteJSDataStream > CreateRemoteJSDataStreamAsync ( TestRemoteJSRuntime jsRuntime = null )
0 commit comments