Skip to content

Commit d12024f

Browse files
authored
Fix SpanByte for edge cases (#182)
1 parent 8147509 commit d12024f

File tree

3 files changed

+234
-4
lines changed

3 files changed

+234
-4
lines changed

Diff for: Tests/NFUnitTestTypes/NFUnitTestTypes.nfproj

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
</PropertyGroup>
2929
<ItemGroup>
3030
<Compile Include="UnitTestObjectTypeTests.cs" />
31+
<Compile Include="UnitTestsSpanByte.cs" />
3132
<Compile Include="UnitTestSubTypeTests.cs" />
3233
<Compile Include="UnitTestValueArrayTypess.cs" />
3334
<Compile Include="Properties\AssemblyInfo.cs" />

Diff for: Tests/NFUnitTestTypes/UnitTestsSpanByte.cs

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
//
2+
// Copyright (c) .NET Foundation and Contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using nanoFramework.TestFramework;
7+
using System;
8+
9+
namespace NFUnitTestTypes
10+
{
11+
[TestClass]
12+
public class UnitTestsSpanByte
13+
{
14+
[TestMethod]
15+
public void EmptySpanTests()
16+
{
17+
// Empty span
18+
SpanByte span = SpanByte.Empty;
19+
// Create a destination span larger
20+
SpanByte destination = new byte[1];
21+
span.CopyTo(destination);
22+
23+
// Now also empty
24+
destination = SpanByte.Empty;
25+
span.CopyTo(destination);
26+
}
27+
28+
[TestMethod]
29+
public void RaisingExceptionsOfAllKindsTests()
30+
{
31+
// Should raise an exception on creation
32+
Assert.Throws(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(null, 1, 2); }, "ArgumentOutOfRangeException when array is null, start is 1 and length is 2");
33+
Assert.Throws(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 1, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 1 and length is 2");
34+
Assert.Throws(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 0, 2); }, "ArgumentOutOfRangeException when array is new byte[1], start is 0 and length is 2");
35+
Assert.Throws(typeof(ArgumentOutOfRangeException), () => { SpanByte span = new SpanByte(new byte[1], 2, 0); }, "ArgumentOutOfRangeException when array is new byte[1], start is 2 and length is 0");
36+
37+
// Exception on index access
38+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
39+
Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
40+
{
41+
SpanByte span = new SpanByte(array);
42+
var data = span[span.Length];
43+
});
44+
Assert.Throws(typeof(IndexOutOfRangeException), () =>
45+
{
46+
SpanByte span = new SpanByte(array);
47+
var data = span[-1];
48+
});
49+
50+
// Copy to with too small destination
51+
Assert.Throws(typeof(ArgumentException), () =>
52+
{
53+
SpanByte span = new SpanByte(array);
54+
SpanByte destination = new byte[span.Length - 1];
55+
span.CopyTo(destination);
56+
});
57+
58+
// Slicing arguments
59+
Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
60+
{
61+
SpanByte span = new SpanByte(array);
62+
var sliced = span.Slice(span.Length + 1);
63+
});
64+
Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
65+
{
66+
SpanByte span = new SpanByte(array);
67+
var sliced = span.Slice(1, span.Length);
68+
});
69+
70+
Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
71+
{
72+
SpanByte span = new SpanByte(array);
73+
var sliced = span.Slice(-1, span.Length);
74+
});
75+
76+
Assert.Throws(typeof(ArgumentOutOfRangeException), () =>
77+
{
78+
SpanByte span = new SpanByte(array);
79+
var sliced = span.Slice(1, -1);
80+
});
81+
82+
}
83+
84+
[TestMethod]
85+
public void ToArrayTest()
86+
{
87+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
88+
SpanByte span = new SpanByte(array);
89+
byte[] toArray = span.ToArray();
90+
Assert.Equal(array, toArray, "Original array and SpanByte.ToArray should be the same");
91+
}
92+
93+
[TestMethod]
94+
public void ConstructorsOfAllKindsTests()
95+
{
96+
// Empty span
97+
SpanByte span = new SpanByte();
98+
Assert.Equal(span.Length, 0, "Empty SpanByte should have length of 0");
99+
Assert.True(span.IsEmpty, "Empty SpanByte should be IsEmpty");
100+
101+
// Empty span
102+
span = new SpanByte(null, 0, 0);
103+
Assert.Equal(span.Length, 0, "Empty SpanByte should have length of 0");
104+
Assert.True(span.IsEmpty, "Empty SpanByte should be IsEmpty");
105+
106+
// Empty span
107+
span = SpanByte.Empty;
108+
Assert.Equal(span.Length, 0, "Empty SpanByte should have length of 0");
109+
Assert.True(span.IsEmpty, "Empty SpanByte should be IsEmpty");
110+
111+
// Span from normal array
112+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
113+
span = new SpanByte(array);
114+
Assert.Equal(span.Length, array.Length, $"SpanByte should have length of the array it takes: {array.Length}");
115+
Assert.False(span.IsEmpty, "SpanByte should NOT be IsEmpty");
116+
117+
// Span from normal array with different start and length
118+
span = new SpanByte(array, 2, 8);
119+
Assert.Equal(span.Length, 8, $"SpanByte should have length of 8");
120+
Assert.False(span.IsEmpty, "SpanByte should NOT be IsEmpty");
121+
}
122+
123+
[TestMethod]
124+
public void SliceTests()
125+
{
126+
// Span from normal array
127+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
128+
SpanByte span = new SpanByte(array);
129+
// Slice 2 elements and check
130+
var sliced = span.Slice(0, 2);
131+
Assert.Equal(sliced.Length, 2, "Sliced span lenght must be 2");
132+
Assert.Equal(sliced[0], (byte)0x00, "Sliced first element must be value 0");
133+
Assert.Equal(sliced[1], (byte)0x01, "Sliced first element must be value 1");
134+
135+
// Slide 4 elements starting at index 2 and check
136+
sliced = span.Slice(2, 4);
137+
Assert.Equal(sliced.Length, 4, "Sliced span lenght must be 4");
138+
Assert.Equal(sliced[0], (byte)0x02, "Sliced first element must be value 2");
139+
Assert.Equal(sliced[1], (byte)0x03, "Sliced first element must be value 3");
140+
Assert.Equal(sliced[2], (byte)0x04, "Sliced first element must be value 4");
141+
Assert.Equal(sliced[3], (byte)0x05, "Sliced first element must be value 5");
142+
143+
// Slide starting 4 at element check
144+
sliced = span.Slice(4);
145+
Assert.Equal(sliced.Length, 12, "Sliced span lenght must be 12");
146+
for (int i = 0; i < sliced.Length; i++)
147+
{
148+
Assert.Equal(sliced[i], span[i + 4], "SpanByte value should be the same as from the original span");
149+
}
150+
151+
// Slice of slice
152+
var secondSliced = sliced.Slice(2, 4);
153+
Assert.Equal(secondSliced.Length, 4, "Sliced span lenght must be 12");
154+
for (int i = 0; i < secondSliced.Length; i++)
155+
{
156+
Assert.Equal(secondSliced[i], sliced[i + 2], "SpanByte value should be the same as from the original span");
157+
}
158+
159+
// Should be an empty one
160+
var empty = span.Slice(span.Length);
161+
Assert.Equal(empty.Length, 0, "slicing all the span should result in an empty span");
162+
Assert.True(empty.IsEmpty, "Empty span should be empty");
163+
}
164+
165+
[TestMethod]
166+
public void CopyToTests()
167+
{
168+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
169+
SpanByte span = new SpanByte(array);
170+
// First a copy to with the full span
171+
SpanByte toCopy = new byte[span.Length];
172+
span.CopyTo(toCopy);
173+
for (int i = 0; i < span.Length; i++)
174+
{
175+
Assert.Equal(toCopy[i], span[i], "SpanByte value should be the same as from the original array");
176+
}
177+
178+
// Now create a larger span
179+
toCopy = new byte[span.Length + 1];
180+
span.CopyTo(toCopy);
181+
for (int i = 0; i < span.Length; i++)
182+
{
183+
Assert.Equal(toCopy[i], span[i], "SpanByte value should be the same as from the original array");
184+
}
185+
186+
Assert.Equal(toCopy[span.Length], (byte)0);
187+
}
188+
189+
[TestMethod]
190+
public void GetElementsTests()
191+
{
192+
// Span from normal array
193+
byte[] array = new byte[16] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
194+
SpanByte span = new SpanByte(array);
195+
for (int i = 0; i < span.Length; i++)
196+
{
197+
Assert.Equal(span[i], array[i], "SpanByte value should be the same as from the original array");
198+
}
199+
200+
// Partial span
201+
span = new SpanByte(array, 2, 8);
202+
for (int i = 0; i < span.Length; i++)
203+
{
204+
Assert.Equal(span[i], array[i + 2], "SpanByte value should be the same as from the original array");
205+
}
206+
}
207+
208+
[TestMethod]
209+
public void SetElementsTests()
210+
{
211+
// Create a span, and set the data
212+
SpanByte span = new byte[12];
213+
// All should be 0
214+
for (int i = 0; i < span.Length; i++)
215+
{
216+
Assert.Equal(span[i], (byte)0, "SpanByte value should be 0");
217+
// Set a value
218+
span[i] = (byte)i;
219+
}
220+
221+
for (int i = 0; i < span.Length; i++)
222+
{
223+
// Check the value
224+
Assert.Equal(span[i], (byte)i, "SpanByte value should be the same as setup in the set method");
225+
}
226+
}
227+
}
228+
}

Diff for: nanoFramework.CoreLibrary/System/SpanByte.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public SpanByte(byte[] array, int start, int length)
5454
if (start < 0 ||
5555
length < 0 ||
5656
start + length > array.Length ||
57-
start >= array.Length)
57+
start > array.Length)
5858
{
5959
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
6060
throw new ArgumentOutOfRangeException();
@@ -75,9 +75,9 @@ public SpanByte(byte[] array, int start, int length)
7575
}
7676
else
7777
{
78-
#pragma warning disable S3928
79-
throw new NullReferenceException();
80-
#pragma warning restore S3928
78+
_start = 0;
79+
_length = 0;
80+
_array = null;
8181
}
8282
}
8383

@@ -102,6 +102,7 @@ public byte this[int index]
102102

103103
return _array[_start + index];
104104
}
105+
105106
set
106107
{
107108
if (index >= _length)

0 commit comments

Comments
 (0)