diff --git a/se5/ArteCheck.Tests/DurationToleranceTests.cs b/se5/ArteCheck.Tests/DurationToleranceTests.cs new file mode 100644 index 00000000..b01523ec --- /dev/null +++ b/se5/ArteCheck.Tests/DurationToleranceTests.cs @@ -0,0 +1,31 @@ +using SubtitleEdit.Plugins.ArteCheck; +using SubtitleEdit.Plugins.Shared; + +namespace ArteCheck.Tests; + +/// 25 fps, 25-frame minimum, 15% tolerance: 21.25 frames is shown as 21, so 21 frames is accepted. +public class DurationToleranceTests +{ + private const double Hour10 = 10 * 3_600_000.0; + + private static List Analyze(int frames) => ArteChecker.Analyze( + new[] { new PluginParagraph { StartMs = Hour10, EndMs = Hour10 + frames * ArteChecker.FrameMs, Text = "Hi", MarginV = "22" } }, + null, + new ArteOptions { EnabledChecks = new() { ArteCheckType.DisplayDuration } }); + + [Theory] + [InlineData(20, true)] + [InlineData(21, false)] + [InlineData(22, false)] + public void ToleratedMinimum_IsRoundedToWholeFrames(int frames, bool reported) + { + Assert.Equal(reported, Analyze(frames).Any(f => f.Kind == ArteFixKind.DisplayDuration)); + } + + [Fact] + public void ToleratedMinimum_MessageShowsTheLimitTheCheckUses() + { + var fix = Assert.Single(Analyze(20), f => f.Kind == ArteFixKind.DisplayDuration); + Assert.Contains("tolerated minimum of 0 s 21 fr", fix.Reason); + } +} diff --git a/se5/ArteCheck/ArteChecker.cs b/se5/ArteCheck/ArteChecker.cs index d2a02caa..4cf4f73d 100644 --- a/se5/ArteCheck/ArteChecker.cs +++ b/se5/ArteCheck/ArteChecker.cs @@ -281,10 +281,15 @@ private double RequiredDurationMs(string text) return Math.Max(_options.MinimumDurationMs, reading); } + /// + /// The shortest duration accepted, on whole frames - the limit the message shows (FormatDuration + /// rounds to frames) must be the one the check uses: 25 frames - 15% = 21.25 shows as 21 frames, + /// so 21 frames passes and 20 is reported (same as Triathlon-rally's web checker). + /// private double AcceptedMinimumDurationMs(string text) => _options.AcceptShortDurations ? _options.ShortMinimumFrames * FrameMs - : RequiredDurationMs(text) * Math.Max(0, 1.0 - _options.ReadingDurationTolerancePercent / 100.0); + : RoundToFrame(RequiredDurationMs(text) * Math.Max(0, 1.0 - _options.ReadingDurationTolerancePercent / 100.0)); private void AnalyzeDisplayDurations(List subtitle) {