< Summary

Line coverage
100%
Covered lines: 10
Uncovered lines: 0
Coverable lines: 10
Total lines: 105
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: RetryAfterPattern()100%11100%
File 2: .ctor(...)100%11100%
File 2: get_RetryAfter()100%11100%
File 2: ParseRetryAfterFromText(...)100%44100%

File(s)

/_/src/NexusLabs.Needlr.Copilot/obj/Release/net10.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs

File '/_/src/NexusLabs.Needlr.Copilot/obj/Release/net10.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs' does not exist (any more).

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Copilot/CopilotRateLimitException.cs

#LineLine coverage
 1using System.Globalization;
 2using System.Text.RegularExpressions;
 3
 4namespace NexusLabs.Needlr.Copilot;
 5
 6/// <summary>
 7/// Thrown when a Copilot web search request is rejected due to rate limiting.
 8/// This can occur either via an HTTP 429 response after retry exhaustion or
 9/// when the MCP tool returns a rate-limit error message as its content.
 10/// </summary>
 11/// <remarks>
 12/// Callers should catch this exception to implement fallback behavior
 13/// (e.g., trying an alternative search provider or waiting before retrying).
 14/// <see cref="RetryAfter"/> provides a hint for how long to wait, when
 15/// available from the response.
 16/// </remarks>
 17public sealed partial class CopilotRateLimitException : Exception
 18{
 19    /// <summary>
 20    /// Creates a new <see cref="CopilotRateLimitException"/> with the given
 21    /// message, optional retry delay, and optional inner exception.
 22    /// </summary>
 23    /// <param name="message">A description of the rate-limit condition.</param>
 24    /// <param name="retryAfter">
 25    /// How long the caller should wait before retrying, if known from the
 26    /// HTTP <c>Retry-After</c> header or the error message text.
 27    /// </param>
 28    /// <param name="innerException">The exception that caused this failure, if any.</param>
 29    public CopilotRateLimitException(
 30        string message,
 31        TimeSpan? retryAfter = null,
 32        Exception? innerException = null)
 633        : base(message, innerException)
 34    {
 635        RetryAfter = retryAfter;
 636    }
 37
 38    /// <summary>
 39    /// The suggested wait duration before retrying, parsed from the HTTP
 40    /// <c>Retry-After</c> header or the error message text. <c>null</c> when
 41    /// no retry hint was provided.
 42    /// </summary>
 343    public TimeSpan? RetryAfter { get; }
 44
 45    /// <summary>
 46    /// Attempts to parse a "Try again in N seconds" hint from the given text.
 47    /// </summary>
 48    internal static TimeSpan? ParseRetryAfterFromText(string text)
 49    {
 550        var match = RetryAfterPattern().Match(text);
 551        if (match.Success &&
 552            int.TryParse(match.Groups[1].Value, CultureInfo.InvariantCulture, out var seconds))
 53        {
 254            return TimeSpan.FromSeconds(seconds);
 55        }
 56
 357        return null;
 58    }
 59
 60    [GeneratedRegex(@"Try again in (\d+) seconds?", RegexOptions.IgnoreCase)]
 61    private static partial Regex RetryAfterPattern();
 62}