1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Buffers;
6 using System.Runtime.InteropServices;
7 using System.Threading;
8 using System.Threading.Tasks;
9 using Xunit;
10 
11 namespace System.IO.Tests
12 {
13     public class Stream_ReadWriteSpan
14     {
15         [Fact]
ReadSpan_DelegatesToRead_Success()16         public void ReadSpan_DelegatesToRead_Success()
17         {
18             bool readInvoked = false;
19             var s = new DelegateStream(
20                 canReadFunc: () => true,
21                 readFunc: (array, offset, count) =>
22                 {
23                     readInvoked = true;
24                     Assert.NotNull(array);
25                     Assert.Equal(0, offset);
26                     Assert.Equal(20, count);
27 
28                     for (int i = 0; i < 10; i++) array[offset + i] = (byte)i;
29                     return 10;
30                 });
31 
32             Span<byte> totalSpan = new byte[30];
33             Span<byte> targetSpan = totalSpan.Slice(5, 20);
34 
35             Assert.Equal(10, s.Read(targetSpan));
36             Assert.True(readInvoked);
37             for (int i = 0; i < 10; i++) Assert.Equal(i, targetSpan[i]);
38             for (int i = 10; i < 20; i++) Assert.Equal(0, targetSpan[i]);
39             readInvoked = false;
40         }
41 
42         [Fact]
WriteSpan_DelegatesToWrite_Success()43         public void WriteSpan_DelegatesToWrite_Success()
44         {
45             bool writeInvoked = false;
46             var s = new DelegateStream(
47                 canWriteFunc: () => true,
48                 writeFunc: (array, offset, count) =>
49                 {
50                     writeInvoked = true;
51                     Assert.NotNull(array);
52                     Assert.Equal(0, offset);
53                     Assert.Equal(3, count);
54 
55                     for (int i = 0; i < count; i++) Assert.Equal(i, array[offset + i]);
56                 });
57 
58             Span<byte> span = new byte[10];
59             span[3] = 1;
60             span[4] = 2;
61             s.Write(span.Slice(2, 3));
62             Assert.True(writeInvoked);
63             writeInvoked = false;
64         }
65 
66         [Fact]
ReadAsyncMemory_WrapsArray_DelegatesToReadAsyncArray_Success()67         public async Task ReadAsyncMemory_WrapsArray_DelegatesToReadAsyncArray_Success()
68         {
69             bool readInvoked = false;
70             var s = new DelegateStream(
71                 canReadFunc: () => true,
72                 readAsyncFunc: (array, offset, count, cancellationToken) =>
73                 {
74                     readInvoked = true;
75                     Assert.NotNull(array);
76                     Assert.Equal(5, offset);
77                     Assert.Equal(20, count);
78 
79                     for (int i = 0; i < 10; i++)
80                     {
81                         array[offset + i] = (byte)i;
82                     }
83                     return Task.FromResult(10);
84                 });
85 
86             Memory<byte> totalMemory = new byte[30];
87             Memory<byte> targetMemory = totalMemory.Slice(5, 20);
88 
89             Assert.Equal(10, await s.ReadAsync(targetMemory));
90             Assert.True(readInvoked);
91             for (int i = 0; i < 10; i++)
92                 Assert.Equal(i, targetMemory.Span[i]);
93             for (int i = 10; i < 20; i++)
94                 Assert.Equal(0, targetMemory.Span[i]);
95             readInvoked = false;
96         }
97 
98         [Fact]
ReadAsyncMemory_WrapsNative_DelegatesToReadAsyncArrayWithPool_Success()99         public async Task ReadAsyncMemory_WrapsNative_DelegatesToReadAsyncArrayWithPool_Success()
100         {
101             bool readInvoked = false;
102             var s = new DelegateStream(
103                 canReadFunc: () => true,
104                 readAsyncFunc: (array, offset, count, cancellationToken) =>
105                 {
106                     readInvoked = true;
107                     Assert.NotNull(array);
108                     Assert.Equal(0, offset);
109                     Assert.Equal(20, count);
110 
111                     for (int i = 0; i < 10; i++)
112                     {
113                         array[offset + i] = (byte)i;
114                     }
115                     return Task.FromResult(10);
116                 });
117 
118             using (var totalNativeMemory = new NativeOwnedMemory(30))
119             {
120                 Memory<byte> totalMemory = totalNativeMemory.Memory;
121                 Memory<byte> targetMemory = totalMemory.Slice(5, 20);
122 
123                 Assert.Equal(10, await s.ReadAsync(targetMemory));
124                 Assert.True(readInvoked);
125                 for (int i = 0; i < 10; i++)
126                     Assert.Equal(i, targetMemory.Span[i]);
127                 readInvoked = false;
128             }
129         }
130 
131         [Fact]
WriteAsyncMemory_WrapsArray_DelegatesToWrite_Success()132         public async Task WriteAsyncMemory_WrapsArray_DelegatesToWrite_Success()
133         {
134             bool writeInvoked = false;
135             var s = new DelegateStream(
136                 canWriteFunc: () => true,
137                 writeAsyncFunc: (array, offset, count, cancellationToken) =>
138                 {
139                     writeInvoked = true;
140                     Assert.NotNull(array);
141                     Assert.Equal(2, offset);
142                     Assert.Equal(3, count);
143 
144                     for (int i = 0; i < count; i++)
145                         Assert.Equal(i, array[offset + i]);
146 
147                     return Task.CompletedTask;
148                 });
149 
150             Memory<byte> memory = new byte[10];
151             memory.Span[3] = 1;
152             memory.Span[4] = 2;
153             await s.WriteAsync(memory.Slice(2, 3));
154             Assert.True(writeInvoked);
155             writeInvoked = false;
156         }
157 
158         [Fact]
WriteAsyncMemory_WrapsNative_DelegatesToWrite_Success()159         public async Task WriteAsyncMemory_WrapsNative_DelegatesToWrite_Success()
160         {
161             bool writeInvoked = false;
162             var s = new DelegateStream(
163                 canWriteFunc: () => true,
164                 writeAsyncFunc: (array, offset, count, cancellationToken) =>
165                 {
166                     writeInvoked = true;
167                     Assert.NotNull(array);
168                     Assert.Equal(0, offset);
169                     Assert.Equal(3, count);
170 
171                     for (int i = 0; i < count; i++)
172                         Assert.Equal(i, array[i]);
173 
174                     return Task.CompletedTask;
175                 });
176 
177             using (var nativeMemory = new NativeOwnedMemory(10))
178             {
179                 Memory<byte> memory = nativeMemory.Memory;
180                 memory.Span[2] = 0;
181                 memory.Span[3] = 1;
182                 memory.Span[4] = 2;
183                 await s.WriteAsync(memory.Slice(2, 3));
184                 Assert.True(writeInvoked);
185                 writeInvoked = false;
186             }
187         }
188     }
189 }
190