Skip to content

Commit 305bbe9

Browse files
committed
Added missing tests
1 parent c9550aa commit 305bbe9

File tree

3 files changed

+328
-0
lines changed

3 files changed

+328
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using AutoMapper.EquivalencyExpression;
5+
using FluentAssertions;
6+
using Xunit;
7+
8+
namespace AutoMapper.Collection
9+
{
10+
public class IListInsertionTests : MappingTestBase
11+
{
12+
private static void Configure(IMapperConfigurationExpression cfg)
13+
{
14+
cfg.AddCollectionMappers();
15+
cfg.CreateMap<MapCollectionWithEqualityTests.ThingDto, MapCollectionWithEqualityTests.Thing>()
16+
.EqualityComparison((MapCollectionWithEqualityTests.ThingDto dto, MapCollectionWithEqualityTests.Thing entity) => dto.ID == entity.ID);
17+
}
18+
19+
[Fact]
20+
public void Should_insert_new_items_at_correct_position_in_IList()
21+
{
22+
var mapper = CreateMapper(Configure);
23+
24+
// Source requires inserting a new item (ID=4) between two existing ones (1 and 2)
25+
var source = new[]
26+
{
27+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
28+
new MapCollectionWithEqualityTests.ThingDto { ID = 4 },
29+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
30+
};
31+
32+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
33+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
34+
35+
// Use a custom IList implementation that lies about Contains in order to skip the pre-add step
36+
// This forces the mapper to take the list.Insert(i, target) branch when placing the new item
37+
var destination = new ContainsAlwaysTrueList<MapCollectionWithEqualityTests.Thing> { b, a };
38+
39+
var result = mapper.Map(source, destination);
40+
41+
result.Should().BeSameAs(destination);
42+
result.Select(t => t.ID).Should().ContainInOrder(1, 4, 2);
43+
result[0].Should().BeSameAs(a);
44+
result[2].Should().BeSameAs(b);
45+
}
46+
47+
// Test double: wraps List<T> but makes Contains return true even when the item is not present
48+
// This is intentional to exercise the code path that performs Insert(i, target) for new items.
49+
private class ContainsAlwaysTrueList<T> : IList<T>
50+
{
51+
private readonly List<T> _inner = new List<T>();
52+
53+
public IEnumerator<T> GetEnumerator() => _inner.GetEnumerator();
54+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
55+
public void Add(T item) => _inner.Add(item);
56+
public void Clear() => _inner.Clear();
57+
58+
// Lie about containment to prevent pre-add of new items
59+
public bool Contains(T item) => true;
60+
61+
public void CopyTo(T[] array, int arrayIndex) => _inner.CopyTo(array, arrayIndex);
62+
public bool Remove(T item) => _inner.Remove(item);
63+
public int Count => _inner.Count;
64+
public bool IsReadOnly => false;
65+
public int IndexOf(T item) => _inner.IndexOf(item);
66+
public void Insert(int index, T item) => _inner.Insert(index, item);
67+
public void RemoveAt(int index) => _inner.RemoveAt(index);
68+
public T this[int index]
69+
{
70+
get => _inner[index];
71+
set => _inner[index] = value;
72+
}
73+
}
74+
}
75+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using AutoMapper.EquivalencyExpression;
4+
using FluentAssertions;
5+
using Xunit;
6+
7+
namespace AutoMapper.Collection
8+
{
9+
public class NonListCollectionRebuildTests : MappingTestBase
10+
{
11+
private static void Configure(IMapperConfigurationExpression cfg)
12+
{
13+
cfg.AddCollectionMappers();
14+
cfg.CreateMap<MapCollectionWithEqualityTests.ThingDto, MapCollectionWithEqualityTests.Thing>()
15+
.EqualityComparison((MapCollectionWithEqualityTests.ThingDto dto, MapCollectionWithEqualityTests.Thing entity) => dto.ID == entity.ID);
16+
}
17+
18+
[Fact]
19+
public void Should_rebuild_non_list_collection_in_source_order_preserving_instances()
20+
{
21+
var mapper = CreateMapper(Configure);
22+
23+
var source = new[]
24+
{
25+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
26+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 },
27+
new MapCollectionWithEqualityTests.ThingDto { ID = 3 }
28+
};
29+
30+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
31+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
32+
var c = new MapCollectionWithEqualityTests.Thing { ID = 3 };
33+
34+
// Use LinkedList<T> which is ICollection<T> but not IList<T>, to trigger the fallback branch (lines 121-134)
35+
var destination = new LinkedList<MapCollectionWithEqualityTests.Thing>(new[] { b, a, c });
36+
37+
var result = mapper.Map(source, destination);
38+
39+
result.Should().BeSameAs(destination);
40+
41+
// Verify order and that existing instances were preserved
42+
result.Select(t => t.ID).Should().ContainInOrder(1, 2, 3);
43+
result.ElementAt(0).Should().BeSameAs(a);
44+
result.ElementAt(1).Should().BeSameAs(b);
45+
result.ElementAt(2).Should().BeSameAs(c);
46+
}
47+
48+
[Fact]
49+
public void Should_remove_extraneous_and_add_new_items_then_rebuild_in_order_for_non_list()
50+
{
51+
var mapper = CreateMapper(Configure);
52+
53+
var source = new[]
54+
{
55+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
56+
new MapCollectionWithEqualityTests.ThingDto { ID = 4 },
57+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
58+
};
59+
60+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
61+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
62+
var extra = new MapCollectionWithEqualityTests.Thing { ID = 3 };
63+
64+
var destination = new LinkedList<MapCollectionWithEqualityTests.Thing>(new[] { b, a, extra });
65+
66+
var result = mapper.Map(source, destination);
67+
68+
// New collection should be in source order and preserve existing instances where matched
69+
result.Select(t => t.ID).Should().ContainInOrder(1, 4, 2);
70+
result.ElementAt(0).Should().BeSameAs(a);
71+
result.ElementAt(2).Should().BeSameAs(b);
72+
73+
// Ensure the extraneous item was removed
74+
result.Should().NotContain(extra);
75+
76+
// Ensure the new item (ID=4) was created and added (reference not equal to any existing)
77+
result.Count(t => t.ID == 4).Should().Be(1);
78+
}
79+
}
80+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
using System.Collections.ObjectModel;
2+
using System.Collections.Specialized;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using AutoMapper.EquivalencyExpression;
6+
using FluentAssertions;
7+
using Xunit;
8+
9+
namespace AutoMapper.Collection
10+
{
11+
public class ObservableCollectionReorderingTests : MappingTestBase
12+
{
13+
private static void Configure(IMapperConfigurationExpression cfg)
14+
{
15+
cfg.AddCollectionMappers();
16+
cfg.CreateMap<MapCollectionWithEqualityTests.ThingDto, MapCollectionWithEqualityTests.Thing>()
17+
.EqualityComparison((MapCollectionWithEqualityTests.ThingDto dto, MapCollectionWithEqualityTests.Thing entity) => dto.ID == entity.ID);
18+
}
19+
20+
[Fact]
21+
public void Reordering_should_raise_Move_event_for_existing_items()
22+
{
23+
var mapper = CreateMapper(Configure);
24+
25+
// Source in desired order
26+
var source = new[]
27+
{
28+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
29+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
30+
};
31+
32+
// Destination has the same two existing instances but in reverse order
33+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
34+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
35+
var destination = new ObservableCollection<MapCollectionWithEqualityTests.Thing> { b, a };
36+
37+
var events = new List<NotifyCollectionChangedEventArgs>();
38+
destination.CollectionChanged += (_, e) => events.Add(e);
39+
40+
// Act
41+
var result = mapper.Map(source, destination);
42+
43+
// Basic correctness checks
44+
result.Should().BeSameAs(destination);
45+
result.Select(t => t.ID).Should().ContainInOrder(1, 2);
46+
result[0].Should().BeSameAs(a);
47+
result[1].Should().BeSameAs(b);
48+
49+
// Event expectations: a single Move from index 1 to 0 for item 'a'
50+
events.Should().HaveCount(1);
51+
events[0].Action.Should().Be(NotifyCollectionChangedAction.Move);
52+
events[0].OldStartingIndex.Should().Be(1);
53+
events[0].NewStartingIndex.Should().Be(0);
54+
events[0].OldItems![0].Should().BeSameAs(a);
55+
}
56+
57+
[Fact]
58+
public void No_reordering_should_not_raise_any_events_for_equal_order()
59+
{
60+
var mapper = CreateMapper(Configure);
61+
62+
var source = new[]
63+
{
64+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
65+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
66+
};
67+
68+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
69+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
70+
var destination = new ObservableCollection<MapCollectionWithEqualityTests.Thing> { a, b };
71+
72+
var events = new List<NotifyCollectionChangedEventArgs>();
73+
destination.CollectionChanged += (_, e) => events.Add(e);
74+
75+
var result = mapper.Map(source, destination);
76+
77+
result.Should().BeSameAs(destination);
78+
result.Select(t => t.ID).Should().ContainInOrder(1, 2);
79+
events.Should().BeEmpty();
80+
}
81+
82+
[Fact]
83+
public void Complex_reordering_should_raise_only_Move_events()
84+
{
85+
var mapper = CreateMapper(Configure);
86+
87+
var source = new[]
88+
{
89+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
90+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 },
91+
new MapCollectionWithEqualityTests.ThingDto { ID = 3 }
92+
};
93+
94+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
95+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
96+
var c = new MapCollectionWithEqualityTests.Thing { ID = 3 };
97+
var destination = new ObservableCollection<MapCollectionWithEqualityTests.Thing> { c, a, b };
98+
99+
var events = new List<NotifyCollectionChangedEventArgs>();
100+
destination.CollectionChanged += (_, e) => events.Add(e);
101+
102+
var result = mapper.Map(source, destination);
103+
104+
result.Should().BeSameAs(destination);
105+
result.Select(t => t.ID).Should().ContainInOrder(1, 2, 3);
106+
result[0].Should().BeSameAs(a);
107+
result[1].Should().BeSameAs(b);
108+
result[2].Should().BeSameAs(c);
109+
110+
// Expect two Move events (reorder existing items), no Add/Remove
111+
events.Should().HaveCount(2);
112+
events.Should().OnlyContain(e => e.Action == NotifyCollectionChangedAction.Move);
113+
}
114+
115+
[Fact]
116+
public void Reordering_with_new_items_should_raise_Add_and_Move_events()
117+
{
118+
var mapper = CreateMapper(Configure);
119+
120+
var source = new[]
121+
{
122+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
123+
new MapCollectionWithEqualityTests.ThingDto { ID = 4 },
124+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
125+
};
126+
127+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
128+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
129+
var destination = new ObservableCollection<MapCollectionWithEqualityTests.Thing> { b, a };
130+
131+
var events = new List<NotifyCollectionChangedEventArgs>();
132+
destination.CollectionChanged += (_, e) => events.Add(e);
133+
134+
var result = mapper.Map(source, destination);
135+
136+
result.Select(t => t.ID).Should().ContainInOrder(1, 4, 2);
137+
result[0].Should().BeSameAs(a);
138+
result[2].Should().BeSameAs(b);
139+
140+
// Expect: Move(a 1->0), Add(4 at 1), Move(b 1->2)
141+
events.Count(e => e.Action == NotifyCollectionChangedAction.Move).Should().Be(2);
142+
events.Count(e => e.Action == NotifyCollectionChangedAction.Add).Should().Be(1);
143+
events.Count(e => e.Action == NotifyCollectionChangedAction.Remove).Should().Be(0);
144+
}
145+
146+
[Fact]
147+
public void Removing_unmatched_items_then_no_reorder_should_raise_only_Remove()
148+
{
149+
var mapper = CreateMapper(Configure);
150+
151+
var source = new[]
152+
{
153+
new MapCollectionWithEqualityTests.ThingDto { ID = 1 },
154+
new MapCollectionWithEqualityTests.ThingDto { ID = 2 }
155+
};
156+
157+
var a = new MapCollectionWithEqualityTests.Thing { ID = 1 };
158+
var b = new MapCollectionWithEqualityTests.Thing { ID = 2 };
159+
var extra = new MapCollectionWithEqualityTests.Thing { ID = 3 };
160+
var destination = new ObservableCollection<MapCollectionWithEqualityTests.Thing> { extra, a, b };
161+
162+
var events = new List<NotifyCollectionChangedEventArgs>();
163+
destination.CollectionChanged += (_, e) => events.Add(e);
164+
165+
var result = mapper.Map(source, destination);
166+
167+
result.Select(t => t.ID).Should().ContainInOrder(1, 2);
168+
events.Count(e => e.Action == NotifyCollectionChangedAction.Remove).Should().Be(1);
169+
events.Count(e => e.Action == NotifyCollectionChangedAction.Move).Should().Be(0);
170+
events.Count(e => e.Action == NotifyCollectionChangedAction.Add).Should().Be(0);
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)