Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using FwDataMiniLcmBridge.Api;
using FwDataMiniLcmBridge.LcmUtils;
using FwDataMiniLcmBridge.Tests.Fixtures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MiniLcm.Models;

namespace FwDataMiniLcmBridge.Tests;

public class CanonicalMorphTypeTests : IDisposable
{
private readonly ServiceProvider _serviceProvider;
private readonly FwDataMiniLcmApi _api;
private readonly FwDataProject _project;

public CanonicalMorphTypeTests()
{
var services = new ServiceCollection()
.AddTestFwDataBridge(mockProjectLoader: false)
.PostConfigure<FwDataBridgeConfig>(config =>
config.TemplatesFolder = Path.GetFullPath("Templates"))
.BuildServiceProvider();
_serviceProvider = services;

var config = services.GetRequiredService<IOptions<FwDataBridgeConfig>>();
Directory.CreateDirectory(config.Value.ProjectsFolder);
var projectName = $"canonical-morph-types-test_{Guid.NewGuid()}";
_project = new FwDataProject(projectName, config.Value.ProjectsFolder);
var projectLoader = services.GetRequiredService<IProjectLoader>();
projectLoader.NewProject(_project, "en", "en");

var fwDataFactory = services.GetRequiredService<FwDataFactory>();
_api = fwDataFactory.GetFwDataMiniLcmApi(_project, false);
}

public void Dispose()
{
_api.Dispose();
_serviceProvider.Dispose();
if (Directory.Exists(_project.ProjectFolder))
Directory.Delete(_project.ProjectFolder, true);
}

[Fact]
public async Task CanonicalMorphTypes_MatchNewLangProjMorphTypes()
{
var libLcmMorphTypes = await _api.GetMorphTypes().ToArrayAsync();
libLcmMorphTypes.Should().NotBeEmpty();
CanonicalMorphTypes.All.Values.Should().BeEquivalentTo(libLcmMorphTypes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,9 @@
</ItemGroup>
<ItemGroup>
<Folder Include="TestData\" />
<PackageReference Include="SIL.LCModel" GeneratePathProperty="true" />
<Content Include="$(PkgSIL_LCModel)/contentFiles/Templates/*.*"
Link="Templates/%(Filename)%(Extension)"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public async Task SecondaryOrder_DefaultsToStem(string query, SortField sortFiel
{
var unknownMorphTypeEntryId = Guid.NewGuid();
Entry[] expected = [
new() { Id = unknownMorphTypeEntryId, LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.Unknown }, // SecondaryOrder defaults to Stem = 1
new() { Id = Guid.NewGuid(), LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.BoundStem }, // SecondaryOrder = 2
new() { Id = Guid.NewGuid(), LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.Suffix }, // SecondaryOrder = 6
new() { Id = unknownMorphTypeEntryId, LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.Unknown }, // SecondaryOrder defaults to Stem = 0
new() { Id = Guid.NewGuid(), LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.BoundStem }, // SecondaryOrder = 10
new() { Id = Guid.NewGuid(), LexemeForm = { ["en"] = "aaaa" }, MorphType = MorphTypeKind.Suffix }, // SecondaryOrder = 70
];

var ids = expected.Select(e => e.Id).ToHashSet();
Expand Down
5 changes: 5 additions & 0 deletions backend/FwLite/FwDataMiniLcmBridge/Api/FwDataMiniLcmApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,7 @@ private Entry FromLexEntry(ILexEntry entry)
CitationForm = FromLcmMultiString(entry.CitationForm),
LiteralMeaning = FromLcmMultiString(entry.LiteralMeaning),
MorphType = LcmHelpers.FromLcmMorphType(entry.PrimaryMorphType), // TODO: Decide what to do about entries with *mixed* morph types
HomographNumber = entry.HomographNumber,
Senses = [.. entry.AllSenses.Select(FromLexSense)],
ComplexFormTypes = ToComplexFormTypes(entry),
Components = [.. ToComplexFormComponents(entry)],
Expand Down Expand Up @@ -1001,6 +1002,10 @@ public async Task<Entry> CreateEntry(Entry entry, CreateEntryOptions? options =
UpdateLcmMultiString(lexEntry.CitationForm, entry.CitationForm);
UpdateLcmMultiString(lexEntry.LiteralMeaning, entry.LiteralMeaning);
UpdateLcmMultiString(lexEntry.Comment, entry.Note);
// Only set an explicit homograph number; when 0, let LibLCM's
// side effects (triggered by setting LexemeForm/CitationForm) auto-assign.
if (entry.HomographNumber != 0)
lexEntry.HomographNumber = entry.HomographNumber;

foreach (var sense in entry.Senses)
{
Expand Down
22 changes: 13 additions & 9 deletions backend/FwLite/FwDataMiniLcmBridge/Api/Sorting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ public static IEnumerable<ILexEntry> ApplyHeadwordOrder(this IEnumerable<ILexEnt
return entries
.OrderBy(e => e.LexEntryHeadword(sortWsHandle, applyMorphTokens: false))
.ThenBy(e => e.PrimaryMorphType?.SecondaryOrder ?? stemSecondaryOrder)
// .ThenBy(e => e.HomographNumber)
.ThenBy(e => e.HomographNumber)
.ThenBy(e => e.Id.Guid);
}
else
{
return entries
.OrderByDescending(e => e.LexEntryHeadword(sortWsHandle, applyMorphTokens: false))
.ThenByDescending(e => e.PrimaryMorphType?.SecondaryOrder ?? stemSecondaryOrder)
// .ThenByDescending(e => e.HomographNumber)
.ThenByDescending(e => e.HomographNumber)
.ThenByDescending(e => e.Id.Guid);
}
}
Expand All @@ -33,28 +33,32 @@ public static IEnumerable<ILexEntry> ApplyHeadwordOrder(this IEnumerable<ILexEnt
/// </summary>
public static IEnumerable<ILexEntry> ApplyRoughBestMatchOrder(this IEnumerable<ILexEntry> entries, SortOptions order, int sortWsHandle, int stemSecondaryOrder, string? query = null)
{
var projected = entries.Select(e => (Entry: e, Headword: e.LexEntryHeadword(sortWsHandle, applyMorphTokens: false)));
var projected = entries.Select(e => (
Entry: e,
Headword: e.LexEntryHeadword(sortWsHandle, applyMorphTokens: false),
HeadwordWithTokens: e.LexEntryHeadword(sortWsHandle, applyMorphTokens: true)
));
if (order.Ascending)
{
return projected
.OrderByDescending(x => !string.IsNullOrEmpty(query) && (x.Headword?.StartsWithDiacriticMatch(query!) ?? false))
.ThenByDescending(x => !string.IsNullOrEmpty(query) && (x.Headword?.ContainsDiacriticMatch(query!) ?? false))
.OrderByDescending(x => !string.IsNullOrEmpty(query) && (x.HeadwordWithTokens?.StartsWithDiacriticMatch(query!) ?? false))
.ThenByDescending(x => !string.IsNullOrEmpty(query) && (x.HeadwordWithTokens?.ContainsDiacriticMatch(query!) ?? false))
.ThenBy(x => x.Headword?.Length ?? 0)
.ThenBy(x => x.Headword)
.ThenBy(x => x.Entry.PrimaryMorphType?.SecondaryOrder ?? stemSecondaryOrder)
// .ThenBy(x => x.Entry.HomographNumber)
.ThenBy(x => x.Entry.HomographNumber)
.ThenBy(x => x.Entry.Id.Guid)
.Select(x => x.Entry);
}
else
{
return projected
.OrderBy(x => !string.IsNullOrEmpty(query) && (x.Headword?.StartsWithDiacriticMatch(query!) ?? false))
.ThenBy(x => !string.IsNullOrEmpty(query) && (x.Headword?.ContainsDiacriticMatch(query!) ?? false))
.OrderBy(x => !string.IsNullOrEmpty(query) && (x.HeadwordWithTokens?.StartsWithDiacriticMatch(query!) ?? false))
.ThenBy(x => !string.IsNullOrEmpty(query) && (x.HeadwordWithTokens?.ContainsDiacriticMatch(query!) ?? false))
.ThenByDescending(x => x.Headword?.Length ?? 0)
.ThenByDescending(x => x.Headword)
.ThenByDescending(x => x.Entry.PrimaryMorphType?.SecondaryOrder ?? stemSecondaryOrder)
// .ThenByDescending(x => x.Entry.HomographNumber)
.ThenByDescending(x => x.Entry.HomographNumber)
.ThenByDescending(x => x.Entry.Id.Guid)
.Select(x => x.Entry);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public override RichMultiString Note
get => new UpdateRichMultiStringProxy(_lcmEntry.Comment, _lexboxLcmApi);
set => throw new NotImplementedException();
}

public override int HomographNumber
{
get => _lcmEntry.HomographNumber;
set => _lcmEntry.HomographNumber = value;
}
}

public class UpdateMultiStringProxy(ITsMultiString multiString, FwDataMiniLcmApi lexboxLcmApi) : MultiString
Expand Down
25 changes: 17 additions & 8 deletions backend/FwLite/FwLiteProjectSync.Tests/EntrySyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ public async Task CanSyncNewEntryReferencedByExistingEntry()
var actualNewEntry = await Api.GetEntry(newEntry.Id);
actualNewEntry.Should().BeEquivalentTo(newEntry, options => options
.Excluding(e => e.ComplexFormTypes) // LibLcm automatically creates a complex form type. Should we?
.Excluding(e => e.HomographNumber) // auto-assigned/updated by API
.For(e => e.Components).Exclude(c => c.Id)
.For(e => e.Components).Exclude(c => c.Order));
}
Expand Down Expand Up @@ -486,14 +487,18 @@ public async Task SyncWithoutComplexFormsAndComponents_CorrectlySyncsUpdatedEntr

// assert
var actualComponent = await Api.GetEntry(componentAfter.Id);
actualComponent.Should().BeEquivalentTo(componentAfter,
options => options.Excluding(e => e.ComplexForms));
actualComponent.Should().BeEquivalentTo(componentAfter, options => options
.Excluding(e => e.ComplexForms)
.Excluding(e => e.HomographNumber) // auto-assigned/updated by API
);
actualComponent.ComplexForms.Should().BeEmpty();

var actualComplexForm = await Api.GetEntry(complexForm.Id);
addedComplexForm.Should().BeEquivalentTo(actualComplexForm);
actualComplexForm.Should().BeEquivalentTo(complexForm,
options => options.Excluding(e => e.Components));
actualComplexForm.Should().BeEquivalentTo(complexForm, options => options
.Excluding(e => e.Components)
.Excluding(e => e.HomographNumber) // auto-assigned/updated by API
);
actualComplexForm.Components.Should().BeEmpty();
}

Expand Down Expand Up @@ -525,14 +530,18 @@ public async Task SyncWithoutComplexFormsAndComponents_CorrectlySyncsAddedEntrie
// assert
var actualComponent = await Api.GetEntry(component.Id);
addedComponent.Should().BeEquivalentTo(actualComponent);
actualComponent.Should().BeEquivalentTo(component,
options => options.Excluding(e => e.ComplexForms));
actualComponent.Should().BeEquivalentTo(component, options => options
.Excluding(e => e.ComplexForms)
.Excluding(e => e.HomographNumber) // auto-assigned/updated by API
);
actualComponent.ComplexForms.Should().BeEmpty();

var actualComplexForm = await Api.GetEntry(complexForm.Id);
addedComplexForm.Should().BeEquivalentTo(actualComplexForm);
actualComplexForm.Should().BeEquivalentTo(complexForm,
options => options.Excluding(e => e.Components));
actualComplexForm.Should().BeEquivalentTo(complexForm, options => options
.Excluding(e => e.Components)
.Excluding(e => e.HomographNumber) // auto-assigned/updated by API
);
actualComplexForm.Components.Should().BeEmpty();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using FluentAssertions.Extensibility;
using FwLiteProjectSync.Tests;

Expand All @@ -7,6 +8,12 @@ namespace FwLiteProjectSync.Tests;

public static class FluentAssertGlobalConfig
{
[ModuleInitializer]
internal static void InitVerify()
{
VerifierSettings.OmitContentFromException();
}

public static void Initialize()
{
MiniLcm.Tests.FluentAssertGlobalConfig.Initialize();
Expand Down
14 changes: 1 addition & 13 deletions backend/FwLite/FwLiteProjectSync.Tests/Import/ResumableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,7 @@ public async Task ImportProject_IsResumable_AcrossRandomFailures()
}).ToList();
var expectedPartsOfSpeech = Enumerable.Range(1, 10)
.Select(i => new PartOfSpeech { Id = Guid.NewGuid(), Name = { ["en"] = $"pos{i}" } }).ToList();
var expectedMorphTypes = Enum.GetValues<MorphTypeKind>()
.Select(typ => new MorphType()
{
Id = Guid.NewGuid(),
Name = new() { ["en"] = $"Test Morph Type {(int)typ} {typ}" },
Abbreviation = new() { ["en"] = $"Tst MrphTyp{(int)typ}" },
Description = new() { { "en", new RichString($"test desc for {typ}") } },
Prefix = null,
Postfix = null,
Kind = typ,
SecondaryOrder = 0
}).ToList();
var expectedMorphTypes = CanonicalMorphTypes.All.Values;

var mockFrom = new Mock<IMiniLcmApi>();
IMiniLcmApi mockTo = new UnreliableApi(
Expand Down Expand Up @@ -132,7 +121,6 @@ public async Task ImportProject_IsResumable_AcrossRandomFailures()
createdEntries.Select(e => e.LexemeForm["en"]).Should().BeEquivalentTo(expectedEntries.Select(e => e.LexemeForm["en"]));
createdMorphTypes.Select(e => e.Name["en"]).Should().BeEquivalentTo(expectedMorphTypes.Select(e => e.Name["en"]));
createdMorphTypes.Select(e => e.Kind).Should().BeEquivalentTo(expectedMorphTypes.Select(e => e.Kind));

}


Expand Down
Loading
Loading