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