Imported Upstream version 1.21.0
[platform/upstream/grpc.git] / src / csharp / Grpc.Core.Tests / Internal / FakeBufferReaderManager.cs
1 #region Copyright notice and license
2
3 // Copyright 2018 The gRPC Authors
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 #endregion
18
19 using System;
20 using System.Collections.Generic;
21 using System.Runtime.InteropServices;
22 using System.Threading.Tasks;
23
24 using Grpc.Core.Internal;
25 using Grpc.Core.Utils;
26
27 namespace Grpc.Core.Internal.Tests
28 {
29     // Creates instances of fake IBufferReader. All created instances will become invalid once Dispose is called.
30     internal class FakeBufferReaderManager : IDisposable
31     {
32         List<GCHandle> pinnedHandles = new List<GCHandle>();
33         bool disposed = false;
34         public IBufferReader CreateSingleSegmentBufferReader(byte[] data)
35         {
36             return CreateMultiSegmentBufferReader(new List<byte[]> { data });
37         }
38
39         public IBufferReader CreateMultiSegmentBufferReader(IEnumerable<byte[]> dataSegments)
40         {
41             GrpcPreconditions.CheckState(!disposed);
42             GrpcPreconditions.CheckNotNull(dataSegments);
43             var segments = new List<GCHandle>();
44             foreach (var data in dataSegments)
45             {
46                 GrpcPreconditions.CheckNotNull(data);
47                 segments.Add(GCHandle.Alloc(data, GCHandleType.Pinned));
48             }
49             pinnedHandles.AddRange(segments);  // all the allocated GCHandles will be freed on Dispose()
50             return new FakeBufferReader(segments);
51         }
52
53         public IBufferReader CreateNullPayloadBufferReader()
54         {
55             GrpcPreconditions.CheckState(!disposed);
56             return new FakeBufferReader(null);
57         }
58
59         public void Dispose()
60         {
61             if (!disposed)
62             {
63                 disposed = true;
64                 for (int i = 0; i < pinnedHandles.Count; i++)
65                 {
66                     pinnedHandles[i].Free();
67                 }
68             }
69         }
70
71         private class FakeBufferReader : IBufferReader
72         {
73             readonly List<GCHandle> bufferSegments;
74             readonly int? totalLength;
75             readonly IEnumerator<GCHandle> segmentEnumerator;
76
77             public FakeBufferReader(List<GCHandle> bufferSegments)
78             {
79                 this.bufferSegments = bufferSegments;
80                 this.totalLength = ComputeTotalLength(bufferSegments);
81                 this.segmentEnumerator = bufferSegments?.GetEnumerator();
82             }
83
84             public int? TotalLength => totalLength;
85
86             public bool TryGetNextSlice(out Slice slice)
87             {
88                 GrpcPreconditions.CheckNotNull(bufferSegments);
89                 if (!segmentEnumerator.MoveNext())
90                 {
91                     slice = default(Slice);
92                     return false;
93                 }
94
95                 var segment = segmentEnumerator.Current;
96                 int sliceLen = ((byte[]) segment.Target).Length;
97                 slice = new Slice(segment.AddrOfPinnedObject(), sliceLen);
98                 return true;
99             }
100
101             static int? ComputeTotalLength(List<GCHandle> bufferSegments)
102             {
103                 if (bufferSegments == null)
104                 {
105                     return null;
106                 }
107
108                 int sum = 0;
109                 foreach (var segment in bufferSegments)
110                 {
111                     var data = (byte[]) segment.Target;
112                     sum += data.Length;
113                 }
114                 return sum;
115             }
116         }
117     }
118 }