Skip to content

Commit b1f7894

Browse files
committed
Validating snapshot ops for SF revisions
This change harnesses DeltaUsxMapper.ProcessDelta and DeltaUsxMapper.Schemas to determine the validity of a set of ops. Tests forthcoming Theoretically, we now don't need to prevent users from restoring invalid versions, since that wasn't actually the problem. I'm either way on keeping that.
1 parent 4a42ec2 commit b1f7894

File tree

4 files changed

+74
-14
lines changed

4 files changed

+74
-14
lines changed

src/SIL.XForge.Scripture/Services/DeltaUsxMapper.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,23 @@ public XDocument ToUsx(XDocument oldUsxDoc, IEnumerable<ChapterDelta> chapterDel
593593
}
594594
}
595595

596+
/// <summary>
597+
/// Checks if the provided Delta object can be converted to a valid USX document.
598+
/// </summary>
599+
/// <param name="delta">The Delta object to validate.</param>
600+
/// <param name="version">The USX version number to set on the root element. Defaults to 1.0.</param>
601+
public static bool IsDeltaValid(Delta delta, double version = 1)
602+
{
603+
var xNodes = ProcessDelta(delta);
604+
var usxRootElement = new XElement("usx", xNodes);
605+
usxRootElement.SetAttributeValue("version", string.Format("{0:0.0}", version));
606+
var usx = new XDocument(usxRootElement);
607+
var isValid = true;
608+
usx.Validate(Schemas, (_, _) => isValid = false);
609+
610+
return isValid;
611+
}
612+
596613
/// <summary>
597614
/// Make USX from a Delta's ops.
598615
/// </summary>

src/SIL.XForge.Scripture/Services/ParatextService.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,11 +1957,6 @@ DateTime timestamp
19571957
// Ensure that the timestamp is UTC
19581958
timestamp = DateTime.SpecifyKind(timestamp, DateTimeKind.Utc);
19591959

1960-
// Load the Paratext project
1961-
string ptProjectId = projectDoc.Data.ParatextId;
1962-
using ScrText scrText = GetScrText(userSecret, ptProjectId);
1963-
VerseRef verseRef = new VerseRef($"{book} {chapter}:0");
1964-
19651960
TextSnapshot ret;
19661961
string id = TextData.GetTextDocId(sfProjectId, book, chapter);
19671962
Snapshot<TextData> snapshot = await connection.FetchSnapshotAsync<TextData>(id, timestamp);
@@ -1971,9 +1966,14 @@ DateTime timestamp
19711966
// We do not have a snapshot, so retrieve the data from Paratext
19721967
// Note: The following code is not testable due to ParatextData limitations
19731968

1969+
// Load the Paratext project
1970+
string ptProjectId = projectDoc.Data.ParatextId;
1971+
using ScrText latestScrText = GetScrText(userSecret, ptProjectId);
1972+
VerseRef verseRef = new VerseRef($"{book} {chapter}:0");
1973+
19741974
// Retrieve the first revision before or at the timestamp
1975-
VersionedText versionedText = VersioningManager.Get(scrText);
1976-
HgRevisionCollection revisionCollection = HgRevisionCollection.Get(scrText);
1975+
VersionedText versionedText = VersioningManager.Get(latestScrText);
1976+
HgRevisionCollection revisionCollection = HgRevisionCollection.Get(latestScrText);
19771977
DateTimeOffset timeStampOffset = new DateTimeOffset(timestamp, TimeSpan.Zero);
19781978
HgRevision? revision = revisionCollection
19791979
.FilterRevisions(r => r.CommitTimeStamp <= timeStampOffset)
@@ -1989,7 +1989,7 @@ DateTime timestamp
19891989
// Retrieve the USFM for the chapter, and convert to USX, then to deltas
19901990
IGetText version = versionedText.GetVersion(revision.Id);
19911991
string usfm = version.GetText(verseRef, true, false);
1992-
ChapterDelta chapterDelta = GetDeltaFromUsfm(scrText, verseRef.BookNum, usfm);
1992+
ChapterDelta chapterDelta = GetDeltaFromUsfm(latestScrText, verseRef.BookNum, usfm);
19931993
ret = new TextSnapshot
19941994
{
19951995
Id = id,
@@ -2001,14 +2001,13 @@ DateTime timestamp
20012001
else
20022002
{
20032003
// We have the snapshot, but we need to determine if it's valid
2004-
var usfm = scrText.GetText(verseRef.BookNum);
2005-
ChapterDelta chapterDelta = GetDeltaFromUsfm(scrText, verseRef.BookNum, usfm);
2004+
var isValid = DeltaUsxMapper.IsDeltaValid(new Delta(snapshot.Data.Ops), snapshot.Version);
20062005
ret = new TextSnapshot
20072006
{
20082007
Id = snapshot.Id,
20092008
Version = snapshot.Version,
20102009
Data = snapshot.Data,
2011-
IsValid = chapterDelta.IsValid,
2010+
IsValid = isValid,
20122011
};
20132012
}
20142013

test/SIL.XForge.Scripture.Tests/Services/DeltaUsxMapperTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3944,6 +3944,52 @@ Blessed is the man...
39443944
[Test]
39453945
public async Task RoundTrip_Asv() => await RoundTripTestHelper("eng-asv_usfm-partial", "eng-asv");
39463946

3947+
[Test]
3948+
public void IsDeltaValid_Valid_ReturnsTrue()
3949+
{
3950+
var delta = Delta.New().InsertChapter("1").InsertPara("p").InsertText("text", "verse_1_1");
3951+
3952+
bool result = DeltaUsxMapper.IsDeltaValid(delta);
3953+
3954+
Assert.IsTrue(result);
3955+
}
3956+
3957+
[Test]
3958+
public void IsDeltaValid_InvalidPara_ReturnsFalse()
3959+
{
3960+
var delta = Delta
3961+
.New()
3962+
.InsertText("Book title", "imt_1")
3963+
.InsertPara("imt")
3964+
.InsertChapter("1")
3965+
.InsertBlank("bad_1")
3966+
.InsertVerse("1")
3967+
.InsertText("New verse text.", "verse_1_1")
3968+
.InsertPara("bad", true);
3969+
3970+
bool result = DeltaUsxMapper.IsDeltaValid(delta);
3971+
3972+
Assert.IsFalse(result);
3973+
}
3974+
3975+
[Test]
3976+
public void IsDeltaValid_InvalidVerse_ReturnsFalse()
3977+
{
3978+
var delta = Delta
3979+
.New()
3980+
.InsertChapter("1")
3981+
.InsertBlank("p_1")
3982+
.InsertVerse("1", "bad", true)
3983+
.InsertBlank("verse_1_1")
3984+
.InsertVerse("2")
3985+
.InsertBlank("verse_1_2")
3986+
.InsertPara("p");
3987+
3988+
bool result = DeltaUsxMapper.IsDeltaValid(delta);
3989+
3990+
Assert.IsFalse(result);
3991+
}
3992+
39473993
private async Task RoundTripTestHelper(string projectZipFilename, string projectShortName)
39483994
{
39493995
string zipFilePath = Path.Join(GetPathToTestProject(), "SampleData", $"{projectZipFilename}.zip");

test/SIL.XForge.Scripture.Tests/Services/ParatextServiceTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5932,15 +5932,13 @@ public async Task GetSnapshotAsync_FetchesSnapshotFromRealtimeServer()
59325932
ScrText scrText = env.GetScrText(associatedPtUser, ptProjectId);
59335933

59345934
env.MockScrTextCollection.FindById(Arg.Any<string>(), Arg.Any<string>()).Returns(_ => scrText);
5935-
env.MockDeltaUsxMapper.ToChapterDeltas(Arg.Any<XDocument>())
5936-
.Returns([new ChapterDelta(chapter, 1, false, textData)]);
59375935

59385936
// SUT
59395937
var actual = await env.Service.GetSnapshotAsync(userSecret, project.Id, book, chapter, DateTime.UtcNow);
59405938
Assert.AreEqual(textData.Ops.First(), actual.Data.Ops.First());
59415939
Assert.AreEqual(textData.Id, actual.Id);
59425940
Assert.AreEqual(0, actual.Version);
5943-
Assert.AreEqual(false, actual.IsValid);
5941+
Assert.AreEqual(true, actual.IsValid); //snapshot in test repo is valid USFM
59445942
}
59455943

59465944
[Test]

0 commit comments

Comments
 (0)