-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fwddata bridge Semantic domains and Parts of speech (#886)
* define parts of speech models in MiniLcm, implement tests and updates for the FwDataBridge pull part of speech helper methods into their own utility class rewrite semantic domain implementation to support them being objects that are referenced, instead of just being a string. prevent json patch changes from having index references, this will avoid conflicts where the index changes due to merges. introduce json patch rewriting to convert patches into specific changes. Rewrite changes to Sense.PartOfSpeechId into SetPartOfSpeechChange. allow creating parts of speech as CRDTs and setup a PoC of pre seeding them. allow creating semantic domains and referencing them in senses, rewrite json patch to change semantic domains of senses. Add tests for creating senses with and without semantic domains, and with and without part of speeches. * remove duplicate field, fix overloaded GetEntries function causing build error due to 2 overloads not requiring parameters. * add WritingSystemTests.cs, and make the project loader fixture a collection fixture so it's shared by all tests in the project. * reduce allocations in ContributeExemplars by ~50% by using spans of chars instead of strings. * use string contains with StringComparison instead of calling ToLowerInvariant on each string. * optimize ws lookup when populating exemplars by using a frozen dictionary, and set the MultiString capacity when converting a LcmMultiString to a MiniLcmMultiString * Populate UI with parts-of-speech * Search improvements * Index dictionary by first grapheme instead of first char * Revert "Index dictionary by first grapheme instead of first char", because first-char sounds like a better way to go (https://sil-lt.slack.com/archives/C806BLR42/p1718797173733449) This reverts commit 614dbd5. * Fix exemplar lookup not always working * Add loading indicators * Improve index character overlay size * Option type cleanup * Add Sandbox to reproduce open bug * Populate semantic domain dropdown (WIP) * Make entry list always fully visible. * Prevent unnecessary change events * Fix type error * Use less peculiar icon * Display search keyboard shortcut * Redesign home page * Resize keys * Fix Part of speech changes not being persisted * Uppercase index exemplars to prevent duplicates * Store selected-entry, selected-index-char and search in URL * Add transition so increased debounce is not so noticeable. * Add save status indicator * Layout and mobile fixes * Cheap fix for semantic domain list being way to big * Format selected semantic domains * gracefully handle null order by text * rework CrdtMultiOptionField to support editing object lists * add parts of speech to CrdtLexboxApi.cs to fix failing tests * add parts of speech and semantic domains to the lf classic api * disable server garbage collection to reduce memory usage. Disable single file until sillsdev/icu-dotnet#201 is merged. * apply some suggested feedback from review. * normalize exemplar to NFD before using it for comparison --------- Co-authored-by: Tim Haasdyk <[email protected]>
- Loading branch information
Showing
85 changed files
with
2,234 additions
and
426 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
backend/FwDataMiniLcmBridge.Tests/Fixtures/ProjectLoaderFixture.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using FwDataMiniLcmBridge.Api; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace FwDataMiniLcmBridge.Tests.Fixtures; | ||
|
||
public class ProjectLoaderFixture : IDisposable | ||
{ | ||
public const string Name = "ProjectLoaderCollection"; | ||
private readonly FwDataFactory _fwDataFactory; | ||
private readonly ServiceProvider _serviceProvider; | ||
|
||
public ProjectLoaderFixture() | ||
{ | ||
//todo make mock of IProjectLoader so we can load from test projects | ||
var provider = new ServiceCollection().AddFwDataBridge().BuildServiceProvider(); | ||
_serviceProvider = provider; | ||
_fwDataFactory = provider.GetRequiredService<FwDataFactory>(); | ||
} | ||
|
||
public FwDataMiniLcmApi CreateApi(string projectName) | ||
{ | ||
return _fwDataFactory.GetFwDataMiniLcmApi(projectName, false); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_serviceProvider.Dispose(); | ||
} | ||
} | ||
|
||
[CollectionDefinition(ProjectLoaderFixture.Name)] | ||
public class ProjectLoaderCollection : ICollectionFixture<ProjectLoaderFixture> | ||
{ | ||
} |
34 changes: 34 additions & 0 deletions
34
backend/FwDataMiniLcmBridge.Tests/FwDataMiniLcmBridge.Tests.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
|
||
<IsPackable>false</IsPackable> | ||
<IsTestProject>true</IsTestProject> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="coverlet.collector" Version="6.0.0"/> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/> | ||
<PackageReference Include="FluentAssertions" Version="6.12.0"/> | ||
<PackageReference Include="xunit" Version="2.5.3"/> | ||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/> | ||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="Xunit"/> | ||
<Using Include="FluentAssertions"/> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\FwDataMiniLcmBridge\FwDataMiniLcmBridge.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Folder Include="TestData\" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using FwDataMiniLcmBridge.Tests.Fixtures; | ||
using MiniLcm; | ||
|
||
namespace FwDataMiniLcmBridge.Tests; | ||
|
||
[Collection(ProjectLoaderFixture.Name)] | ||
public class PartOfSpeechTests(ProjectLoaderFixture fixture) | ||
{ | ||
[Fact] | ||
public async Task GetPartsOfSpeech_ReturnsAllPartsOfSpeech() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var partOfSpeeches = await api.GetPartsOfSpeech().ToArrayAsync(); | ||
partOfSpeeches.Should().AllSatisfy(po => po.Id.Should().NotBe(Guid.Empty)); | ||
} | ||
|
||
[Fact] | ||
public async Task Sense_HasPartOfSpeech() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var entry = await api.GetEntries().FirstAsync(e => e.Senses.Any(s => !string.IsNullOrEmpty(s.PartOfSpeech))); | ||
var sense = entry.Senses.First(s => !string.IsNullOrEmpty(s.PartOfSpeech)); | ||
sense.PartOfSpeech.Should().NotBeNullOrEmpty(); | ||
sense.PartOfSpeechId.Should().NotBeNull(); | ||
} | ||
|
||
[Fact] | ||
public async Task Sense_UpdatesPartOfSpeech() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var entry = await api.GetEntries().FirstAsync(e => e.Senses.Any(s => !string.IsNullOrEmpty(s.PartOfSpeech))); | ||
var sense = entry.Senses.First(s => !string.IsNullOrEmpty(s.PartOfSpeech)); | ||
var newPartOfSpeech = await api.GetPartsOfSpeech().FirstAsync(po => po.Id != sense.PartOfSpeechId); | ||
|
||
var update = api.CreateUpdateBuilder<Sense>() | ||
.Set(s => s.PartOfSpeech, newPartOfSpeech.Name["en"])//this won't actually update the part of speech, but it shouldn't cause an issue either. | ||
.Set(s => s.PartOfSpeechId, newPartOfSpeech.Id) | ||
.Build(); | ||
await api.UpdateSense(entry.Id, sense.Id, update); | ||
|
||
entry = await api.GetEntry(entry.Id); | ||
ArgumentNullException.ThrowIfNull(entry); | ||
var updatedSense = entry.Senses.First(s => s.Id == sense.Id); | ||
updatedSense.PartOfSpeechId.Should().Be(newPartOfSpeech.Id); | ||
updatedSense.PartOfSpeech.Should().NotBe(sense.PartOfSpeech);//the part of speech here is whatever the default is for the project, not english. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
using FwDataMiniLcmBridge.Tests.Fixtures; | ||
using MiniLcm; | ||
|
||
namespace FwDataMiniLcmBridge.Tests; | ||
|
||
[Collection(ProjectLoaderFixture.Name)] | ||
public class SemanticDomainTests(ProjectLoaderFixture fixture) | ||
{ | ||
[Fact] | ||
public async Task GetSemanticDomains_ReturnsAllSemanticDomains() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var semanticDomains = await api.GetSemanticDomains().ToArrayAsync(); | ||
semanticDomains.Should().AllSatisfy(sd => | ||
{ | ||
sd.Id.Should().NotBe(Guid.Empty); | ||
sd.Name.Values.Should().NotBeEmpty(); | ||
sd.Code.Should().NotBeEmpty(); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public async Task Sense_HasSemanticDomains() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var entry = await api.GetEntries().FirstAsync(e => e.Senses.Any(s => s.SemanticDomains.Any())); | ||
var sense = entry.Senses.First(s => s.SemanticDomains.Any()); | ||
sense.SemanticDomains.Should().NotBeEmpty(); | ||
sense.SemanticDomains.Should().AllSatisfy(sd => | ||
{ | ||
sd.Id.Should().NotBe(Guid.Empty); | ||
sd.Name.Values.Should().NotBeEmpty(); | ||
sd.Code.Should().NotBeEmpty(); | ||
}); | ||
} | ||
|
||
[Fact] | ||
public async Task Sense_AddSemanticDomain() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var entry = await api.GetEntries().FirstAsync(e => e.Senses.Any(s => s.SemanticDomains.Any())); | ||
var sense = entry.Senses.First(s => s.SemanticDomains.Any()); | ||
var currentSemanticDomain = sense.SemanticDomains.First(); | ||
var newSemanticDomain = await api.GetSemanticDomains().FirstAsync(sd => sd.Id != currentSemanticDomain.Id); | ||
|
||
var update = api.CreateUpdateBuilder<Sense>() | ||
.Add(s => s.SemanticDomains, newSemanticDomain) | ||
.Build(); | ||
await api.UpdateSense(entry.Id, sense.Id, update); | ||
|
||
entry = await api.GetEntry(entry.Id); | ||
ArgumentNullException.ThrowIfNull(entry); | ||
var updatedSense = entry.Senses.First(s => s.Id == sense.Id); | ||
updatedSense.SemanticDomains.Select(sd => sd.Id).Should().Contain(newSemanticDomain.Id); | ||
} | ||
|
||
[Fact] | ||
public async Task Sense_RemoveSemanticDomain() | ||
{ | ||
var api = fixture.CreateApi("sena-3"); | ||
var entry = await api.GetEntries().FirstAsync(e => e.Senses.Any(s => s.SemanticDomains.Any())); | ||
var sense = entry.Senses.First(s => s.SemanticDomains.Any()); | ||
var domainToRemove = sense.SemanticDomains[0]; | ||
|
||
var update = api.CreateUpdateBuilder<Sense>() | ||
.Remove(s => s.SemanticDomains, 0) | ||
.Build(); | ||
await api.UpdateSense(entry.Id, sense.Id, update); | ||
|
||
entry = await api.GetEntry(entry.Id); | ||
ArgumentNullException.ThrowIfNull(entry); | ||
var updatedSense = entry.Senses.First(s => s.Id == sense.Id); | ||
updatedSense.SemanticDomains.Select(sd => sd.Id).Should().NotContain(domainToRemove.Id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using FwDataMiniLcmBridge.Tests.Fixtures; | ||
|
||
namespace FwDataMiniLcmBridge.Tests; | ||
|
||
[Collection(ProjectLoaderFixture.Name)] | ||
public class WritingSystemTests(ProjectLoaderFixture fixture) | ||
{ | ||
[Fact] | ||
public async Task GetWritingSystems_DoesNotReturnNullOrEmpty() | ||
{ | ||
var writingSystems = await fixture.CreateApi("sena-3").GetWritingSystems(); | ||
writingSystems.Vernacular.Should().NotBeNullOrEmpty(); | ||
writingSystems.Analysis.Should().NotBeNullOrEmpty(); | ||
} | ||
|
||
[Fact] | ||
public async Task GetWritingSystems_ReturnsExemplars() | ||
{ | ||
var writingSystems = await fixture.CreateApi("sena-3").GetWritingSystems(); | ||
writingSystems.Vernacular.Should().Contain(ws => ws.Exemplars.Any()); | ||
} | ||
} |
Oops, something went wrong.