Skip to content

Commit 93998df

Browse files
committed
Add missing GetHashCode methods
1 parent 1d20393 commit 93998df

File tree

2 files changed

+140
-2
lines changed

2 files changed

+140
-2
lines changed

backend/FwLite/MiniLcm.Tests/RichMultiStringTests.cs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Drawing;
21
using System.Text.Json;
32
using MiniLcm.Tests.AutoFakerHelpers;
43
using Soenneker.Utils.AutoBogus;
@@ -10,6 +9,7 @@ namespace MiniLcm.Tests;
109
public class RichMultiStringTests
1110
{
1211
private static readonly AutoFaker AutoFaker = new(AutoFakerDefault.Config);
12+
1313
[Fact]
1414
public void RichMultiString_DeserializesSimpleRichString()
1515
{
@@ -146,6 +146,7 @@ public void RichSpan_EqualityTests()
146146
var actualSpan = richSpan.Copy();
147147
richSpan.Should().Be(actualSpan);
148148
richSpan.Equals(actualSpan).Should().BeTrue();
149+
richSpan.GetHashCode().Should().Be(actualSpan.GetHashCode());
149150
}
150151

151152
[Fact]
@@ -185,6 +186,19 @@ public void RichSpan_EqualityObjectDataMustMatch()
185186
[Fact]
186187
public void RichSpan_PerPropertyEqualityTests()
187188
{
189+
static object GenerateDifferentValue(AutoFaker autoFaker, Type type, object? currentValue)
190+
{
191+
// AutoBogus can return null/default; retry until we actually change the field so the test is a reliable tripwire.
192+
for (var attempt = 0; attempt < 20; attempt++)
193+
{
194+
var value = autoFaker.Generate(type);
195+
if (value is null) continue;
196+
if (currentValue is null || !currentValue.Equals(value)) return value;
197+
}
198+
199+
throw new InvalidOperationException($"Unable to generate a different value for type '{type.FullName}'.");
200+
}
201+
188202
var blankSpan = new RichSpan()
189203
{
190204
Text = "test"
@@ -195,11 +209,38 @@ public void RichSpan_PerPropertyEqualityTests()
195209
if (fieldInfo.FieldType == typeof(RichTextObjectData)) continue;
196210
var span = new RichSpan() { Text = "test" };
197211
span.Equals(blankSpan).Should().BeTrue();
198-
fieldInfo.SetValue(span, AutoFaker.Generate(fieldInfo.FieldType));
212+
var currentValue = fieldInfo.GetValue(span);
213+
var differentValue = GenerateDifferentValue(AutoFaker, fieldInfo.FieldType, currentValue);
214+
fieldInfo.SetValue(span, differentValue);
199215
span.Equals(blankSpan).Should().BeFalse("field {0} do not match", fieldInfo.Name);
200216
}
201217
}
202218

219+
[Fact]
220+
public void RichString_HashCodeMatchesEquality()
221+
{
222+
var rs1 = new RichString([new RichSpan() { Text = "test", Ws = "en", Bold = RichTextToggle.On }]);
223+
var rs2 = rs1.Copy();
224+
225+
rs1.Equals(rs2).Should().BeTrue();
226+
rs1.GetHashCode().Should().Be(rs2.GetHashCode());
227+
}
228+
229+
[Fact]
230+
public void RichString_HashCodeMatchesEquality_ManySeededCases()
231+
{
232+
var seededFaker = new AutoFaker(AutoFakerDefault.Config);
233+
seededFaker.UseSeed(12345);
234+
for (var i = 0; i < 200; i++)
235+
{
236+
var rs1 = seededFaker.Generate<RichString>();
237+
var rs2 = rs1.Copy();
238+
239+
rs1.Equals(rs2).Should().BeTrue();
240+
rs1.GetHashCode().Should().Be(rs2.GetHashCode());
241+
}
242+
}
243+
203244
[Fact]
204245
public void JsonPatchCanUpdateRichMultiString()
205246
{

backend/FwLite/MiniLcm/Models/RichString.cs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,17 @@ public override bool Equals(object? obj)
103103
if (obj.GetType() != GetType()) return false;
104104
return Equals((RichString)obj);
105105
}
106+
107+
public override int GetHashCode()
108+
{
109+
var hash = new HashCode();
110+
foreach (var span in Spans)
111+
{
112+
hash.Add(span);
113+
}
114+
115+
return hash.ToHashCode();
116+
}
106117
}
107118

108119

@@ -300,6 +311,92 @@ public virtual bool Equals(RichSpan? other)
300311
return EqualsProps(other) && Text == other.Text;
301312
}
302313

314+
public override int GetHashCode()
315+
{
316+
var hash = new HashCode();
317+
318+
hash.Add(Ws);
319+
hash.Add(WsBase);
320+
hash.Add(Italic);
321+
hash.Add(Bold);
322+
hash.Add(Align);
323+
hash.Add(Superscript);
324+
hash.Add(Underline);
325+
hash.Add(FontFamily);
326+
hash.Add(FontSize);
327+
hash.Add(FontSizeUnit);
328+
hash.Add(FontVariations);
329+
hash.Add(Offset);
330+
hash.Add(OffsetUnit);
331+
hash.Add(ForeColor);
332+
hash.Add(BackColor);
333+
hash.Add(UnderColor);
334+
hash.Add(FirstIndent);
335+
hash.Add(LeadingIndent);
336+
hash.Add(TrailingIndent);
337+
hash.Add(SpaceBefore);
338+
hash.Add(SpaceAfter);
339+
hash.Add(MarginTop);
340+
hash.Add(TabDef);
341+
hash.Add(LineHeight);
342+
hash.Add(LineHeightUnit);
343+
hash.Add(ParaColor);
344+
hash.Add(SpellCheck);
345+
hash.Add(RightToLeft);
346+
hash.Add(DirectionDepth);
347+
hash.Add(KeepWithNext);
348+
hash.Add(KeepTogether);
349+
hash.Add(Hyphenate);
350+
hash.Add(MaxLines);
351+
hash.Add(CellBorderWidth);
352+
hash.Add(CellSpacing);
353+
hash.Add(CellPadding);
354+
hash.Add(Editable);
355+
hash.Add(SetRowDefaults);
356+
hash.Add(RelLineHeight);
357+
hash.Add(WidowOrphan);
358+
hash.Add(PadTop);
359+
hash.Add(PadBottom);
360+
hash.Add(PadLeading);
361+
hash.Add(PadTrailing);
362+
hash.Add(ParaStyle);
363+
hash.Add(CharStyle);
364+
hash.Add(NamedStyle);
365+
hash.Add(WsStyle);
366+
hash.Add(BorderTop);
367+
hash.Add(BorderBottom);
368+
hash.Add(BorderLeading);
369+
hash.Add(BorderTrailing);
370+
hash.Add(BorderColor);
371+
hash.Add(BulNumScheme);
372+
hash.Add(BulNumStartAt);
373+
hash.Add(BulNumTxtBef);
374+
hash.Add(BulNumTxtAft);
375+
hash.Add(BulNumFontInfo);
376+
hash.Add(CustomBullet);
377+
hash.Add(TabList);
378+
hash.Add(TableRule);
379+
hash.Add(FieldName);
380+
hash.Add(ObjData);
381+
382+
if (Tags is null)
383+
{
384+
hash.Add(0);
385+
}
386+
else
387+
{
388+
hash.Add(1);
389+
foreach (var tag in Tags)
390+
{
391+
hash.Add(tag);
392+
}
393+
}
394+
395+
hash.Add(Text);
396+
397+
return hash.ToHashCode();
398+
}
399+
303400
public bool EqualsProps(RichSpan? other)
304401
{
305402
if (other is null) return false;

0 commit comments

Comments
 (0)