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.Text;
6 using Xunit;
7 
8 namespace System.SpanTests
9 {
10     public static partial class ReadOnlySpanTests
11     {
12         [Theory]
13         [InlineData("a", "a", 'a', 0)]
14         [InlineData("ab", "a", 'a', 0)]
15         [InlineData("aab", "a", 'a', 1)]
16         [InlineData("acab", "a", 'a', 2)]
17         [InlineData("acab", "c", 'c', 1)]
18         [InlineData("abcdefghijklmnopqrstuvwxyz", "lo", 'o', 14)]
19         [InlineData("abcdefghijklmnopqrstuvwxyz", "ol", 'o', 14)]
20         [InlineData("abcdefghijklmnopqrstuvwxyz", "ll", 'l', 11)]
21         [InlineData("abcdefghijklmnopqrstuvwxyz", "lmr", 'r', 17)]
22         [InlineData("abcdefghijklmnopqrstuvwxyz", "rml", 'r', 17)]
23         [InlineData("abcdefghijklmnopqrstuvwxyz", "mlr", 'r', 17)]
24         [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", "lmr", 'r', 43)]
25         [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrzzzzzzzz", "lmr", 'r', 43)]
26         [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqxzzzzzzzz", "lmr", 'm', 38)]
27         [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqlzzzzzzzz", "lmr", 'l', 43)]
28         [InlineData("/localhost:5000/PATH/%2FPATH2/ HTTP/1.1", " %?", ' ', 30)]
29         [InlineData("/localhost:5000/PATH/%2FPATH2/?key=value HTTP/1.1", " %?", ' ', 40)]
30         [InlineData("/localhost:5000/PATH/PATH2/?key=value HTTP/1.1", " %?", ' ', 37)]
31         [InlineData("/localhost:5000/PATH/PATH2/ HTTP/1.1", " %?", ' ', 27)]
LastIndexOfAnyStrings_Byte(string raw, string search, char expectResult, int expectIndex)32         public static void LastIndexOfAnyStrings_Byte(string raw, string search, char expectResult, int expectIndex)
33         {
34             byte[] buffers = Encoding.UTF8.GetBytes(raw);
35             var span = new ReadOnlySpan<byte>(buffers);
36             char[] searchFor = search.ToCharArray();
37             byte[] searchForBytes = Encoding.UTF8.GetBytes(searchFor);
38 
39             var index = -1;
40             if (searchFor.Length == 1)
41             {
42                 index = span.LastIndexOf((byte)searchFor[0]);
43             }
44             else if (searchFor.Length == 2)
45             {
46                 index = span.LastIndexOfAny((byte)searchFor[0], (byte)searchFor[1]);
47             }
48             else if (searchFor.Length == 3)
49             {
50                 index = span.LastIndexOfAny((byte)searchFor[0], (byte)searchFor[1], (byte)searchFor[2]);
51             }
52             else
53             {
54                 index = span.LastIndexOfAny(new ReadOnlySpan<byte>(searchForBytes));
55             }
56 
57             var found = span[index];
58             Assert.Equal((byte)expectResult, found);
59             Assert.Equal(expectIndex, index);
60         }
61 
62         [Fact]
ZeroLengthLastIndexOfAny_Byte_TwoByte()63         public static void ZeroLengthLastIndexOfAny_Byte_TwoByte()
64         {
65             ReadOnlySpan<byte> sp = new ReadOnlySpan<byte>(Array.Empty<byte>());
66             int idx = sp.LastIndexOfAny<byte>(0, 0);
67             Assert.Equal(-1, idx);
68         }
69 
70         [Fact]
DefaultFilledLastIndexOfAny_Byte_TwoByte()71         public static void DefaultFilledLastIndexOfAny_Byte_TwoByte()
72         {
73             Random rnd = new Random(42);
74 
75             for (int length = 0; length < byte.MaxValue; length++)
76             {
77                 byte[] a = new byte[length];
78                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
79 
80                 byte[] targets = { default, 99 };
81 
82                 for (int i = 0; i < length; i++)
83                 {
84                     int index = rnd.Next(0, 2) == 0 ? 0 : 1;
85                     byte target0 = targets[index];
86                     byte target1 = targets[(index + 1) % 2];
87                     int idx = span.LastIndexOfAny(target0, target1);
88                     Assert.Equal(span.Length - 1, idx);
89                 }
90             }
91         }
92 
93         [Fact]
TestMatchLastIndexOfAny_Byte_TwoByte()94         public static void TestMatchLastIndexOfAny_Byte_TwoByte()
95         {
96             for (int length = 0; length < byte.MaxValue; length++)
97             {
98                 byte[] a = new byte[length];
99                 for (int i = 0; i < length; i++)
100                 {
101                     a[i] = (byte)(i + 1);
102                 }
103                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
104 
105                 for (int targetIndex = 0; targetIndex < length; targetIndex++)
106                 {
107                     byte target0 = a[targetIndex];
108                     byte target1 = 0;
109                     int idx = span.LastIndexOfAny(target0, target1);
110                     Assert.Equal(targetIndex, idx);
111                 }
112 
113                 for (int targetIndex = 0; targetIndex < length - 1; targetIndex++)
114                 {
115                     byte target0 = a[targetIndex];
116                     byte target1 = a[targetIndex + 1];
117                     int idx = span.LastIndexOfAny(target0, target1);
118                     Assert.Equal(targetIndex + 1, idx);
119                 }
120 
121                 for (int targetIndex = 0; targetIndex < length - 1; targetIndex++)
122                 {
123                     byte target0 = 0;
124                     byte target1 = a[targetIndex + 1];
125                     int idx = span.LastIndexOfAny(target0, target1);
126                     Assert.Equal(targetIndex + 1, idx);
127                 }
128             }
129         }
130 
131         [Fact]
TestNoMatchLastIndexOfAny_Byte_TwoByte()132         public static void TestNoMatchLastIndexOfAny_Byte_TwoByte()
133         {
134             var rnd = new Random(42);
135             for (int length = 0; length < byte.MaxValue; length++)
136             {
137                 byte[] a = new byte[length];
138                 byte target0 = (byte)rnd.Next(1, 256);
139                 byte target1 = (byte)rnd.Next(1, 256);
140                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
141 
142                 int idx = span.LastIndexOfAny(target0, target1);
143                 Assert.Equal(-1, idx);
144             }
145         }
146 
147         [Fact]
TestMultipleMatchLastIndexOfAny_Byte_TwoByte()148         public static void TestMultipleMatchLastIndexOfAny_Byte_TwoByte()
149         {
150             for (int length = 3; length < byte.MaxValue; length++)
151             {
152                 byte[] a = new byte[length];
153                 for (int i = 0; i < length; i++)
154                 {
155                     byte val = (byte)(i + 1);
156                     a[i] = val == 200 ? (byte)201 : val;
157                 }
158 
159                 a[length - 1] = 200;
160                 a[length - 2] = 200;
161                 a[length - 3] = 200;
162 
163                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
164                 int idx = span.LastIndexOfAny<byte>(200, 200);
165                 Assert.Equal(length - 1, idx);
166             }
167         }
168 
169         [Fact]
MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_TwoByte()170         public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_TwoByte()
171         {
172             for (int length = 1; length < byte.MaxValue; length++)
173             {
174                 byte[] a = new byte[length + 2];
175                 a[0] = 99;
176                 a[length + 1] = 98;
177                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
178                 int index = span.LastIndexOfAny<byte>(99, 98);
179                 Assert.Equal(-1, index);
180             }
181 
182             for (int length = 1; length < byte.MaxValue; length++)
183             {
184                 byte[] a = new byte[length + 2];
185                 a[0] = 99;
186                 a[length + 1] = 99;
187                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
188                 int index = span.LastIndexOfAny<byte>(99, 99);
189                 Assert.Equal(-1, index);
190             }
191         }
192 
193         [Fact]
ZeroLengthIndexOf_Byte_ThreeByte()194         public static void ZeroLengthIndexOf_Byte_ThreeByte()
195         {
196             ReadOnlySpan<byte> sp = new ReadOnlySpan<byte>(Array.Empty<byte>());
197             int idx = sp.LastIndexOfAny<byte>(0, 0, 0);
198             Assert.Equal(-1, idx);
199         }
200 
201         [Fact]
DefaultFilledLastIndexOfAny_Byte_ThreeByte()202         public static void DefaultFilledLastIndexOfAny_Byte_ThreeByte()
203         {
204             Random rnd = new Random(42);
205 
206             for (int length = 0; length < byte.MaxValue; length++)
207             {
208                 byte[] a = new byte[length];
209                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
210 
211                 byte[] targets = { default, 99, 98 };
212 
213                 for (int i = 0; i < length; i++)
214                 {
215                     int index = rnd.Next(0, 3);
216                     byte target0 = targets[index];
217                     byte target1 = targets[(index + 1) % 2];
218                     byte target2 = targets[(index + 1) % 3];
219                     int idx = span.LastIndexOfAny(target0, target1, target2);
220                     Assert.Equal(span.Length - 1, idx);
221                 }
222             }
223         }
224 
225         [Fact]
TestMatchLastIndexOfAny_Byte_ThreeByte()226         public static void TestMatchLastIndexOfAny_Byte_ThreeByte()
227         {
228             for (int length = 0; length < byte.MaxValue; length++)
229             {
230                 byte[] a = new byte[length];
231                 for (int i = 0; i < length; i++)
232                 {
233                     a[i] = (byte)(i + 1);
234                 }
235                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
236 
237                 for (int targetIndex = 0; targetIndex < length; targetIndex++)
238                 {
239                     byte target0 = a[targetIndex];
240                     byte target1 = 0;
241                     byte target2 = 0;
242                     int idx = span.LastIndexOfAny(target0, target1, target2);
243                     Assert.Equal(targetIndex, idx);
244                 }
245 
246                 for (int targetIndex = 0; targetIndex < length - 2; targetIndex++)
247                 {
248                     byte target0 = a[targetIndex];
249                     byte target1 = a[targetIndex + 1];
250                     byte target2 = a[targetIndex + 2];
251                     int idx = span.LastIndexOfAny(target0, target1, target2);
252                     Assert.Equal(targetIndex + 2, idx);
253                 }
254 
255                 for (int targetIndex = 0; targetIndex < length - 2; targetIndex++)
256                 {
257                     byte target0 = 0;
258                     byte target1 = 0;
259                     byte target2 = a[targetIndex + 2];
260                     int idx = span.LastIndexOfAny(target0, target1, target2);
261                     Assert.Equal(targetIndex + 2, idx);
262                 }
263             }
264         }
265 
266         [Fact]
TestNoMatchLastIndexOfAny_Byte_ThreeByte()267         public static void TestNoMatchLastIndexOfAny_Byte_ThreeByte()
268         {
269             var rnd = new Random(42);
270             for (int length = 0; length < byte.MaxValue; length++)
271             {
272                 byte[] a = new byte[length];
273                 byte target0 = (byte)rnd.Next(1, 256);
274                 byte target1 = (byte)rnd.Next(1, 256);
275                 byte target2 = (byte)rnd.Next(1, 256);
276                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
277 
278                 int idx = span.LastIndexOfAny(target0, target1, target2);
279                 Assert.Equal(-1, idx);
280             }
281         }
282 
283         [Fact]
TestMultipleMatchLastIndexOfAny_Byte_ThreeByte()284         public static void TestMultipleMatchLastIndexOfAny_Byte_ThreeByte()
285         {
286             for (int length = 4; length < byte.MaxValue; length++)
287             {
288                 byte[] a = new byte[length];
289                 for (int i = 0; i < length; i++)
290                 {
291                     byte val = (byte)(i + 1);
292                     a[i] = val == 200 ? (byte)201 : val;
293                 }
294 
295                 a[length - 1] = 200;
296                 a[length - 2] = 200;
297                 a[length - 3] = 200;
298                 a[length - 4] = 200;
299 
300                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
301                 int idx = span.LastIndexOfAny<byte>(200, 200, 200);
302                 Assert.Equal(length - 1, idx);
303             }
304         }
305 
306         [Fact]
MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_ThreeByte()307         public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_ThreeByte()
308         {
309             for (int length = 1; length < byte.MaxValue; length++)
310             {
311                 byte[] a = new byte[length + 2];
312                 a[0] = 99;
313                 a[length + 1] = 98;
314                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
315                 int index = span.LastIndexOfAny<byte>(99, 98, 99);
316                 Assert.Equal(-1, index);
317             }
318 
319             for (int length = 1; length < byte.MaxValue; length++)
320             {
321                 byte[] a = new byte[length + 2];
322                 a[0] = 99;
323                 a[length + 1] = 99;
324                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
325                 int index = span.LastIndexOfAny<byte>(99, 99, 99);
326                 Assert.Equal(-1, index);
327             }
328         }
329 
330         [Fact]
ZeroLengthLastIndexOfAny_Byte_ManyByte()331         public static void ZeroLengthLastIndexOfAny_Byte_ManyByte()
332         {
333             ReadOnlySpan<byte> sp = new ReadOnlySpan<byte>(Array.Empty<byte>());
334             var values = new ReadOnlySpan<byte>(new byte[] { 0, 0, 0, 0 });
335             int idx = sp.LastIndexOfAny(values);
336             Assert.Equal(-1, idx);
337 
338             values = new ReadOnlySpan<byte>(new byte[] { });
339             idx = sp.LastIndexOfAny(values);
340             Assert.Equal(0, idx);
341         }
342 
343         [Fact]
DefaultFilledLastIndexOfAny_Byte_ManyByte()344         public static void DefaultFilledLastIndexOfAny_Byte_ManyByte()
345         {
346             for (int length = 0; length < byte.MaxValue; length++)
347             {
348                 byte[] a = new byte[length];
349                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
350 
351                 var values = new ReadOnlySpan<byte>(new byte[] { default, 99, 98, 0 });
352 
353                 for (int i = 0; i < length; i++)
354                 {
355                     int idx = span.LastIndexOfAny(values);
356                     Assert.Equal(span.Length - 1, idx);
357                 }
358             }
359         }
360 
361         [Fact]
TestMatchLastIndexOfAny_Byte_ManyByte()362         public static void TestMatchLastIndexOfAny_Byte_ManyByte()
363         {
364             for (int length = 0; length < byte.MaxValue; length++)
365             {
366                 byte[] a = new byte[length];
367                 for (int i = 0; i < length; i++)
368                 {
369                     a[i] = (byte)(i + 1);
370                 }
371                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
372 
373                 for (int targetIndex = 0; targetIndex < length; targetIndex++)
374                 {
375                     var values = new ReadOnlySpan<byte>(new byte[] { a[targetIndex], 0, 0, 0 });
376                     int idx = span.LastIndexOfAny(values);
377                     Assert.Equal(targetIndex, idx);
378                 }
379 
380                 for (int targetIndex = 0; targetIndex < length - 3; targetIndex++)
381                 {
382                     var values = new ReadOnlySpan<byte>(new byte[] { a[targetIndex], a[targetIndex + 1], a[targetIndex + 2], a[targetIndex + 3] });
383                     int idx = span.LastIndexOfAny(values);
384                     Assert.Equal(targetIndex + 3, idx);
385                 }
386 
387                 for (int targetIndex = 0; targetIndex < length - 3; targetIndex++)
388                 {
389                     var values = new ReadOnlySpan<byte>(new byte[] { 0, 0, 0, a[targetIndex + 3] });
390                     int idx = span.LastIndexOfAny(values);
391                     Assert.Equal(targetIndex + 3, idx);
392                 }
393             }
394         }
395 
396         [Fact]
TestMatchValuesLargerLastIndexOfAny_Byte_ManyByte()397         public static void TestMatchValuesLargerLastIndexOfAny_Byte_ManyByte()
398         {
399             var rnd = new Random(42);
400             for (int length = 2; length < byte.MaxValue; length++)
401             {
402                 byte[] a = new byte[length];
403                 int expectedIndex = length / 2;
404                 for (int i = 0; i < length; i++)
405                 {
406                     if (i == expectedIndex)
407                     {
408                         continue;
409                     }
410                     a[i] = 255;
411                 }
412                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
413 
414                 byte[] targets = new byte[length * 2];
415                 for (int i = 0; i < targets.Length; i++)
416                 {
417                     if (i == length + 1)
418                     {
419                         continue;
420                     }
421                     targets[i] = (byte)rnd.Next(1, 255);
422                 }
423 
424                 var values = new ReadOnlySpan<byte>(targets);
425                 int idx = span.LastIndexOfAny(values);
426                 Assert.Equal(expectedIndex, idx);
427             }
428         }
429 
430         [Fact]
TestNoMatchLastIndexOfAny_Byte_ManyByte()431         public static void TestNoMatchLastIndexOfAny_Byte_ManyByte()
432         {
433             var rnd = new Random(42);
434             for (int length = 1; length < byte.MaxValue; length++)
435             {
436                 byte[] a = new byte[length];
437                 byte[] targets = new byte[length];
438                 for (int i = 0; i < targets.Length; i++)
439                 {
440                     targets[i] = (byte)rnd.Next(1, 256);
441                 }
442                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
443                 var values = new ReadOnlySpan<byte>(targets);
444 
445                 int idx = span.LastIndexOfAny(values);
446                 Assert.Equal(-1, idx);
447             }
448         }
449 
450         [Fact]
TestNoMatchValuesLargerLastIndexOfAny_Byte_ManyByte()451         public static void TestNoMatchValuesLargerLastIndexOfAny_Byte_ManyByte()
452         {
453             var rnd = new Random(42);
454             for (int length = 1; length < byte.MaxValue; length++)
455             {
456                 byte[] a = new byte[length];
457                 byte[] targets = new byte[length * 2];
458                 for (int i = 0; i < targets.Length; i++)
459                 {
460                     targets[i] = (byte)rnd.Next(1, 256);
461                 }
462                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
463                 var values = new ReadOnlySpan<byte>(targets);
464 
465                 int idx = span.LastIndexOfAny(values);
466                 Assert.Equal(-1, idx);
467             }
468         }
469 
470         [Fact]
TestMultipleMatchLastIndexOfAny_Byte_ManyByte()471         public static void TestMultipleMatchLastIndexOfAny_Byte_ManyByte()
472         {
473             for (int length = 5; length < byte.MaxValue; length++)
474             {
475                 byte[] a = new byte[length];
476                 for (int i = 0; i < length; i++)
477                 {
478                     byte val = (byte)(i + 1);
479                     a[i] = val == 200 ? (byte)201 : val;
480                 }
481 
482                 a[length - 1] = 200;
483                 a[length - 2] = 200;
484                 a[length - 3] = 200;
485                 a[length - 4] = 200;
486                 a[length - 5] = 200;
487 
488                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a);
489                 var values = new ReadOnlySpan<byte>(new byte[] { 200, 200, 200, 200, 200, 200, 200, 200, 200 });
490                 int idx = span.LastIndexOfAny(values);
491                 Assert.Equal(length - 1, idx);
492             }
493         }
494 
495         [Fact]
MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_ManyByte()496         public static void MakeSureNoChecksGoOutOfRangeLastIndexOfAny_Byte_ManyByte()
497         {
498             for (int length = 1; length < byte.MaxValue; length++)
499             {
500                 byte[] a = new byte[length + 2];
501                 a[0] = 99;
502                 a[length + 1] = 98;
503                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
504                 var values = new ReadOnlySpan<byte>(new byte[] { 99, 98, 99, 98, 99, 98 });
505                 int index = span.LastIndexOfAny(values);
506                 Assert.Equal(-1, index);
507             }
508 
509             for (int length = 1; length < byte.MaxValue; length++)
510             {
511                 byte[] a = new byte[length + 2];
512                 a[0] = 99;
513                 a[length + 1] = 99;
514                 ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(a, 1, length - 1);
515                 var values = new ReadOnlySpan<byte>(new byte[] { 99, 99, 99, 99, 99, 99 });
516                 int index = span.LastIndexOfAny(values);
517                 Assert.Equal(-1, index);
518             }
519         }
520     }
521 }
522