Skip to content

Reject a sub-tick --for and report an overflowing one as too long [patch] - #59

Merged
matt-edmondson merged 2 commits into
mainfrom
fix/57-duration-edges
Nov 4, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
fix/57-duration-edges

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #57

What was wrong

DurationParser.TryParseAnyLength checked totalSeconds <= 0 and > TimeSpan.MaxValue.TotalSeconds on the double, before converting it:

  1. --for 0.00000001s passed the positive check, then TimeSpan.FromSeconds rounded it to TimeSpan.Zero. The tool started and stopped at the same moment, and the tray timer got a zero interval.
  2. --for 20000000d returned false, so CommandLineParser.ReadDuration reported it as "not a duration" instead of the "too long" message that 30d gets.

Change

  • The converted TimeSpan must be at least one tick, so a sub-tick value is rejected as not a duration.
  • A value that parses but is too large for TimeSpan comes back as TimeSpan.MaxValue. The existing > MaxDuration checks in TryParse and ReadDuration then reject it as too long. The public TryParse contract is unchanged.

Tests

  • DurationParserTests: 0.00000001s / 0.00000004s are invalid. 20000000d and a 68-digit hour count are too long for TryParse and come back as TimeSpan.MaxValue from TryParseAnyLength.
  • CommandLineParserTests: --for 0.00000001s gives "is not a duration", and --for 20000000d gives "--for can be at most 24 days".
  • 8 of the new cases fail on main and pass with the fix. Full suite: 170 passed, 1 skipped, 0 failed.

Generated by Claude Code

…tch]

TryParseAnyLength checked that the duration was positive on the double,
before TimeSpan.FromSeconds rounded "0.00000001s" down to zero, so the tool
started and stopped at once. It also returned false for a value past
TimeSpan.MaxValue, so "--for 20000000d" was reported as "not a duration"
rather than "too long". Check the converted TimeSpan for at least one
tick, and return TimeSpan.MaxValue for a value too long to hold so the
caller's upper bound reports it.

Fixes #57

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW3e2AZDcKPKkvjAga2
TimeSpan.FromSeconds does not throw for any value below the
TimeSpan.MaxValue.TotalSeconds guard that precedes it (it does not throw
at the bound itself either), so the catch was dead code and left the new
lines short of the coverage gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017vfJW3e2AZDcKPKkvjAga2
@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit f9aab31 into main Nov 4, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--for edge values: "0.00000001s" is accepted as a zero duration (stops at once), and "20000000d" is reported as "not a duration" instead of "too long"

2 participants