diff --git a/src/Serval/test/Serval.E2ETests/Serval.E2ETests.csproj b/src/Serval/test/Serval.E2ETests/Serval.E2ETests.csproj index 2c6e50e5..d539003e 100644 --- a/src/Serval/test/Serval.E2ETests/Serval.E2ETests.csproj +++ b/src/Serval/test/Serval.E2ETests/Serval.E2ETests.csproj @@ -18,6 +18,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Serval/test/Serval.E2ETests/ServalUsfmTests.cs b/src/Serval/test/Serval.E2ETests/ServalUsfmTests.cs new file mode 100644 index 00000000..bbdf3a9b --- /dev/null +++ b/src/Serval/test/Serval.E2ETests/ServalUsfmTests.cs @@ -0,0 +1,109 @@ +using SIL.Machine.Corpora; + +namespace Serval.E2ETests; + +[TestFixture] +public class ServalUsfmTests +{ + public static readonly string PretranslationPath = Path.Combine("..", "..", "..", "data", "pretranslations.json"); + public static readonly string ParatextProjectPath = Path.Combine("..", "..", "..", "data", "project"); + + [Test] + [Ignore("This is for manual testing only. Remove this tag to run the test.")] + /* + In order to run this test on specific projects, place the Paratext projects or Paratext project zips in the Corpora/TestData/project/ folder. + If only testing one project, you can instead place the project in the Corpora/TestData/ folder and rename it to "project" + */ + public async Task CreateUsfmFile() + { + async Task GetUsfmAsync(string projectPath) + { + ParatextProjectSettingsParserBase parser; + ZipArchive? projectArchive = null; + try + { + projectArchive = ZipFile.Open(projectPath, ZipArchiveMode.Read); + parser = new ZipParatextProjectSettingsParser(projectArchive); + } + catch (UnauthorizedAccessException) + { + parser = new FileParatextProjectSettingsParser(projectPath); + } + ParatextProjectSettings settings = parser.Parse(); + + // Read text from pretranslations file + using Stream pretranslationStream = File.OpenRead(PretranslationPath); + UpdateUsfmRow[] pretranslations = await JsonSerializer + .DeserializeAsyncEnumerable( + pretranslationStream, + new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase } + ) + .Select(p => new UpdateUsfmRow( + (IReadOnlyList)( + p?.Refs.Select(r => ScriptureRef.Parse(r, settings.Versification).ToRelaxed()).ToArray() ?? [] + ), + p?.Translation ?? "" + )) + .ToArrayAsync(); + List bookIds = []; + ParatextProjectTextUpdaterBase updater; + if (projectArchive == null) + { + bookIds = ( + Directory + .EnumerateFiles(projectPath, $"{settings.FileNamePrefix}*{settings.FileNameSuffix}") + .Select(path => new DirectoryInfo(path).Name) + .Select(filename => + { + string bookId; + if (settings.IsBookFileName(filename, out bookId)) + return bookId; + else + return ""; + }) + .Where(id => id != "") + ).ToList(); + updater = new FileParatextProjectTextUpdater(projectPath); + } + else + { + bookIds = projectArchive + .Entries.Where(e => + e.Name.StartsWith(settings.FileNamePrefix) && e.Name.EndsWith(settings.FileNameSuffix) + ) + .Select(e => + { + string bookId; + if (settings.IsBookFileName(e.Name, out bookId)) + return bookId; + else + return ""; + }) + .Where(id => id != "") + .ToList(); + updater = new ZipParatextProjectTextUpdater(projectArchive); + } + foreach (string bookId in bookIds) + { + string newUsfm = updater.UpdateUsfm( + bookId, + pretranslations, + textBehavior: UpdateUsfmTextBehavior.StripExisting + ); + Assert.That(newUsfm, Is.Not.Null); + } + } + if (!File.Exists(Path.Combine(ParatextProjectPath, "Settings.xml"))) + { + Assert.Multiple(() => + { + foreach (string subdir in Directory.EnumerateFiles(ParatextProjectPath)) + Assert.DoesNotThrowAsync(async () => await GetUsfmAsync(subdir), $"Failed to parse {subdir}"); + }); + } + else + { + await GetUsfmAsync(ParatextProjectPath); + } + } +}