Skip to content

Commit 7184fe2

Browse files
committed
Added comments to unit tests
1 parent be5312d commit 7184fe2

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

UnitTests/UnitTests.HighPerformance.Shared/Extensions/Test_MemoryExtensions.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public class Test_MemoryExtensions
1919
[TestMethod]
2020
public void Test_MemoryExtensions_Cast_Empty()
2121
{
22+
// Casting an empty memory of any size should always be valid
23+
// and result in another empty memory, regardless of types.
2224
Memory<byte> m1 = default;
2325
Memory<byte> mc1 = m1.Cast<byte, byte>();
2426

@@ -34,11 +36,13 @@ public void Test_MemoryExtensions_Cast_Empty()
3436

3537
Assert.IsTrue(mc3.IsEmpty);
3638

39+
// Same as above, but with a sliced memory (length 12, slide from 12, so length of 0)
3740
Memory<byte> m4 = new byte[12].AsMemory(12);
3841
Memory<int> mc4 = m4.Cast<byte, int>();
3942

4043
Assert.IsTrue(mc4.IsEmpty);
4144

45+
// Same as above, but slicing to 12 in two steps
4246
Memory<byte> m5 = new byte[12].AsMemory().Slice(4).Slice(8);
4347
Memory<int> mc5 = m5.Cast<byte, int>();
4448

@@ -49,16 +53,19 @@ public void Test_MemoryExtensions_Cast_Empty()
4953
[TestMethod]
5054
public void Test_MemoryExtensions_Cast_TooShort()
5155
{
56+
// One int is 4 bytes, so casting from 3 rounds down to 0
5257
Memory<byte> m1 = new byte[3];
5358
Memory<int> mc1 = m1.Cast<byte, int>();
5459

5560
Assert.IsTrue(mc1.IsEmpty);
5661

62+
// Same as above, 13 / sizeof(int) == 3
5763
Memory<byte> m2 = new byte[13];
5864
Memory<float> mc2 = m2.Cast<byte, float>();
5965

6066
Assert.AreEqual(mc2.Length, 3);
6167

68+
// 16 - 5 = 11 ---> 11 / sizeof(int) = 2
6269
Memory<byte> m3 = new byte[16].AsMemory(5);
6370
Memory<float> mc3 = m3.Cast<byte, float>();
6471

@@ -69,6 +76,7 @@ public void Test_MemoryExtensions_Cast_TooShort()
6976
[TestMethod]
7077
public void Test_MemoryExtensions_FromArray_CastFromByte()
7178
{
79+
// Test for a standard cast from bytes with an evenly divisible length
7280
Memory<byte> memoryOfBytes = new byte[128];
7381
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
7482

@@ -77,6 +85,9 @@ public void Test_MemoryExtensions_FromArray_CastFromByte()
7785
Span<byte> spanOfBytes = memoryOfBytes.Span;
7886
Span<float> spanOfFloats = memoryOfFloats.Span;
7987

88+
// We also need to check that the Span<T> returned from the caast memory
89+
// actually has the initial reference pointing to the same location as
90+
// the one to the same item in the span from the original memory.
8091
Assert.AreEqual(memoryOfFloats.Length, spanOfFloats.Length);
8192
Assert.IsTrue(Unsafe.AreSame(
8293
ref spanOfBytes[0],
@@ -87,6 +98,8 @@ public void Test_MemoryExtensions_FromArray_CastFromByte()
8798
[TestMethod]
8899
public void Test_MemoryExtensions_FromArray_CastToByte()
89100
{
101+
// Cast from float to bytes to verify casting works when the target type
102+
// as a smaller byte size as well (so the resulting length will be larger).
90103
Memory<float> memoryOfFloats = new float[128];
91104
Memory<byte> memoryOfBytes = memoryOfFloats.Cast<float, byte>();
92105

@@ -95,6 +108,8 @@ public void Test_MemoryExtensions_FromArray_CastToByte()
95108
Span<float> spanOfFloats = memoryOfFloats.Span;
96109
Span<byte> spanOfBytes = memoryOfBytes.Span;
97110

111+
// Same as above, we need to verify that the resulting span has matching
112+
// starting references with the one produced by the original memory.
98113
Assert.AreEqual(memoryOfBytes.Length, spanOfBytes.Length);
99114
Assert.IsTrue(Unsafe.AreSame(
100115
ref spanOfFloats[0],
@@ -105,6 +120,7 @@ public void Test_MemoryExtensions_FromArray_CastToByte()
105120
[TestMethod]
106121
public void Test_MemoryExtensions_FromArray_CastToShort()
107122
{
123+
// Similar test as above, just with different types to double check
108124
Memory<float> memoryOfFloats = new float[128];
109125
Memory<short> memoryOfShorts = memoryOfFloats.Cast<float, short>();
110126

@@ -123,13 +139,20 @@ public void Test_MemoryExtensions_FromArray_CastToShort()
123139
[TestMethod]
124140
public void Test_MemoryExtensions_FromArray_CastFromByteAndBack()
125141
{
142+
// Here we start from a byte array, get a memory, then cast to float and then
143+
// back to byte. We want to verify that the final memory is both valid and
144+
// consistent, as well that our internal optimization works and that the final
145+
// memory correctly skipped the indirect memory managed and just wrapped the original
146+
// array instead. This is documented in the custom array memory manager in the package.
126147
var data = new byte[128];
127148
Memory<byte> memoryOfBytes = data;
128149
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
129150
Memory<byte> memoryBack = memoryOfFloats.Cast<float, byte>();
130151

131152
Assert.AreEqual(memoryOfBytes.Length, memoryBack.Length);
132153

154+
// Here we get the array from the final memory and check that it does exist and
155+
// the associated parameters match the ones we'd expect here (same length, offset of 0).
133156
Assert.IsTrue(MemoryMarshal.TryGetArray<byte>(memoryBack, out var segment));
134157
Assert.AreSame(segment.Array!, data);
135158
Assert.AreEqual(segment.Offset, 0);
@@ -140,13 +163,16 @@ public void Test_MemoryExtensions_FromArray_CastFromByteAndBack()
140163
Span<byte> span1 = memoryOfBytes.Span;
141164
Span<byte> span2 = memoryBack.Span;
142165

166+
// Also validate the initial and final spans for reference equality
143167
Assert.IsTrue(span1 == span2);
144168
}
145169

146170
[TestCategory("MemoryExtensions")]
147171
[TestMethod]
148172
public void Test_MemoryExtensions_Cast_TooShort_WithSlice()
149173
{
174+
// Like we did above, we have some more tests where we slice an initial memory and
175+
// validate the length of the resulting, accounting for the expected rounding down.
150176
Memory<byte> m1 = new byte[8].AsMemory().Slice(4, 3);
151177
Memory<int> mc1 = m1.Cast<byte, int>();
152178

@@ -167,6 +193,8 @@ public void Test_MemoryExtensions_Cast_TooShort_WithSlice()
167193
[TestMethod]
168194
public void Test_MemoryExtensions_FromArray_CastFromByte_WithSlice()
169195
{
196+
// Same exact test as the cast from byte to float did above, but with a slice. This is done
197+
// to ensure the cast still works correctly when the memory is internally storing an offset.
170198
Memory<byte> memoryOfBytes = new byte[512].AsMemory().Slice(128, 128);
171199
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
172200

@@ -185,6 +213,7 @@ public void Test_MemoryExtensions_FromArray_CastFromByte_WithSlice()
185213
[TestMethod]
186214
public void Test_MemoryExtensions_FromArray_CastToByte_WithSlice()
187215
{
216+
// Same as above, just with inverted source and destination types
188217
Memory<float> memoryOfFloats = new float[512].AsMemory().Slice(128, 128);
189218
Memory<byte> memoryOfBytes = memoryOfFloats.Cast<float, byte>();
190219

@@ -203,6 +232,8 @@ public void Test_MemoryExtensions_FromArray_CastToByte_WithSlice()
203232
[TestMethod]
204233
public void Test_MemoryExtensions_FromArray_CastToShort_WithSlice()
205234
{
235+
// Once again the same test but with types both different in size than 1. We're mostly
236+
// just testing the rounding logic in a number of different case to ensure it's correct.
206237
Memory<float> memoryOfFloats = new float[512].AsMemory().Slice(128, 128);
207238
Memory<short> memoryOfShorts = memoryOfFloats.Cast<float, short>();
208239

@@ -221,13 +252,15 @@ public void Test_MemoryExtensions_FromArray_CastToShort_WithSlice()
221252
[TestMethod]
222253
public void Test_MemoryExtensions_FromArray_CastFromByteAndBack_WithSlice()
223254
{
255+
// Just like the equivalent test above, but with a slice thrown in too
224256
var data = new byte[512];
225257
Memory<byte> memoryOfBytes = data.AsMemory().Slice(128, 128);
226258
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
227259
Memory<byte> memoryBack = memoryOfFloats.Cast<float, byte>();
228260

229261
Assert.AreEqual(memoryOfBytes.Length, memoryBack.Length);
230262

263+
// Here we now also have to validate the starting offset from the extracted array
231264
Assert.IsTrue(MemoryMarshal.TryGetArray<byte>(memoryBack, out var segment));
232265
Assert.AreSame(segment.Array!, data);
233266
Assert.AreEqual(segment.Offset, 128);
@@ -245,6 +278,10 @@ public void Test_MemoryExtensions_FromArray_CastFromByteAndBack_WithSlice()
245278
[TestMethod]
246279
public void Test_MemoryExtensions_FromMemoryManager_CastFromByte()
247280
{
281+
// This test is just like the ones above, but this time we're casting a memory
282+
// that wraps a custom memory manager and not an array. This is done to ensure
283+
// the casting logic works correctly in all cases, as it'll use a different
284+
// memory manager internally (a memory can wrap a string, an array or a manager).
248285
Memory<byte> memoryOfBytes = new ArrayMemoryManager<byte>(128);
249286
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
250287

@@ -263,6 +300,7 @@ public void Test_MemoryExtensions_FromMemoryManager_CastFromByte()
263300
[TestMethod]
264301
public void Test_MemoryExtensions_FromMemoryManager_CastToByte()
265302
{
303+
// Same as above, but with inverted types
266304
Memory<float> memoryOfFloats = new ArrayMemoryManager<float>(128);
267305
Memory<byte> memoryOfBytes = memoryOfFloats.Cast<float, byte>();
268306

@@ -281,6 +319,7 @@ public void Test_MemoryExtensions_FromMemoryManager_CastToByte()
281319
[TestMethod]
282320
public void Test_MemoryExtensions_FromMemoryManager_CastToShort()
283321
{
322+
// Same as above, but with types different in size than 1, just in case
284323
Memory<float> memoryOfFloats = new ArrayMemoryManager<float>(128);
285324
Memory<short> memoryOfShorts = memoryOfFloats.Cast<float, short>();
286325

@@ -299,13 +338,16 @@ public void Test_MemoryExtensions_FromMemoryManager_CastToShort()
299338
[TestMethod]
300339
public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack()
301340
{
341+
// Equivalent to the one with an array, but with a memory manager
302342
var data = new ArrayMemoryManager<byte>(128);
303343
Memory<byte> memoryOfBytes = data;
304344
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
305345
Memory<byte> memoryBack = memoryOfFloats.Cast<float, byte>();
306346

307347
Assert.AreEqual(memoryOfBytes.Length, memoryBack.Length);
308348

349+
// Here we expect to get back the original memory manager, due to the same optimization we
350+
// checked for when using an array. We need to check they're the same, and the other parameters.
309351
Assert.IsTrue(MemoryMarshal.TryGetMemoryManager<byte, ArrayMemoryManager<byte>>(memoryBack, out var manager, out var start, out var length));
310352
Assert.AreSame(manager!, data);
311353
Assert.AreEqual(start, 0);
@@ -323,6 +365,7 @@ public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack()
323365
[TestMethod]
324366
public void Test_MemoryExtensions_FromMemoryManager_CastFromByte_WithSlice()
325367
{
368+
// Same as the ones with an array, but with an extra slice
326369
Memory<byte> memoryOfBytes = new ArrayMemoryManager<byte>(512).Memory.Slice(128, 128);
327370
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
328371

@@ -341,6 +384,7 @@ public void Test_MemoryExtensions_FromMemoryManager_CastFromByte_WithSlice()
341384
[TestMethod]
342385
public void Test_MemoryExtensions_FromMemoryManager_CastToByte_WithSlice()
343386
{
387+
// Same as above, but with inverted types
344388
Memory<float> memoryOfFloats = new ArrayMemoryManager<float>(512).Memory.Slice(128, 128);
345389
Memory<byte> memoryOfBytes = memoryOfFloats.Cast<float, byte>();
346390

@@ -359,6 +403,7 @@ public void Test_MemoryExtensions_FromMemoryManager_CastToByte_WithSlice()
359403
[TestMethod]
360404
public void Test_MemoryExtensions_FromMemoryManager_CastToShort_WithSlice()
361405
{
406+
// Same as above but with different types
362407
Memory<float> memoryOfFloats = new ArrayMemoryManager<float>(512).Memory.Slice(128, 128);
363408
Memory<short> memoryOfShorts = memoryOfFloats.Cast<float, short>();
364409

@@ -377,13 +422,15 @@ public void Test_MemoryExtensions_FromMemoryManager_CastToShort_WithSlice()
377422
[TestMethod]
378423
public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack_WithSlice()
379424
{
425+
// Just like the one above, but with the slice
380426
var data = new ArrayMemoryManager<byte>(512);
381427
Memory<byte> memoryOfBytes = data.Memory.Slice(128, 128);
382428
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>();
383429
Memory<byte> memoryBack = memoryOfFloats.Cast<float, byte>();
384430

385431
Assert.AreEqual(memoryOfBytes.Length, memoryBack.Length);
386432

433+
// Here we also need to validate that the offset was maintained
387434
Assert.IsTrue(MemoryMarshal.TryGetMemoryManager<byte, ArrayMemoryManager<byte>>(memoryBack, out var manager, out var start, out var length));
388435
Assert.AreSame(manager!, data);
389436
Assert.AreEqual(start, 128);
@@ -410,6 +457,12 @@ public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack_WithSlic
410457
[DataRow(256, 64, 8)]
411458
public unsafe void Test_MemoryExtensions_FromArray_CastFromByte_Pin(int size, int preOffset, int postOffset)
412459
{
460+
// Here we need to validate that pinning works correctly in a number of cases. First we allocate
461+
// an array of the requested size, then get a memory after slicing to a target position, then cast
462+
// and then slice again. We do so to ensure that pinning correctly tracks the correct index with
463+
// respect to the original array through a number of internal offsets. As in, when pinning the
464+
// final memory, our internal custom memory manager should be able to pin the item in the original
465+
// array at offset preOffset + (postOffset * sizeof(float)), accounting for the cast as well.
413466
var data = new byte[size];
414467
Memory<byte> memoryOfBytes = data.AsMemory(preOffset);
415468
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>().Slice(postOffset);
@@ -435,6 +488,7 @@ public unsafe void Test_MemoryExtensions_FromArray_CastFromByte_Pin(int size, in
435488
[DataRow(256, 64, 8)]
436489
public unsafe void Test_MemoryExtensions_FromMemoryManager_CastFromByte_Pin(int size, int preOffset, int postOffset)
437490
{
491+
// Just like the test above, but this type the initial memory wraps a memory manager
438492
var data = new ArrayMemoryManager<byte>(size);
439493
Memory<byte> memoryOfBytes = data.Memory.Slice(preOffset);
440494
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>().Slice(postOffset);
@@ -451,13 +505,16 @@ public unsafe void Test_MemoryExtensions_FromMemoryManager_CastFromByte_Pin(int
451505
[TestMethod]
452506
public void Test_MemoryExtensions_FromString_CastFromByteAndBack()
453507
{
508+
// This is the same as the tests above, but here we're testing the
509+
// other remaining case, that is when a memory is wrapping a string.
454510
var data = new string('a', 128);
455511
Memory<char> memoryOfChars = MemoryMarshal.AsMemory(data.AsMemory());
456512
Memory<float> memoryOfFloats = memoryOfChars.Cast<char, float>();
457513
Memory<char> memoryBack = memoryOfFloats.Cast<float, char>();
458514

459515
Assert.AreEqual(memoryOfChars.Length, memoryBack.Length);
460516

517+
// Get the original string back (to validate the optimization too) and check the params
461518
Assert.IsTrue(MemoryMarshal.TryGetString(memoryOfChars, out var text, out int start, out int length));
462519
Assert.AreSame(text!, data);
463520
Assert.AreEqual(start, 0);
@@ -484,6 +541,7 @@ public void Test_MemoryExtensions_FromString_CastFromByteAndBack()
484541
[DataRow(256, 64, 8)]
485542
public unsafe void Test_MemoryExtensions_FromString_CastAndPin(int size, int preOffset, int postOffset)
486543
{
544+
// Same test as before to validate pinning, but starting from a string
487545
var data = new string('a', size);
488546
Memory<char> memoryOfChars = MemoryMarshal.AsMemory(data.AsMemory()).Slice(preOffset);
489547
Memory<byte> memoryOfBytes = memoryOfChars.Cast<char, byte>().Slice(postOffset);
@@ -496,6 +554,8 @@ public unsafe void Test_MemoryExtensions_FromString_CastAndPin(int size, int pre
496554
Assert.IsTrue(p1 == p2);
497555
}
498556

557+
// Here we also add an extra test just like the one above, but casting to a type
558+
// that is bigger in byte size than char. Just to double check the casting logic.
499559
Memory<int> memoryOfInts = memoryOfChars.Cast<char, int>().Slice(postOffset);
500560

501561
using (var handle2 = memoryOfInts.Pin())
@@ -513,6 +573,7 @@ public void Test_MemoryExtensions_EmptyMemoryStream()
513573
{
514574
Memory<byte> memory = default;
515575

576+
// Creating a stream from a default memory is valid, it's just empty
516577
Stream stream = memory.AsStream();
517578

518579
Assert.IsNotNull(stream);

0 commit comments

Comments
 (0)