Skip to content

Commit a6acc08

Browse files
authored
Custom comparers (#215)
* Comparers for all indices CharEqualityComparers API for easy ignore case access * - Custom comparers - Some test cleanup * Fixed unit test * Continued * Unit tests for comparers & fixed discovered bug of incorrect FullTextIndex.StartsWith * All unit tests fixed
1 parent 950a153 commit a6acc08

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+954
-414
lines changed

.editorconfig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ csharp_prefer_static_local_function = true:suggestion
4141
csharp_style_prefer_not_pattern = true:suggestion
4242
csharp_style_prefer_top_level_statements = true:silent
4343
csharp_style_conditional_delegate_call = true:suggestion
44+
csharp_style_prefer_primary_constructors = true:suggestion
45+
csharp_prefer_system_threading_lock = true:suggestion
4446
[*.{cs,vb}]
4547
dotnet_style_prefer_auto_properties= true:suggestion
4648
dotnet_style_prefer_conditional_expression_over_assignment= false:suggestion
@@ -124,4 +126,5 @@ dotnet_style_prefer_inferred_tuple_names = true:suggestion
124126
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
125127
dotnet_style_prefer_compound_assignment = true:suggestion
126128
dotnet_style_prefer_simplified_interpolation = true:suggestion
127-
dotnet_style_namespace_match_folder = true:suggestion
129+
dotnet_style_namespace_match_folder = true:suggestion
130+
dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion

Akade.IndexedSet.Tests/CommonIndexTests/BaseIndexTest.Contains.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
using Microsoft.VisualStudio.TestTools.UnitTesting;
22

33
namespace Akade.IndexedSet.Tests.CommonIndexTests;
4-
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex>
4+
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex, TComparer>
55
{
6-
[TestMethod]
6+
[BaseTestMethod]
77
public void Contains_based_methods_should_throw_if_not_supported()
88
{
99
if (!SupportsContainsQueries)
@@ -13,7 +13,7 @@ public void Contains_based_methods_should_throw_if_not_supported()
1313
}
1414
}
1515

16-
[TestMethod]
16+
[BaseTestMethod]
1717
public void Contains_returns_empty_set_if_set_is_empty()
1818
{
1919
if (SupportsContainsQueries)
@@ -23,7 +23,7 @@ public void Contains_returns_empty_set_if_set_is_empty()
2323
}
2424
}
2525

26-
[TestMethod]
26+
[BaseTestMethod]
2727
public void Contains_returns_empty_set_if_no_matching_key_is_available()
2828
{
2929
if (SupportsContainsQueries)
@@ -33,7 +33,7 @@ public void Contains_returns_empty_set_if_no_matching_key_is_available()
3333
}
3434
}
3535

36-
[TestMethod]
36+
[BaseTestMethod]
3737
public void Contains_returns_matching_item()
3838
{
3939
if (SupportsContainsQueries)
@@ -45,7 +45,7 @@ public void Contains_returns_matching_item()
4545
}
4646
}
4747

48-
[TestMethod]
48+
[BaseTestMethod]
4949
public void Contains_returns_multiple_matching_item()
5050
{
5151
if (SupportsContainsQueries)
@@ -61,7 +61,7 @@ public void Contains_returns_multiple_matching_item()
6161
}
6262
}
6363

64-
[TestMethod]
64+
[BaseTestMethod]
6565
public void FuzzyContains_based_methods_should_throw_if_not_supported()
6666
{
6767
if (!SupportsContainsQueries)
@@ -71,7 +71,7 @@ public void FuzzyContains_based_methods_should_throw_if_not_supported()
7171
}
7272
}
7373

74-
[TestMethod]
74+
[BaseTestMethod]
7575
public void FuzzyContains_returns_empty_set_if_set_is_empty()
7676
{
7777
if (SupportsContainsQueries)
@@ -81,7 +81,7 @@ public void FuzzyContains_returns_empty_set_if_set_is_empty()
8181
}
8282
}
8383

84-
[TestMethod]
84+
[BaseTestMethod]
8585
public void FuzzyContains_returns_empty_set_if_no_matching_key_is_available()
8686
{
8787
if (SupportsContainsQueries)
@@ -91,7 +91,7 @@ public void FuzzyContains_returns_empty_set_if_no_matching_key_is_available()
9191
}
9292
}
9393

94-
[TestMethod]
94+
[BaseTestMethod]
9595
public void FuzzyContains_returns_matching_item()
9696
{
9797
if (SupportsContainsQueries)
@@ -108,7 +108,7 @@ public void FuzzyContains_returns_matching_item()
108108
}
109109
}
110110

111-
[TestMethod]
111+
[BaseTestMethod]
112112
public void FuzzyContains_returns_multiple_matching_item()
113113
{
114114
if (SupportsContainsQueries)

Akade.IndexedSet.Tests/CommonIndexTests/BaseIndexTest.RangeQueries.cs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
using Microsoft.VisualStudio.TestTools.UnitTesting;
1+
using Akade.IndexedSet.Tests.TestUtilities;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
23

34
namespace Akade.IndexedSet.Tests.CommonIndexTests;
4-
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex>
5+
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex, TComparer>
56
{
6-
[TestMethod]
7+
[BaseTestMethod]
78
public void Range_based_methods_should_throw_if_not_supported()
89
{
910
if (!SupportsRangeBasedQueries)
@@ -23,7 +24,7 @@ public void Range_based_methods_should_throw_if_not_supported()
2324
}
2425
}
2526

26-
[TestMethod]
27+
[BaseTestMethod]
2728
public void Range_returns_empty_result_if_not_present()
2829
{
2930
if (SupportsRangeBasedQueries)
@@ -33,7 +34,7 @@ public void Range_returns_empty_result_if_not_present()
3334
}
3435
}
3536

36-
[TestMethod]
37+
[BaseTestMethod]
3738
public void Range_returns_sorted_elements_respecting_boundary_parameters_for_unique_data()
3839
{
3940
if (SupportsRangeBasedQueries)
@@ -42,7 +43,7 @@ public void Range_returns_sorted_elements_respecting_boundary_parameters_for_uni
4243
TElement[] data = GetUniqueData();
4344
AddElements(data, index);
4445

45-
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor)];
46+
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor, ComparerUtils.GetComparer<TIndexKey>(_comparer))];
4647

4748
TIndexKey rangeStart = _keyAccessor(orderedElements[1]);
4849
TIndexKey rangeEnd = _keyAccessor(orderedElements[^2]);
@@ -53,7 +54,7 @@ public void Range_returns_sorted_elements_respecting_boundary_parameters_for_uni
5354
}
5455
}
5556

56-
[TestMethod]
57+
[BaseTestMethod]
5758
public void Comparison_queries_return_empty_result_if_no_element_is_present()
5859
{
5960
if (SupportsRangeBasedQueries)
@@ -66,25 +67,25 @@ public void Comparison_queries_return_empty_result_if_no_element_is_present()
6667
}
6768
}
6869

69-
[TestMethod]
70+
[BaseTestMethod]
7071
public void Comparison_queries_return_sorted_elements_respecting_boundary()
7172
{
7273
if (SupportsRangeBasedQueries)
7374
{
7475
TIndex index = CreateIndex();
7576
TElement[] data = GetUniqueData();
7677
AddElements(data, index);
77-
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor)];
78+
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor, ComparerUtils.GetComparer<TIndexKey>(_comparer))];
7879

79-
TIndexKey boundary = _keyAccessor(orderedElements[3]);
80-
CollectionAssert.AreEqual(orderedElements[0..3], index.LessThan(boundary).ToArray());
81-
CollectionAssert.AreEqual(orderedElements[0..4], index.LessThanOrEqual(boundary).ToArray());
82-
CollectionAssert.AreEqual(orderedElements[4..], index.GreaterThan(boundary).ToArray());
83-
CollectionAssert.AreEqual(orderedElements[3..], index.GreaterThanOrEqual(boundary).ToArray());
80+
TIndexKey boundary = _keyAccessor(orderedElements[2]);
81+
CollectionAssert.AreEqual(orderedElements[0..2], index.LessThan(boundary).ToArray());
82+
CollectionAssert.AreEqual(orderedElements[0..3], index.LessThanOrEqual(boundary).ToArray());
83+
CollectionAssert.AreEqual(orderedElements[3..], index.GreaterThan(boundary).ToArray());
84+
CollectionAssert.AreEqual(orderedElements[2..], index.GreaterThanOrEqual(boundary).ToArray());
8485
}
8586
}
8687

87-
[TestMethod]
88+
[BaseTestMethod]
8889
public void MaxMin_throw_if_the_set_is_empty()
8990
{
9091
if (SupportsRangeBasedQueries)
@@ -95,7 +96,7 @@ public void MaxMin_throw_if_the_set_is_empty()
9596
}
9697
}
9798

98-
[TestMethod]
99+
[BaseTestMethod]
99100
public void MaxMin_return_empty_enumerable_if_the_set_is_empty()
100101
{
101102
if (SupportsRangeBasedQueries)
@@ -106,7 +107,7 @@ public void MaxMin_return_empty_enumerable_if_the_set_is_empty()
106107
}
107108
}
108109

109-
[TestMethod]
110+
[BaseTestMethod]
110111
public void MaxMin_return_correct_key_and_values()
111112
{
112113
if (SupportsRangeBasedQueries)
@@ -115,7 +116,7 @@ public void MaxMin_return_correct_key_and_values()
115116
TElement[] data = GetUniqueData();
116117
AddElements(data, index);
117118

118-
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor)];
119+
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor, ComparerUtils.GetComparer<TIndexKey>(_comparer))];
119120

120121
Assert.AreEqual(_keyAccessor(orderedElements[0]), index.Min());
121122
Assert.AreEqual(orderedElements[0], index.MinBy().Single());
@@ -125,7 +126,7 @@ public void MaxMin_return_correct_key_and_values()
125126
}
126127
}
127128

128-
[TestMethod]
129+
[BaseTestMethod]
129130
public void OrderBy_returns_empty_values_with_no_data()
130131
{
131132
if (SupportsRangeBasedQueries)
@@ -135,7 +136,7 @@ public void OrderBy_returns_empty_values_with_no_data()
135136
}
136137
}
137138

138-
[TestMethod]
139+
[BaseTestMethod]
139140
public void OrderBy_throws_if_skip_value_is_too_large()
140141
{
141142
if (SupportsRangeBasedQueries)
@@ -147,15 +148,15 @@ public void OrderBy_throws_if_skip_value_is_too_large()
147148
}
148149
}
149150

150-
[TestMethod]
151+
[BaseTestMethod]
151152
public void OrderBy_returns_sorted_values()
152153
{
153154
if (SupportsRangeBasedQueries)
154155
{
155156
TIndex index = CreateIndex();
156157
TElement[] data = GetUniqueData();
157158
AddElements(data, index);
158-
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor)];
159+
TElement[] orderedElements = [.. data.OrderBy(_keyAccessor, ComparerUtils.GetComparer<TIndexKey>(_comparer))];
159160

160161
for (int i = 0; i < orderedElements.Length; i++)
161162
{
@@ -164,7 +165,7 @@ public void OrderBy_returns_sorted_values()
164165
}
165166
}
166167

167-
[TestMethod]
168+
[BaseTestMethod]
168169
public void OrderByDescending_returns_empty_values_with_no_data()
169170
{
170171
if (SupportsRangeBasedQueries)
@@ -174,7 +175,7 @@ public void OrderByDescending_returns_empty_values_with_no_data()
174175
}
175176
}
176177

177-
[TestMethod]
178+
[BaseTestMethod]
178179
public void OrderByDescending_throws_if_skip_value_is_too_large()
179180
{
180181
if (SupportsRangeBasedQueries)
@@ -186,15 +187,15 @@ public void OrderByDescending_throws_if_skip_value_is_too_large()
186187
}
187188
}
188189

189-
[TestMethod]
190+
[BaseTestMethod]
190191
public void OrderByDescending_returns_sorted_values()
191192
{
192193
if (SupportsRangeBasedQueries)
193194
{
194195
TIndex index = CreateIndex();
195196
TElement[] data = GetUniqueData();
196197
AddElements(data, index);
197-
TElement[] orderedElements = [.. data.OrderByDescending(_keyAccessor)];
198+
TElement[] orderedElements = [.. data.OrderByDescending(_keyAccessor, ComparerUtils.GetComparer<TIndexKey>(_comparer))];
198199

199200
for (int i = 0; i < orderedElements.Length; i++)
200201
{

Akade.IndexedSet.Tests/CommonIndexTests/BaseIndexTest.Single.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,59 @@
1-
using Microsoft.VisualStudio.TestTools.UnitTesting;
1+
using Akade.IndexedSet.Tests.TestUtilities;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
23

34
namespace Akade.IndexedSet.Tests.CommonIndexTests;
4-
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex>
5+
internal abstract partial class BaseIndexTest<TIndexKey, TElement, TIndex, TComparer>
56
{
67

7-
[TestMethod]
8+
[BaseTestMethod]
89
public void Single_should_return_matching_element()
910
{
1011
TElement[] data = GetUniqueData();
1112
TIndex index = CreateIndexWithData(data);
1213
Assert.AreEqual(data[0], index.Single(_keyAccessor(data[0])));
1314
}
1415

15-
[TestMethod]
16+
[BaseTestMethod]
1617
public void Single_should_throw_if_empty()
1718
{
1819
TIndex index = CreateIndex();
1920
_ = Assert.ThrowsException<KeyNotFoundException>(() => index.Single(GetNotExistingKey()));
2021
}
2122

22-
[TestMethod]
23+
[BaseTestMethod]
2324
public void Single_should_throw_if_not_found()
2425
{
2526
TIndex index = CreateIndexWithData(GetUniqueData());
2627
_ = Assert.ThrowsException<KeyNotFoundException>(() => index.Single(GetNotExistingKey()));
2728
}
2829

29-
[TestMethod]
30+
[BaseTestMethod]
3031
public void Single_should_throw_if_multiple_entries_are_found()
3132
{
3233
if (SupportsNonUniqueKeys)
3334
{
3435
TElement[] data = GetNonUniqueData();
3536
TIndex index = CreateIndexWithData(data);
36-
TIndexKey nonUniqueKey = data.GroupBy(_keyAccessor).Where(x => x.Count() > 1).First().Key;
37+
TIndexKey nonUniqueKey = data.GroupByWithSortBasedFallback(_keyAccessor, _comparer).Where(x => x.Count() > 1).First().Key;
3738
_ = Assert.ThrowsException<InvalidOperationException>(() => index.Single(nonUniqueKey));
3839
}
3940
}
4041

41-
[TestMethod]
42+
[BaseTestMethod]
4243
public void TryGetSingle_should_return_false_if_empty()
4344
{
4445
TIndex index = CreateIndex();
4546
Assert.IsFalse(index.TryGetSingle(GetNotExistingKey(), out _));
4647
}
4748

48-
[TestMethod]
49+
[BaseTestMethod]
4950
public void TryGetSingle_should_return_false_if_key_is_not_present()
5051
{
5152
TIndex index = CreateIndexWithData(GetUniqueData());
5253
Assert.IsFalse(index.TryGetSingle(GetNotExistingKey(), out _));
5354
}
5455

55-
[TestMethod]
56+
[BaseTestMethod]
5657
public void TryGetSingle_should_return_true_for_matching_element()
5758
{
5859
TElement[] data = GetUniqueData();
@@ -61,14 +62,14 @@ public void TryGetSingle_should_return_true_for_matching_element()
6162
Assert.AreEqual(data[0], element);
6263
}
6364

64-
[TestMethod]
65+
[BaseTestMethod]
6566
public void TryGetSingle_should_return_false_if_multiple_entries_are_found()
6667
{
6768
if (SupportsNonUniqueKeys)
6869
{
6970
TElement[] data = GetNonUniqueData();
7071
TIndex index = CreateIndexWithData(data);
71-
TIndexKey nonUniqueKey = data.GroupBy(_keyAccessor).Where(x => x.Count() > 1).First().Key;
72+
TIndexKey nonUniqueKey = data.GroupByWithSortBasedFallback(_keyAccessor, _comparer).Where(x => x.Count() > 1).First().Key;
7273
Assert.IsFalse(index.TryGetSingle(nonUniqueKey, out _));
7374
}
7475
}

0 commit comments

Comments
 (0)