Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate WritingSystemIds on creation #1230

Merged
merged 13 commits into from
Nov 15, 2024
Merged
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
2 changes: 1 addition & 1 deletion backend/FwLite/FwLiteProjectSync.Tests/UpdateDiffTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class UpdateDiffTests
{
private readonly AutoFaker _autoFaker = new(new AutoFakerConfig()
{
Overrides = [new MultiStringOverride()]
Overrides = [new MultiStringOverride(), new WritingSystemIdOverride()]
});

[Fact]
Expand Down
10 changes: 8 additions & 2 deletions backend/FwLite/LcmCrdt.Tests/DataModelSnapshotTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MiniLcm.Tests.AutoFakerHelpers;
using SIL.Harmony.Changes;
using SIL.Harmony.Entities;
using Soenneker.Utils.AutoBogus;
using Soenneker.Utils.AutoBogus.Config;

namespace LcmCrdt.Tests;

public class DataModelSnapshotTests : IAsyncLifetime
{
private static AutoFaker _faker = new AutoFaker(new AutoFakerConfig()
{
Overrides = [new MultiStringOverride(), new WritingSystemIdOverride()]
});

protected readonly AsyncServiceScope _services;
private readonly LcmCrdtDbContext _crdtDbContext;
private CrdtConfig _crdtConfig;
Expand Down Expand Up @@ -76,15 +83,14 @@ public async Task VerifyIObjectWithIdModels()
[Fact]
public void VerifyIObjectWithIdsMatchAdapterGetObjectTypeName()
{
var faker = new AutoFaker();
var jsonSerializerOptions = _crdtConfig.JsonSerializerOptions;
var types = jsonSerializerOptions.GetTypeInfo(typeof(IObjectWithId)).PolymorphismOptions?.DerivedTypes ?? [];
using (new AssertionScope())
{
foreach (var jsonDerivedType in types)
{
var typeDiscriminator = jsonDerivedType.TypeDiscriminator.Should().BeOfType<string>().Subject;
var obj = faker.Generate(jsonDerivedType.DerivedType);
var obj = _faker.Generate(jsonDerivedType.DerivedType);
new MiniLcmCrdtAdapter((IObjectWithId)obj).GetObjectTypeName().Should().Be(typeDiscriminator);
}
}
Expand Down
7 changes: 6 additions & 1 deletion backend/FwLite/LcmCrdt.Tests/EntityCopyMethodTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using SIL.Harmony.Entities;
using LcmCrdt.Objects;
using MiniLcm.Tests.AutoFakerHelpers;
using SIL.Harmony;
using Soenneker.Utils.AutoBogus;
using Soenneker.Utils.AutoBogus.Config;
Expand All @@ -8,7 +9,11 @@ namespace LcmCrdt.Tests;

public class EntityCopyMethodTests
{
private readonly AutoFaker _autoFaker = new(new AutoFakerConfig());
private readonly AutoFaker _autoFaker = new(new AutoFakerConfig()
{
Overrides = [new MultiStringOverride(), new WritingSystemIdOverride()]
});

public static IEnumerable<object[]> GetEntityTypes()
{
var crdtConfig = new CrdtConfig();
Expand Down
22 changes: 0 additions & 22 deletions backend/FwLite/LcmCrdt.Tests/MultiStringOverride.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ public override void Generate(AutoFakerOverrideContext context)
var wordsArray = context.Faker.Random.WordsArray(1, 4);
foreach (var word in wordsArray)
{
var writingSystemId = validWs is not null
? context.Faker.Random.ArrayElement(validWs)
: context.Faker.Random.String(2, 'a', 'z');
var writingSystemId = context.Faker.Random.ArrayElement(validWs ?? WritingSystemCodes.ValidTwoLetterCodes);
target[writingSystemId] = word;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using MiniLcm.Models;
using Soenneker.Utils.AutoBogus.Context;
using Soenneker.Utils.AutoBogus.Override;

namespace MiniLcm.Tests.AutoFakerHelpers;

public class WritingSystemIdOverride: AutoFakerOverride<WritingSystemId>
{
public override bool Preinitialize => false;

public override void Generate(AutoFakerOverrideContext context)
{
var ws = context.Faker.Random.ArrayElement(WritingSystemCodes.ValidTwoLetterCodes);
context.Instance = new WritingSystemId(ws);
}
}
8 changes: 8 additions & 0 deletions backend/FwLite/MiniLcm.Tests/WritingSystemCodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using SIL.WritingSystems;

namespace MiniLcm.Tests;

public static class WritingSystemCodes
{
public static readonly string[] ValidTwoLetterCodes = StandardSubtags.RegisteredLanguages.Select(lang => lang.Code).ToArray();
}
34 changes: 34 additions & 0 deletions backend/FwLite/MiniLcm.Tests/WritingSystemIdTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using MiniLcm.Models;

namespace MiniLcm.Tests;

public class WritingSystemIdTests
{
[Theory]
[InlineData("en")]
[InlineData("th")]
[InlineData("en-Zxxx-x-audio")]
public void ValidWritingSystemId_ShouldNotThrow(string code)
{
var ws = new WritingSystemId(code);
ws.Should().NotBeNull();
}

[Theory]
[InlineData("gx")]
[InlineData("oo")]
[InlineData("eng")] // Three-letter codes not allowed when there's a valid two-letter code
[InlineData("eng-Zxxx-x-audio")]
[InlineData("nonsense")]
public void InvalidWritingSystemId_ShouldThrow(string code)
{
Assert.Throws<ArgumentException>(() => new WritingSystemId(code));
}

[Fact]
public void DefaultWritingSystemId_IsValid()
{
var ws = new WritingSystemId("default");
ws.Should().NotBeNull();
}
}
1 change: 1 addition & 0 deletions backend/FwLite/MiniLcm/MiniLcm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="SIL.WritingSystems" Version="14.2.0-beta*" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="SystemTextJsonPatch" Version="3.2.1" />
</ItemGroup>
Expand Down
18 changes: 17 additions & 1 deletion backend/FwLite/MiniLcm/Models/WritingSystemId.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using SIL.WritingSystems;

namespace MiniLcm.Models;

Expand All @@ -26,11 +27,26 @@ public override void WriteAsPropertyName(Utf8JsonWriter writer, WritingSystemId
}

[JsonConverter(typeof(WritingSystemIdJsonConverter))]
public readonly record struct WritingSystemId(string Code): ISpanFormattable, ISpanParsable<WritingSystemId>
public readonly record struct WritingSystemId: ISpanFormattable, ISpanParsable<WritingSystemId>
{
public string Code { get; init; }

public WritingSystemId(string code)
{
if (code == "default" || IetfLanguageTag.IsValid(code))
{
Code = code;
}
else
{
throw new ArgumentException($"Invalid writing system ID '{code}'", nameof(code));
}
}

public static implicit operator string(WritingSystemId ws) => ws.Code;
public static implicit operator WritingSystemId(string code) => new(code);
public static implicit operator WritingSystemId(ReadOnlySpan<char> code) => new(new string(code));

public override string ToString()
{
return Code;
Expand Down
Loading