Skip to content

Commit efff36d

Browse files
committed
.
1 parent 60e7b84 commit efff36d

17 files changed

Lines changed: 307 additions & 299 deletions

src/Tests/ArgumentExceptions/ArgumentOutOfRangeExceptionTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@ public class ArgumentOutOfRangeExceptionTests
44
{
55
#region ThrowIfZero Tests
66

7+
[Test]
8+
public async Task ThrowIfZero_SetsActualValueAndParamName()
9+
{
10+
ArgumentOutOfRangeException? captured = null;
11+
try
12+
{
13+
ArgumentOutOfRangeException.ThrowIfZero(0, "count");
14+
}
15+
catch (ArgumentOutOfRangeException exception)
16+
{
17+
captured = exception;
18+
}
19+
20+
await Assert.That(captured).IsNotNull();
21+
await Assert.That(captured!.ActualValue).IsEqualTo((object) 0);
22+
await Assert.That(captured.ParamName).IsEqualTo("count");
23+
}
24+
725
[Test]
826
public async Task ThrowIfZero_WithZeroInt_ThrowsArgumentOutOfRangeException()
927
{

src/Tests/ConvertPolyfillTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
1+
using System.Buffers;
2+
13
public class ConvertPolyfillTests
24
{
5+
[Test]
6+
public async Task FromHexString_ConsumedOnInvalidData()
7+
{
8+
var destination = new byte[8];
9+
10+
// A valid leading nibble is counted as consumed; consumed stops at i unless the low nibble is valid.
11+
await AssertConsumed("4G", 1); // hi valid, lo invalid
12+
await AssertConsumed("G4", 0); // hi invalid, lo valid
13+
await AssertConsumed("GG", 1); // both invalid
14+
await AssertConsumed("444G", 3); // failure mid-span
15+
16+
// The UTF-8 byte overload shares the same consumed semantics.
17+
var bytesStatus = Convert.FromHexString("4G"u8, destination, out var bytesConsumed, out _);
18+
await Assert.That(bytesStatus).IsEqualTo(OperationStatus.InvalidData);
19+
await Assert.That(bytesConsumed).IsEqualTo(1);
20+
21+
// DestinationTooSmall takes priority over InvalidData when the buffer is already full.
22+
var smallDestination = new byte[2];
23+
var fullStatus = Convert.FromHexString("a1F6CG".AsSpan(), smallDestination, out var fullConsumed, out var fullWritten);
24+
await Assert.That(fullStatus).IsEqualTo(OperationStatus.DestinationTooSmall);
25+
await Assert.That(fullConsumed).IsEqualTo(4);
26+
await Assert.That(fullWritten).IsEqualTo(2);
27+
28+
async Task AssertConsumed(string source, int expectedConsumed)
29+
{
30+
var status = Convert.FromHexString(source.AsSpan(), destination, out var consumed, out _);
31+
await Assert.That(status).IsEqualTo(OperationStatus.InvalidData);
32+
await Assert.That(consumed).IsEqualTo(expectedConsumed);
33+
}
34+
}
35+
336
[Test]
437
public async Task ToHexString_ValidInput()
538
{

src/Tests/EqualityComparerPolyfillTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33

44
public class EqualityComparerPolyfillTests
55
{
6+
[Test]
7+
public async Task Create_NullDelegates_Throw()
8+
{
9+
await Assert.That(() => EqualityComparer<int>.Create(null!)).Throws<ArgumentNullException>();
10+
11+
// The keySelector overload's delegate signature differs in nullability between the
12+
// polyfill (Func<T?, TKey?>) and the .NET 11 BCL (Func<T?, TKey>); adapt accordingly.
13+
#if NET11_0_OR_GREATER
14+
Func<string?, int> keySelector = null!;
15+
#else
16+
Func<string?, int?> keySelector = null!;
17+
#endif
18+
await Assert.That(() => EqualityComparer<string>.Create(keySelector)).Throws<ArgumentNullException>();
19+
}
20+
621
[Test]
722
public async Task Create_WithEqualsAndGetHashCode()
823
{

src/Tests/FilePolyfillTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,31 @@ public void TearDown()
2727
File.Delete(hardLinkFilePath);
2828
}
2929

30+
[Test]
31+
public async Task GetSetUnixFileMode_SetUser_RoundTrip()
32+
{
33+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
34+
{
35+
// GetUnixFileMode/SetUnixFileMode are not supported on Windows.
36+
return;
37+
}
38+
39+
var path = Path.GetTempFileName();
40+
try
41+
{
42+
File.SetUnixFileMode(path, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.SetUser);
43+
var mode = File.GetUnixFileMode(path);
44+
45+
// setuid is octal 4 (SetUser); it must not be read/written as setgid (octal 2).
46+
await Assert.That(mode.HasFlag(UnixFileMode.SetUser)).IsTrue();
47+
await Assert.That(mode.HasFlag(UnixFileMode.SetGroup)).IsFalse();
48+
}
49+
finally
50+
{
51+
File.Delete(path);
52+
}
53+
}
54+
3055
#if FeatureMemory
3156
[Test]
3257
public async Task AppendAllBytes()

src/Tests/Numbers/DoublePolyfillTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
public class DoublePolyfillTest
22
{
3+
[Test]
4+
public async Task TryParse_AllowsThousands()
5+
{
6+
var invariant = CultureInfo.InvariantCulture;
7+
8+
await Assert.That(double.TryParse("1,234.5", invariant, out var value)).IsTrue();
9+
await Assert.That(value).IsEqualTo(1234.5);
10+
11+
await Assert.That(double.TryParse("1,234.5".AsSpan(), invariant, out var spanValue)).IsTrue();
12+
await Assert.That(spanValue).IsEqualTo(1234.5);
13+
}
14+
315
[Test]
416
public async Task TryParse()
517
{

src/Tests/Numbers/SinglePolyfillTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
public class SinglePolyfillTest
22
{
3+
[Test]
4+
public async Task TryParse_AllowsThousands()
5+
{
6+
var invariant = CultureInfo.InvariantCulture;
7+
8+
await Assert.That(float.TryParse("1,234.5", invariant, out var value)).IsTrue();
9+
await Assert.That(value).IsEqualTo(1234.5f);
10+
11+
await Assert.That(float.TryParse("1,234.5".AsSpan(), invariant, out var spanValue)).IsTrue();
12+
await Assert.That(spanValue).IsEqualTo(1234.5f);
13+
}
14+
315
[Test]
416
public async Task TryParse()
517
{

src/Tests/PolyfillTests_ArraySegment.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11

22
partial class PolyfillTests
33
{
4+
[Test]
5+
public async Task ArraySegment_CopyTo_DefaultDestination_Throws()
6+
{
7+
var source = new ArraySegment<int>(new[] {1, 2, 3});
8+
ArraySegment<int> destination = default;
9+
await Assert.That(() => source.CopyTo(destination)).Throws<InvalidOperationException>();
10+
}
11+
412
[Test]
513
public async Task CopyTo_ArraySegment_CopiesElements()
614
{

src/Tests/PolyfillTests_Compression.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33

44
partial class PolyfillTests
55
{
6+
[Test]
7+
public async Task ZipFile_ExtractToDirectory_Overwrite_PreservesExistingFiles()
8+
{
9+
var root = Path.Combine(Path.GetTempPath(), "polyfill_zip_" + Guid.NewGuid().ToString("N"));
10+
var zipPath = Path.Combine(root, "archive.zip");
11+
var destination = Path.Combine(root, "dest");
12+
Directory.CreateDirectory(root);
13+
Directory.CreateDirectory(destination);
14+
try
15+
{
16+
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
17+
using (var writer = new StreamWriter(archive.CreateEntry("a.txt").Open()))
18+
{
19+
writer.Write("from-archive");
20+
}
21+
22+
File.WriteAllText(Path.Combine(destination, "preexisting.txt"), "keep-me");
23+
File.WriteAllText(Path.Combine(destination, "a.txt"), "old");
24+
25+
await ZipFile.ExtractToDirectoryAsync(zipPath, destination, overwriteFiles: true);
26+
27+
// Pre-existing file not in the archive is preserved; archive file is overwritten.
28+
await Assert.That(File.Exists(Path.Combine(destination, "preexisting.txt"))).IsTrue();
29+
await Assert.That(File.ReadAllText(Path.Combine(destination, "preexisting.txt"))).IsEqualTo("keep-me");
30+
await Assert.That(File.ReadAllText(Path.Combine(destination, "a.txt"))).IsEqualTo("from-archive");
31+
}
32+
finally
33+
{
34+
Directory.Delete(root, true);
35+
}
36+
}
37+
638
[Test]
739
public async Task ZipArchiveEntry_Open_WithFileAccess()
840
{

src/Tests/PolyfillTests_ConcurrentDictionary.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
partial class PolyfillTests
22
{
3+
[Test]
4+
public async Task ConcurrentDictionary_GetOrAdd_NullFactory_Throws()
5+
{
6+
var dictionary = new ConcurrentDictionary<string, int>();
7+
dictionary.TryAdd("a", 1);
8+
Func<string, int, int> factory = null!;
9+
10+
// Eager validation: throws for both present and absent keys.
11+
await Assert.That(() => dictionary.GetOrAdd("a", factory, 5)).Throws<ArgumentNullException>();
12+
await Assert.That(() => dictionary.GetOrAdd("b", factory, 5)).Throws<ArgumentNullException>();
13+
}
14+
315
[Test]
416
public async Task ConcurrentDictionaryGetOrAddFunc()
517
{

src/Tests/PolyfillTests_List.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
partial class PolyfillTests
22
{
3+
[Test]
4+
public async Task List_CopyTo_TooShort_Throws_AndLeavesDestinationUntouched()
5+
{
6+
var list = new List<int> {10, 20, 30, 40, 50};
7+
8+
var destination = new int[3];
9+
await Assert.That(() => list.CopyTo(new Span<int>(destination))).Throws<ArgumentException>();
10+
await Assert.That(destination.All(_ => _ == 0)).IsTrue();
11+
12+
var ok = new int[5];
13+
list.CopyTo(new Span<int>(ok));
14+
await Assert.That(string.Join(",", ok)).IsEqualTo("10,20,30,40,50");
15+
}
16+
17+
[Test]
18+
public async Task List_InsertRange_InvalidIndex_Throws()
19+
{
20+
var list = new List<int> {1, 2, 3};
21+
await Assert.That(() => list.InsertRange(10, ReadOnlySpan<int>.Empty)).Throws<ArgumentOutOfRangeException>();
22+
}
23+
324
[Test]
425
public async Task IListAsReadOnly()
526
{

0 commit comments

Comments
 (0)