Skip to content

Commit 90ae39c

Browse files
committed
Add more constructors and add tests
1 parent b063c39 commit 90ae39c

File tree

2 files changed

+208
-1
lines changed

2 files changed

+208
-1
lines changed

src/Meziantou.Framework.Threading/Collections/Concurrent/SynchronizedList.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,27 @@ namespace Meziantou.Framework.Collections.Concurrent;
44

55
public sealed class SynchronizedList<T> : IList<T>, IReadOnlyList<T>
66
{
7-
private readonly List<T> _list = [];
7+
private readonly List<T> _list;
8+
9+
public SynchronizedList()
10+
{
11+
_list = [];
12+
}
13+
14+
public SynchronizedList(int capacity)
15+
{
16+
_list = new List<T>(capacity);
17+
}
18+
19+
public SynchronizedList(IEnumerable<T>? items = null)
20+
{
21+
_list = items != null ? [.. items] : [];
22+
}
23+
24+
public SynchronizedList(ReadOnlySpan<T> items)
25+
{
26+
_list = [.. items];
27+
}
828

929
public int Count
1030
{
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
using Meziantou.Framework.Collections.Concurrent;
2+
using Xunit;
3+
4+
namespace Meziantou.Framework.Tests.Collections.Concurrent;
5+
6+
public sealed class SynchronizedListTests
7+
{
8+
[Fact]
9+
public void CollectionInitializer()
10+
{
11+
SynchronizedList<int> list = [1, 2, 3];
12+
Assert.Equal(new[] { 1, 2, 3 }, list);
13+
}
14+
15+
[Fact]
16+
public void CollectionInitializer_Spread()
17+
{
18+
SynchronizedList<int> list1 = [1, 2, 3];
19+
SynchronizedList<int> list2 = [.. list1, 4];
20+
Assert.Equal(new[] { 1, 2, 3, 4 }, list2);
21+
}
22+
23+
[Fact]
24+
public void DefaultConstructor_ShouldBeEmpty()
25+
{
26+
var list = new SynchronizedList<int>();
27+
Assert.Empty(list);
28+
}
29+
30+
[Fact]
31+
public void ConstructorWithCapacity_ShouldBeEmpty()
32+
{
33+
var list = new SynchronizedList<int>(10);
34+
Assert.Empty(list);
35+
}
36+
37+
[Fact]
38+
public void ConstructorWithEnumerable_ShouldContainItems()
39+
{
40+
var items = new[] { 1, 2, 3 };
41+
var list = new SynchronizedList<int>(items);
42+
Assert.Equal(items, list);
43+
}
44+
45+
[Fact]
46+
public void ConstructorWithReadOnlySpan_ShouldContainItems()
47+
{
48+
var items = new[] { 4, 5, 6 };
49+
var list = new SynchronizedList<int>(items.AsSpan());
50+
Assert.Equal(items, list);
51+
}
52+
53+
[Fact]
54+
public void Add_ShouldAddItems()
55+
{
56+
var list = new SynchronizedList<int>();
57+
list.Add(1);
58+
list.Add(2);
59+
Assert.Equal(new[] { 1, 2 }, list);
60+
}
61+
62+
[Fact]
63+
public void Remove_ShouldRemoveItem()
64+
{
65+
var list = new SynchronizedList<int>([1, 2, 3]);
66+
var result = list.Remove(2);
67+
Assert.True(result);
68+
Assert.Equal(new[] { 1, 3 }, list);
69+
}
70+
71+
[Fact]
72+
public void RemoveAt_ShouldRemoveItemAtIndex()
73+
{
74+
var list = new SynchronizedList<int>([1, 2, 3]);
75+
list.RemoveAt(1);
76+
Assert.Equal(new[] { 1, 3 }, list);
77+
}
78+
79+
[Fact]
80+
public void Insert_ShouldInsertItem()
81+
{
82+
var list = new SynchronizedList<int>([1, 3]);
83+
list.Insert(1, 2);
84+
Assert.Equal(new[] { 1, 2, 3 }, list);
85+
}
86+
87+
[Fact]
88+
public void Clear_ShouldRemoveAllItems()
89+
{
90+
var list = new SynchronizedList<int>([1, 2, 3]);
91+
list.Clear();
92+
Assert.Empty(list);
93+
}
94+
95+
[Fact]
96+
[SuppressMessage("Assertions", "xUnit2017:Do not use Contains() to check if a value exists in a collection")]
97+
public void Contains_ShouldReturnTrueIfItemExists()
98+
{
99+
var list = new SynchronizedList<int>([1, 2, 3]);
100+
Assert.True(list.Contains(2));
101+
Assert.False(list.Contains(4));
102+
}
103+
104+
[Fact]
105+
public void IndexOf_ShouldReturnCorrectIndex()
106+
{
107+
var list = new SynchronizedList<int>([1, 2, 3]);
108+
Assert.Equal(1, list.IndexOf(2));
109+
Assert.Equal(-1, list.IndexOf(4));
110+
}
111+
112+
[Fact]
113+
public void CopyTo_ShouldCopyItems()
114+
{
115+
var list = new SynchronizedList<int>([1, 2, 3]);
116+
var array = new int[5];
117+
list.CopyTo(array, 1);
118+
Assert.Equal([0, 1, 2, 3, 0], array);
119+
}
120+
121+
[Fact]
122+
public void EnsureCapacity_ShouldIncreaseCapacity()
123+
{
124+
var list = new SynchronizedList<int>();
125+
var capacity = list.EnsureCapacity(100);
126+
Assert.True(capacity >= 100);
127+
}
128+
129+
[Fact]
130+
public void Indexer_GetSet_ShouldWork()
131+
{
132+
var list = new SynchronizedList<int>([1, 2, 3]);
133+
Assert.Equal(2, list[1]);
134+
list[1] = 42;
135+
Assert.Equal(42, list[1]);
136+
}
137+
138+
[Fact]
139+
public void Enumerator_ShouldReturnAllItems()
140+
{
141+
var items = new[] { 1, 2, 3 };
142+
var list = new SynchronizedList<int>(items);
143+
Assert.Equal(items, list.ToArray());
144+
}
145+
146+
[Fact]
147+
public void IsReadOnly_ShouldBeFalse()
148+
{
149+
var list = new SynchronizedList<int>();
150+
Assert.False(((ICollection<int>)list).IsReadOnly);
151+
}
152+
153+
[Fact]
154+
public void CopyToArray_ShouldCopyItems()
155+
{
156+
var list = new SynchronizedList<int>([1, 2, 3]);
157+
var array = new int[3];
158+
list.CopyTo(array, 0);
159+
Assert.Equal([1, 2, 3], array);
160+
}
161+
162+
[Fact]
163+
public async Task ThreadSafety_AddRemove_ShouldWorkCorrectly()
164+
{
165+
var list = new SynchronizedList<int>();
166+
var tasks = new List<Task>();
167+
168+
for (var i = 0; i < 100; i++)
169+
{
170+
var value = i;
171+
tasks.Add(Task.Run(() => list.Add(value)));
172+
}
173+
174+
await Task.WhenAll(tasks);
175+
Assert.Equal(100, list.Count);
176+
177+
tasks.Clear();
178+
for (var i = 0; i < 100; i++)
179+
{
180+
var value = i;
181+
tasks.Add(Task.Run(() => list.Remove(value)));
182+
}
183+
184+
await Task.WhenAll(tasks);
185+
Assert.Empty(list);
186+
}
187+
}

0 commit comments

Comments
 (0)