Skip to content

Commit 8e5c926

Browse files
committed
Extracted static allocations of collation instances only used by tests.
1 parent 91d2a62 commit 8e5c926

2 files changed

Lines changed: 47 additions & 80 deletions

File tree

SqlServerSimulator.Tests.Internal/CollationTests.cs

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,27 @@ namespace SqlServerSimulator;
99
/// name-resolution surface (<see cref="Collation.TryGet"/> /
1010
/// <see cref="Collation.IsRecognized"/>) are exercised in the public
1111
/// <c>CollationBehaviorTests</c> / <c>CollationMetadataTests</c> /
12-
/// <c>LikeTests</c>; this file keeps only the dormant comparers
13-
/// (<see cref="Collation.Latin1General100CiAs"/>,
14-
/// <see cref="Collation.Latin1GeneralCiAs"/>,
15-
/// <see cref="Collation.Latin1GeneralCsAs"/>,
16-
/// <see cref="Collation.Latin1GeneralBin"/>) and the internal-only null
17-
/// handling of <see cref="Collation.Default"/>'s
18-
/// <see cref="IComparer{T}"/> / <see cref="IEqualityComparer{T}"/>
19-
/// contracts. The dormant algorithms exist in the code but aren't called
20-
/// from any public SQL site (every string op outside the LIKE
21-
/// case-sensitivity flag still goes through <see cref="Collation.Default"/>
22-
/// — see <c>docs/claude/database-options.md</c>); the tests pin the
23-
/// dormant contract so the algorithms behave correctly once routing
24-
/// lands.
12+
/// <c>LikeTests</c>; this file keeps the non-default-collation algorithm
13+
/// contracts and the internal-only null handling of
14+
/// <see cref="Collation.Default"/>'s <see cref="IComparer{T}"/> /
15+
/// <see cref="IEqualityComparer{T}"/> contracts. The non-default
16+
/// algorithms exist in the code but aren't called from any public SQL
17+
/// site (every string op outside the LIKE case-sensitivity flag still
18+
/// goes through <see cref="Collation.Default"/> — see
19+
/// <c>docs/claude/database-options.md</c>); the tests pin the contract
20+
/// so the algorithms behave correctly once routing lands.
2521
/// </summary>
2622
[TestClass]
2723
public sealed class CollationTests
2824
{
25+
private static readonly Collation Latin1General100CiAs = Collation.TryGet("Latin1_General_100_CI_AS")!;
26+
27+
private static readonly Collation Latin1GeneralCiAs = Collation.TryGet("Latin1_General_CI_AS")!;
28+
29+
private static readonly Collation Latin1GeneralCsAs = Collation.TryGet("Latin1_General_CS_AS")!;
30+
31+
private static readonly Collation Latin1GeneralBin = Collation.TryGet("Latin1_General_BIN")!;
32+
2933
// ---- SQL_Latin1_General_CP1_CI_AS — internal-only contracts ----
3034

3135
/// <summary>
@@ -53,16 +57,16 @@ public void Sql_NullHandling()
5357
[TestMethod]
5458
public void Win100_AsciiCaseFolding_EqualAndOrderedSame()
5559
{
56-
IsTrue(Collation.Latin1General100CiAs.Equals("abc", "ABC"));
57-
AreEqual(0, Collation.Latin1General100CiAs.Compare("abc", "ABC"));
58-
AreEqual(Collation.Latin1General100CiAs.GetHashCode("abc"), Collation.Latin1General100CiAs.GetHashCode("ABC"));
60+
IsTrue(Latin1General100CiAs.Equals("abc", "ABC"));
61+
AreEqual(0, Latin1General100CiAs.Compare("abc", "ABC"));
62+
AreEqual(Latin1General100CiAs.GetHashCode("abc"), Latin1General100CiAs.GetHashCode("ABC"));
5963
}
6064

6165
[TestMethod]
6266
public void Win100_AccentSensitive()
6367
{
64-
IsFalse(Collation.Latin1General100CiAs.Equals("e", "é"));
65-
AreNotEqual(0, Collation.Latin1General100CiAs.Compare("e", "é"));
68+
IsFalse(Latin1General100CiAs.Equals("e", "é"));
69+
AreNotEqual(0, Latin1General100CiAs.Compare("e", "é"));
6670
}
6771

6872
[TestMethod]
@@ -72,16 +76,16 @@ public void Win100_ApostropheIsPrimaryWeightZero_InSort()
7276
// MIN of ('Aaronsburg', "'Aiea") is 'Aaronsburg' under
7377
// Latin1_General_100_CI_AS because the apostrophe drops out of
7478
// the primary sort key, leaving "Aiea" > "Aaronsburg".
75-
IsLessThan(0, Collation.Latin1General100CiAs.Compare("Aaronsburg", "'Aiea"));
76-
AreEqual(0, Collation.Latin1General100CiAs.Compare("'A", "A"));
77-
AreEqual(0, Collation.Latin1General100CiAs.Compare("O'Brien", "OBrien"));
79+
IsLessThan(0, Latin1General100CiAs.Compare("Aaronsburg", "'Aiea"));
80+
AreEqual(0, Latin1General100CiAs.Compare("'A", "A"));
81+
AreEqual(0, Latin1General100CiAs.Compare("O'Brien", "OBrien"));
7882
}
7983

8084
[TestMethod]
8185
public void Win100_HyphenIsPrimaryWeightZero_InSort()
8286
{
83-
AreEqual(0, Collation.Latin1General100CiAs.Compare("co-op", "coop"));
84-
AreEqual(0, Collation.Latin1General100CiAs.Compare("re-do", "redo"));
87+
AreEqual(0, Latin1General100CiAs.Compare("co-op", "coop"));
88+
AreEqual(0, Latin1General100CiAs.Compare("re-do", "redo"));
8589
}
8690

8791
[TestMethod]
@@ -90,27 +94,27 @@ public void Win100_Equality_IsStrictAboutSymbols_NotJustSort()
9094
// Probe-confirmed: 'OBrien' = 'O''Brien' returns 0 even under
9195
// Windows-100 CI_AS. The primary-weight-zero treatment only
9296
// applies to sort/MIN/MAX, not to '='.
93-
IsFalse(Collation.Latin1General100CiAs.Equals("O'Brien", "OBrien"));
94-
IsFalse(Collation.Latin1General100CiAs.Equals("'A", "A"));
95-
IsFalse(Collation.Latin1General100CiAs.Equals("co-op", "coop"));
97+
IsFalse(Latin1General100CiAs.Equals("O'Brien", "OBrien"));
98+
IsFalse(Latin1General100CiAs.Equals("'A", "A"));
99+
IsFalse(Latin1General100CiAs.Equals("co-op", "coop"));
96100
}
97101

98102
[TestMethod]
99103
public void Win100_HashCode_AgreesWithEquals()
100104
{
101-
AreEqual(Collation.Latin1General100CiAs.GetHashCode("AbC"), Collation.Latin1General100CiAs.GetHashCode("abc"));
105+
AreEqual(Latin1General100CiAs.GetHashCode("AbC"), Latin1General100CiAs.GetHashCode("abc"));
102106
// And differs for strings the equality side distinguishes.
103-
AreNotEqual(Collation.Latin1General100CiAs.GetHashCode("O'Brien"), Collation.Latin1General100CiAs.GetHashCode("OBrien"));
107+
AreNotEqual(Latin1General100CiAs.GetHashCode("O'Brien"), Latin1General100CiAs.GetHashCode("OBrien"));
104108
}
105109

106110
[TestMethod]
107111
public void Win100_NullHandling()
108112
{
109-
IsTrue(Collation.Latin1General100CiAs.Equals(null, null));
110-
IsFalse(Collation.Latin1General100CiAs.Equals(null, "x"));
111-
AreEqual(0, Collation.Latin1General100CiAs.Compare(null, null));
112-
IsLessThan(0, Collation.Latin1General100CiAs.Compare(null, "x"));
113-
IsGreaterThan(0, Collation.Latin1General100CiAs.Compare("x", null));
113+
IsTrue(Latin1General100CiAs.Equals(null, null));
114+
IsFalse(Latin1General100CiAs.Equals(null, "x"));
115+
AreEqual(0, Latin1General100CiAs.Compare(null, null));
116+
IsLessThan(0, Latin1General100CiAs.Compare(null, "x"));
117+
IsGreaterThan(0, Latin1General100CiAs.Compare("x", null));
114118
}
115119

116120
// ---- Latin1_General_CI_AS (Windows-style pre-v100) ----
@@ -122,21 +126,21 @@ public void Win80_BehavesLikeWin100_ForAsciiAndLatin1()
122126
// v100 are identical (the v100 update changed ordering for non-
123127
// Latin scripts and a handful of newly-added supplementary code
124128
// points; none reach the regression bar).
125-
IsTrue(Collation.Latin1GeneralCiAs.Equals("abc", "ABC"));
126-
AreEqual(0, Collation.Latin1GeneralCiAs.Compare("'A", "A"));
127-
IsFalse(Collation.Latin1GeneralCiAs.Equals("'A", "A"));
128-
IsLessThan(0, Collation.Latin1GeneralCiAs.Compare("Aaronsburg", "'Aiea"));
129+
IsTrue(Latin1GeneralCiAs.Equals("abc", "ABC"));
130+
AreEqual(0, Latin1GeneralCiAs.Compare("'A", "A"));
131+
IsFalse(Latin1GeneralCiAs.Equals("'A", "A"));
132+
IsLessThan(0, Latin1GeneralCiAs.Compare("Aaronsburg", "'Aiea"));
129133
}
130134

131135
[TestMethod]
132136
public void Win80_HashCode_AgreesWithEquals()
133-
=> AreEqual(Collation.Latin1GeneralCiAs.GetHashCode("AbC"), Collation.Latin1GeneralCiAs.GetHashCode("abc"));
137+
=> AreEqual(Latin1GeneralCiAs.GetHashCode("AbC"), Latin1GeneralCiAs.GetHashCode("abc"));
134138

135139
// ---- Latin1_General_CS_AS ----
136140

137141
[TestMethod]
138142
public void CsAs_AccentSensitive()
139-
=> IsFalse(Collation.Latin1GeneralCsAs.Equals("e", "é"));
143+
=> IsFalse(Latin1GeneralCsAs.Equals("e", "é"));
140144

141145
// ---- Latin1_General_BIN ----
142146

@@ -146,9 +150,11 @@ public void Bin_StrictCodepoint_DistinguishesNfdAndNfc()
146150
// NFC = single precomposed U+00E9; NFD = base 'e' + combining
147151
// U+0301. Ordinal compare treats them as distinct byte sequences;
148152
// CompareInfo-based comparers (Sql, Win100, CsAs) fold them.
153+
// Spelled with escapes so editor / tool normalization can't collapse
154+
// the two literals into the same encoded form.
149155
const string nfc = "é";
150156
const string nfd = "é";
151-
IsFalse(Collation.Latin1GeneralBin.Equals(nfc, nfd));
157+
IsFalse(Latin1GeneralBin.Equals(nfc, nfd));
152158
IsTrue(Collation.Default.Equals(nfc, nfd));
153159
}
154160
}

SqlServerSimulator/Collation.cs

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -75,53 +75,14 @@ private protected Collation()
7575
/// </summary>
7676
internal static Collation Default => defaultLazy.Value;
7777

78-
/// <summary>
79-
/// Convenience accessor for the v100 Windows-style CI_AS variant.
80-
/// Retained for the internal test surface that exercises the dormant
81-
/// Windows-CI body directly; new call sites should use
82-
/// <see cref="TryGet"/> with the literal name.
83-
/// </summary>
84-
internal static Collation Latin1General100CiAs => latin1General100CiAsLazy.Value;
85-
86-
/// <summary>
87-
/// Convenience accessor for the pre-v100 Windows-style CI_AS variant.
88-
/// Same retention rationale as <see cref="Latin1General100CiAs"/>.
89-
/// </summary>
90-
internal static Collation Latin1GeneralCiAs => latin1GeneralCiAsLazy.Value;
91-
92-
/// <summary>
93-
/// Convenience accessor for the Windows-style CS_AS variant. Same
94-
/// retention rationale as <see cref="Latin1General100CiAs"/>.
95-
/// </summary>
96-
internal static Collation Latin1GeneralCsAs => latin1GeneralCsAsLazy.Value;
97-
98-
/// <summary>
99-
/// Convenience accessor for the pre-2005 binary collation (asymmetric
100-
/// position-0-codeunit / position-1+-codepoint compare on nvarchar).
101-
/// Same retention rationale as <see cref="Latin1General100CiAs"/>.
102-
/// </summary>
103-
internal static Collation Latin1GeneralBin => latin1GeneralBinLazy.Value;
104-
105-
// <see cref="Lazy{T}"/> wrappers defer the <see cref="TryGet"/> call
78+
// <see cref="Lazy{T}"/> wrapper defers the <see cref="TryGet"/> call
10679
// until first access — the alternative (eager field initialization)
10780
// races the parser-state fields across partial-class file boundaries
10881
// and the textual-order guarantee for static-field initializers
10982
// doesn't cross those.
11083
private static readonly Lazy<Collation> defaultLazy =
11184
new(() => TryGet("SQL_Latin1_General_CP1_CI_AS")!);
11285

113-
private static readonly Lazy<Collation> latin1General100CiAsLazy =
114-
new(() => TryGet("Latin1_General_100_CI_AS")!);
115-
116-
private static readonly Lazy<Collation> latin1GeneralCiAsLazy =
117-
new(() => TryGet("Latin1_General_CI_AS")!);
118-
119-
private static readonly Lazy<Collation> latin1GeneralCsAsLazy =
120-
new(() => TryGet("Latin1_General_CS_AS")!);
121-
122-
private static readonly Lazy<Collation> latin1GeneralBinLazy =
123-
new(() => TryGet("Latin1_General_BIN")!);
124-
12586
/// <summary>
12687
/// SQL Server's collation-coercibility resolution for two operands.
12788
/// Returns the winning <see cref="Collation"/> and <see cref="Coercibility"/>

0 commit comments

Comments
 (0)