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

Add subscriptions to the check aggregator to enable multiple webviews #1319

Merged
merged 1 commit into from
Nov 22, 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
36 changes: 26 additions & 10 deletions c-sharp-tests/Checks/CheckRunResultTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ namespace TestParanextDataProvider.Checks;

public class CheckRunResultTests
{
[TestCase("checkId", "projectId", "message", "GEN 1:1", 1, "GEN 1:2", 5, true)]
[TestCase("ABC", "projectId", "message", "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "ABC", "message", "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "projectId", "ABC", "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "projectId", "message", "GEN 1:2", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "projectId", "message", "GEN 1:1", 2, "GEN 1:2", 5, false)]
[TestCase("checkId", "projectId", "message", "GEN 1:1", 1, "GEN 1:3", 5, false)]
[TestCase("checkId", "projectId", "message", "GEN 1:1", 1, "GEN 1:2", 7, false)]
[TestCase("checkId", "resType", "projectId", "msg", false, "GEN 1:1", 1, "GEN 1:2", 5, true)]
[TestCase("ABC", "resType", "projectId", "msg", false, "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "ABC", "projectId", "msg", false, "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "ABC", "msg", false, "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "projectId", "ABC", false, "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "projectId", "msg", true, "GEN 1:1", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "projectId", "msg", false, "GEN 1:2", 1, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "projectId", "msg", false, "GEN 1:1", 2, "GEN 1:2", 5, false)]
[TestCase("checkId", "resType", "projectId", "msg", false, "GEN 1:1", 1, "GEN 1:3", 5, false)]
[TestCase("checkId", "resType", "projectId", "msg", false, "GEN 1:1", 1, "GEN 1:2", 7, false)]
public void Equality_Objects_ComparedByValue(
string checkId2,
string checkResultType2,
string projectId2,
string message2,
bool isDenied2,
string verseRefStart2,
int offsetStart2,
string verseRefEnd2,
Expand All @@ -28,13 +32,25 @@ bool expectedResult
CheckLocation start1 = new(vrefStart1, 1);
VerseRef vrefEnd1 = new("GEN 1:2");
CheckLocation end1 = new(vrefEnd1, 5);
CheckRunResult checkRunResult1 = new("checkId", "projectId", "message", "", start1, end1);
CheckRunResult checkRunResult1 =
new("checkId", "resType", "projectId", "msg", "", false, vrefStart1, start1, end1);

VerseRef vrefStart2 = new(verseRefStart2);
CheckLocation start2 = new(vrefStart2, offsetStart2);
VerseRef vrefEnd2 = new(verseRefEnd2);
CheckLocation end2 = new(vrefEnd2, offsetEnd2);
CheckRunResult checkRunResult2 = new(checkId2, projectId2, message2, "", start2, end2);
CheckRunResult checkRunResult2 =
new(
checkId2,
checkResultType2,
projectId2,
message2,
"",
isDenied2,
vrefStart2,
start2,
end2
);

Assert.That(checkRunResult1 == checkRunResult2, Is.EqualTo(expectedResult));
Assert.That(checkRunResult1.Equals(checkRunResult2), Is.EqualTo(expectedResult));
Expand Down
97 changes: 73 additions & 24 deletions c-sharp/Checks/CheckResultsRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ public void RecordError(
CheckRunResults.Add(
new CheckRunResult(
checkId,
messageId.InternalValue,
projectId,
message,
// ParatextData adds a space at the end sometimes that isn't in the text
token.Text.TrimEnd(),
false,
token.VerseRef,
// Actual offsets will be calculated below after results have been filtered
new CheckLocation(token.VerseRef, offset),
new CheckLocation(token.VerseRef, 0)
Expand All @@ -55,10 +58,13 @@ public void RecordError(
CheckRunResults.Add(
new CheckRunResult(
checkId,
messageId.InternalValue,
projectId,
message,
// ParatextData adds a space at the end sometimes that isn't in the text
text.TrimEnd(),
false,
vref,
// Actual offsets will be calculated below after results have been filtered
new CheckLocation(vref, selectionStart),
new CheckLocation(vref, 0)
Expand Down Expand Up @@ -87,42 +93,85 @@ public List<CheckRunResult> TrimResultsFromBook(int bookNum)
}

/// <summary>
/// Remove all results that are not within the given range
/// After a check has finished running, filter and complete filling in data on the results found.
/// This will:<br/>
/// 1. Remove all results that are not within the given ranges<br/>
/// 2. Lookup whether each check result was previously denied<br/>
/// 3. Calculate actual offsets for each result
/// </summary>
public void FilterResults(CheckInputRange range)
public void PostProcessResults(
CheckInputRange[]? ranges,
ErrorMessageDenials? denials,
UsfmBookIndexer? indexer
)
{
for (int i = CheckRunResults.Count - 1; i >= 0; i--)
{
var result = CheckRunResults[i];
var verseRef = result.Start.VerseRef;
if (!range.IsWithinRange(result.ProjectId, verseRef.BookNum, verseRef.ChapterNum))
CheckRunResults.RemoveAt(i);
}
}

/// <summary>
/// Given an indexed view of USFM text, determine the actual offsets to include for each result
/// </summary>
public void CalculateActualOffsets(UsfmBookIndexer indexer)
{
foreach (var result in CheckRunResults)
{
var verseIndex = indexer.GetIndex(result.Start.VerseRef);
if (!verseIndex.HasValue)
// Filter by ranges first to throw out whatever we can
if (ranges != null)
{
result.Start.Offset = 0;
continue;
var vref = result.Start.VerseRef;
bool isWithinAnyRange = false;
foreach (var range in ranges)
{
if (range.IsWithinRange(result.ProjectId, vref.BookNum, vref.ChapterNum))
{
isWithinAnyRange = true;
break;
}
}
if (!isWithinAnyRange)
{
CheckRunResults.RemoveAt(i);
continue;
}
}

var textIndex = indexer.Usfm.IndexOf(result.Text, verseIndex.Value);
if (textIndex < 0)
// Lookup whether a check was previously denied
if (denials != null)
{
result.Start.Offset = 0;
continue;
var isDenied = denials.IsDenied(
new Enum<MessageId>(result.CheckResultType),
result.VerseRef,
result.MessageFormatString,
result.Text
);
if (isDenied != result.IsDenied)
CheckRunResults[i] = new CheckRunResult(
result.CheckId,
result.CheckResultType,
result.ProjectId,
result.MessageFormatString,
result.Text,
isDenied,
result.VerseRef,
result.Start,
result.End
);
}

result.Start.Offset += textIndex - verseIndex.Value;
result.End.Offset = result.Start.Offset + result.Text.Length;
// Calculate actual offsets
if (indexer != null)
{
var verseIndex = indexer.GetIndex(result.Start.VerseRef);
if (!verseIndex.HasValue)
{
result.Start.Offset = 0;
continue;
}

var textIndex = indexer.Usfm.IndexOf(result.Text, verseIndex.Value);
if (textIndex < 0)
{
result.Start.Offset = 0;
continue;
}

result.Start.Offset += textIndex - verseIndex.Value;
result.End.Offset = result.Start.Offset + result.Text.Length;
}
}
}
}
59 changes: 26 additions & 33 deletions c-sharp/Checks/CheckRunResult.cs
Original file line number Diff line number Diff line change
@@ -1,59 +1,52 @@
using System.Text.Json.Serialization;
using SIL.Scripture;

namespace Paranext.DataProvider.Checks;

/// <summary>
/// Represents a single error/issue flagged by a check in a given project. This class must
/// serialize/deserialize to the CheckRunResult type defined in TypeScript.
/// </summary>
public sealed class CheckRunResult(
string checkId,
string projectId,
string messageFormatString,
string text,
CheckLocation start,
CheckLocation end
public sealed record CheckRunResult(
string CheckId,
string CheckResultType,
string ProjectId,
string MessageFormatString,
[property: JsonIgnore] string Text,
bool IsDenied,
VerseRef VerseRef,
CheckLocation Start,
CheckLocation End
) : IEquatable<CheckRunResult>
{
public string CheckId { get; } = checkId;
public string ProjectId { get; } = projectId;
public string MessageFormatString { get; } = messageFormatString;

[JsonIgnore]
public string Text { get; } = text;
public CheckLocation Start { get; } = start;
public CheckLocation End { get; } = end;

public override bool Equals(object? obj)
{
return obj is CheckRunResult checkRunResult && Equals(checkRunResult);
}

public bool Equals(CheckRunResult? other)
{
if (ReferenceEquals(other, null))
if (other is null)
return false;

return CheckId == other.CheckId
&& CheckResultType == other.CheckResultType
&& ProjectId == other.ProjectId
&& MessageFormatString == other.MessageFormatString
&& Text == other.Text
&& IsDenied == other.IsDenied
&& VerseRef.ToStringWithVersification() == other.VerseRef.ToStringWithVersification()
&& Start == other.Start
&& End == other.End;
}

public static bool operator ==(CheckRunResult a, CheckRunResult b)
{
return a.Equals(b);
}

public static bool operator !=(CheckRunResult a, CheckRunResult b)
{
return !(a == b);
}

public override int GetHashCode()
{
return HashCode.Combine(CheckId, ProjectId, MessageFormatString, Text, Start, End);
int hash = HashCode.Combine(
CheckId,
CheckResultType,
ProjectId,
MessageFormatString,
Text,
IsDenied,
VerseRef,
Start
);
return HashCode.Combine(hash, End);
}
}
Loading
Loading