Skip to content

Commit b40adf2

Browse files
authored
Ensure SyncRoot is not null (#132)
1 parent a3fa3d8 commit b40adf2

File tree

4 files changed

+123
-14
lines changed

4 files changed

+123
-14
lines changed

src/Microsoft.AspNetCore.SystemWebAdapters/Internal/NonGenericCollectionWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace Microsoft.AspNetCore.SystemWebAdapters.Internal
99
{
1010
internal class NonGenericCollectionWrapper<T> : ICollection
1111
{
12+
private object? _syncRoot;
1213
private readonly ICollection<T> _collection;
1314

1415
public NonGenericCollectionWrapper(ICollection<T> collection)
@@ -18,9 +19,9 @@ public NonGenericCollectionWrapper(ICollection<T> collection)
1819

1920
public int Count => _collection.Count;
2021

21-
public bool IsSynchronized => false;
22+
public bool IsSynchronized => (_collection as ICollection)?.IsSynchronized ?? false;
2223

23-
public object SyncRoot => null!;
24+
public object SyncRoot => _syncRoot ??= (_collection as ICollection)?.SyncRoot ?? new object();
2425

2526
public void CopyTo(Array array, int index)
2627
{

src/Microsoft.AspNetCore.SystemWebAdapters/Internal/NonGenericDictionaryWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ internal class NonGenericDictionaryWrapper : IDictionary
1111
{
1212
private readonly IDictionary<object, object?> _original;
1313

14+
private object? _syncRoot;
1415
private ICollection? _keys;
1516
private ICollection? _values;
1617

@@ -57,9 +58,9 @@ public ICollection Values
5758

5859
public int Count => _original.Count;
5960

60-
public bool IsSynchronized => false;
61+
public bool IsSynchronized => (_original as ICollection)?.IsSynchronized ?? false;
6162

62-
public object SyncRoot => null!;
63+
public object SyncRoot => _syncRoot ??= (_original as ICollection)?.SyncRoot ?? new object();
6364

6465
public void Add(object key, object? value) => _original.Add(key, value);
6566

test/Microsoft.AspNetCore.SystemWebAdapters.Tests/Internal/NonGenericCollectionWrapperTests.cs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
24
using System.Diagnostics.CodeAnalysis;
35
using System.Linq;
46
using AutoFixture;
7+
using Moq;
58
using Xunit;
69

710
namespace Microsoft.AspNetCore.SystemWebAdapters.Internal
@@ -34,13 +37,74 @@ public void Empty()
3437
Assert.Empty(wrapped);
3538
}
3639

40+
[Theory]
41+
[InlineData(null)]
42+
[InlineData(true)]
43+
[InlineData(false)]
44+
public void IsSynchronized(bool? isSynchronized)
45+
{
46+
// Arrange
47+
var original = new Mock<ICollection<object>>();
48+
49+
if (isSynchronized.HasValue)
50+
{
51+
var collection = original.As<ICollection>();
52+
collection.Setup(c => c.IsSynchronized).Returns(isSynchronized.Value);
53+
}
54+
55+
var wrapped = new NonGenericCollectionWrapper<object>(original.Object);
56+
57+
// Act
58+
var result = wrapped.IsSynchronized;
59+
60+
// Assert
61+
Assert.Equal(isSynchronized ?? false, result);
62+
}
63+
64+
[Fact]
65+
public void NoSyncRoot()
66+
{
67+
// Arrange
68+
var original = new Mock<ICollection<object>>();
69+
var wrapped = new NonGenericCollectionWrapper<object>(original.Object);
70+
71+
// Act
72+
var result1 = wrapped.SyncRoot;
73+
var result2 = wrapped.SyncRoot;
74+
75+
// Assert
76+
Assert.Same(result1, result2);
77+
}
78+
79+
[Fact]
80+
public void HasSyncRoot()
81+
{
82+
// Arrange
83+
var original = new Mock<ICollection<object>>();
84+
var syncRoot = new object();
85+
86+
var collection = original.As<ICollection>();
87+
collection.Setup(c => c.SyncRoot).Returns(syncRoot);
88+
89+
var wrapped = new NonGenericCollectionWrapper<object>(original.Object);
90+
91+
// Act
92+
var result1 = wrapped.SyncRoot;
93+
var result2 = wrapped.SyncRoot;
94+
95+
// Assert
96+
Assert.Same(syncRoot, result1);
97+
Assert.Same(syncRoot, result2);
98+
}
99+
37100
[Fact]
38101
public void SyncProperties()
39102
{
40-
var wrapped = new NonGenericCollectionWrapper<object>(Array.Empty<object>());
103+
var list = new List<object>();
104+
var wrapped = new NonGenericCollectionWrapper<object>(list);
41105

42106
Assert.False(wrapped.IsSynchronized);
43-
Assert.Null(wrapped.SyncRoot);
107+
Assert.Equal(((ICollection)list).SyncRoot, wrapped.SyncRoot);
44108
}
45109

46110
[Fact]

test/Microsoft.AspNetCore.SystemWebAdapters.Tests/Internal/NonGenericDictionaryWrapperTests.cs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public NonGenericDictionaryWrapperTests()
1818
_fixture = new Fixture();
1919
}
2020

21+
2122
[Fact]
2223
public void IsFixedSize()
2324
{
@@ -27,22 +28,64 @@ public void IsFixedSize()
2728
Assert.False(wrapped.IsFixedSize);
2829
}
2930

31+
[Theory]
32+
[InlineData(null)]
33+
[InlineData(true)]
34+
[InlineData(false)]
35+
public void IsSynchronized(bool? isSynchronized)
36+
{
37+
// Arrange
38+
var dictionary = new Mock<IDictionary<object, object?>>();
39+
40+
if (isSynchronized.HasValue)
41+
{
42+
var collection = dictionary.As<ICollection>();
43+
collection.Setup(c => c.IsSynchronized).Returns(isSynchronized.Value);
44+
}
45+
46+
var wrapped = new NonGenericDictionaryWrapper(dictionary.Object);
47+
48+
// Act
49+
var result = wrapped.IsSynchronized;
50+
51+
// Assert
52+
Assert.Equal(isSynchronized ?? false, result);
53+
}
54+
3055
[Fact]
31-
public void IsSynchronized()
56+
public void NoSyncRoot()
3257
{
33-
var dictionary = new Dictionary<object, object?>();
34-
var wrapped = new NonGenericDictionaryWrapper(dictionary);
58+
// Arrange
59+
var dictionary = new Mock<IDictionary<object, object?>>();
60+
var wrapped = new NonGenericDictionaryWrapper(dictionary.Object);
61+
62+
// Act
63+
var result1 = wrapped.SyncRoot;
64+
var result2 = wrapped.SyncRoot;
3565

36-
Assert.False(wrapped.IsSynchronized);
66+
// Assert
67+
Assert.Same(result1, result2);
3768
}
3869

3970
[Fact]
40-
public void SyncRoot()
71+
public void HasSyncRoot()
4172
{
42-
var dictionary = new Dictionary<object, object?>();
43-
var wrapped = new NonGenericDictionaryWrapper(dictionary);
73+
// Arrange
74+
var dictionary = new Mock<IDictionary<object, object?>>();
75+
var syncRoot = new object();
76+
77+
var collection = dictionary.As<ICollection>();
78+
collection.Setup(c => c.SyncRoot).Returns(syncRoot);
79+
80+
var wrapped = new NonGenericDictionaryWrapper(dictionary.Object);
81+
82+
// Act
83+
var result1 = wrapped.SyncRoot;
84+
var result2 = wrapped.SyncRoot;
4485

45-
Assert.Null(wrapped.SyncRoot);
86+
// Assert
87+
Assert.Same(syncRoot, result1);
88+
Assert.Same(syncRoot, result2);
4689
}
4790

4891
[Theory]

0 commit comments

Comments
 (0)