Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/SIL.LCModel/DomainImpl/OverridesLing_Lex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,13 @@ public static bool CorrectHomographNumbers(List<ILexEntry> rgHomographs)
{
// Should we notify the user that we're doing this helpful renumbering for him?
// We do our best to keep them in the same order.
// Tie-break on DateCreated then Guid so the result is deterministic and reasonable.
int n = 1;
foreach (ILexEntry le in rgHomographs.OrderBy(h => h.HomographNumber).ToList())
foreach (ILexEntry le in rgHomographs
.OrderBy(h => h.HomographNumber)
.ThenBy(h => h.DateCreated)
.ThenBy(h => h.Guid)
.ToList())
{
if (le.HomographNumber != n)
le.HomographNumber = n;
Expand Down
19 changes: 19 additions & 0 deletions src/SIL.LCModel/Infrastructure/Impl/RepositoryAdditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,25 @@ public List<ILexEntry> CollectHomographs(string sForm, IMoMorphType morphType)
return CollectHomographs(sForm, 0, GetHomographs(sForm), morphType);
}

/// <summary>
/// Validate and, if needed, correct homograph numbers for the set <paramref name="entry"/>
/// participates in. Zeros the entry's HomographNumber if form is blank (so callers
/// don't need to special-case that).
/// Caller should create the unit of work.
/// </summary>
/// <returns>true if no change was needed, false if anything was renumbered.</returns>
public bool CorrectHomographNumbers(ILexEntry entry)
{
var form = entry.HomographFormKey;
if (form == Strings.ksQuestions)
{
if (entry.HomographNumber == 0) return true;
entry.HomographNumber = 0;
return false;
}
return LexDb.CorrectHomographNumbers(CollectHomographs(form, entry.PrimaryMorphType));
}

/// <summary>
/// Main method to collect all the homographs of the given form from the given list of entries.
/// Set hvo to 0 to collect absolutely every matching homograph.
Expand Down
9 changes: 9 additions & 0 deletions src/SIL.LCModel/RepositoryInterfaceAdditions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,15 @@ public partial interface ILexEntryRepository
/// </summary>
List<ILexEntry> CollectHomographs(string sForm, IMoMorphType morphType);

/// <summary>
/// Validate and, if needed, correct homograph numbers for the set <paramref name="entry"/>
/// participates in. Zeros the entry's HomographNumber if form is blank (so callers
/// don't need to special-case that).
/// Caller should create the unit of work.
/// </summary>
/// <returns>true if no change was needed, false if anything was renumbered.</returns>
bool CorrectHomographNumbers(ILexEntry entry);

/// <summary>
/// Maps the specified morph type onto a canonical ordering that should be used in comparing two
/// entries to see whether they are homographs.
Expand Down
68 changes: 68 additions & 0 deletions tests/SIL.LCModel.Tests/DomainImpl/LingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,74 @@ public void HomographValidationWorks()
}
}

/// <summary>
/// When a full renumber is needed, ties on HomographNumber are broken by
/// DateCreated (then Guid) so that the outcome is entirely deterministic.
/// </summary>
[Test]
public void CorrectHomographNumbers_FullRenumber_TieBreaksByDateCreated()
{
const string sLexForm = "tieBreakTest";
var e1 = MakeEntry(sLexForm);
var e2 = MakeEntry(sLexForm);
var e3 = MakeEntry(sLexForm);

e1.HomographNumber = 5;
e2.HomographNumber = 5;
e3.HomographNumber = 5;

// Reverse natural creation order so DateCreated differs from insertion order.
var baseTime = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);
e3.DateCreated = baseTime;
e2.DateCreated = baseTime.AddMinutes(1);
e1.DateCreated = baseTime.AddMinutes(2);

var fOk = LexDb.CorrectHomographNumbers(new List<ILexEntry> { e1, e2, e3 });

Assert.IsFalse(fOk, "CorrectHomographNumbers had to renumber homographs");
Assert.AreEqual(1, e3.HomographNumber, "oldest DateCreated wins HN=1");
Assert.AreEqual(2, e2.HomographNumber);
Assert.AreEqual(3, e1.HomographNumber, "newest DateCreated gets HN=3");
}

/// <summary>
/// Algorithm behaviour is covered by HomographValidationWorks.
/// This just exercises the wrapper.
/// </summary>
[Test]
public void CorrectHomographNumbers_RenumbersInvalidSet()
{
const string sLexForm = "repoCorrectHnTest";
var e1 = MakeEntry(sLexForm);
var e2 = MakeEntry(sLexForm);
var e3 = MakeEntry(sLexForm);

e1.HomographNumber = 2;
e2.HomographNumber = 2;
e3.HomographNumber = 0;

var repo = Cache.ServiceLocator.GetInstance<ILexEntryRepository>();
Assert.IsFalse(repo.CorrectHomographNumbers(e1), "Invalid set should be renumbered.");
CollectionAssert.AreEquivalent(new[] { 1, 2, 3 },
new[] { e1.HomographNumber, e2.HomographNumber, e3.HomographNumber });
Assert.IsTrue(repo.CorrectHomographNumbers(e1), "Already-valid set: no change.");
}

/// <summary>
/// Empty-form branch added on top of LexDb.CorrectHomographNumbers.
/// </summary>
[Test]
public void CorrectHomographNumbers_EmptyForm_ForcesZero()
{
var entry = MakeEntry("");
Assert.AreEqual(Strings.ksQuestions, entry.HomographFormKey);
entry.HomographNumber = 7;

var repo = Cache.ServiceLocator.GetInstance<ILexEntryRepository>();
Assert.IsFalse(repo.CorrectHomographNumbers(entry));
Assert.AreEqual(0, entry.HomographNumber);
}

private ILexEntry MakeEntry(string sLexForm)
{
var lme = Cache.ServiceLocator.GetInstance<ILexEntryFactory>().Create();
Expand Down