Skip to content

test(strconv): add QuickCheck property tests - #4035

Merged
bobzhang merged 7 commits into
mainfrom
agent/quickcheck-strconv
Aug 15, 2026
Merged

test(strconv): add QuickCheck property tests#4035
bobzhang merged 7 commits into
mainfrom
agent/quickcheck-strconv

Conversation

@bobzhang

Copy link
Copy Markdown
Contributor

Adds strconv/quickcheck_test.mbt with specification-quality property tests for string↔number conversion, following the pattern of hashmap/quickcheck_test.mbt.

Properties covered

  • Shortest round-trip exactness (the killer property): parse_double(d.to_string()) is bitwise equal to d for doubles built from arbitrary 64-bit patterns — covering subnormals, extreme exponents and infinities that the size-bounded built-in Arbitrary instances never reach — plus a second run over uniform doubles in [0, 1] to exercise the fast path densely. NaN is excluded via filter; negative zero gets a documented exemption (see below).
  • Full-range integer round-trips: parse_int64 / parse_uint64 invert to_string over the whole 64-bit range (values assembled from arbitrary bytes), parse_int / parse_uint over the 32-bit range, with and without explicit base=10, and with an explicit leading +.
  • Parser agreement / correct rounding: on the same decimal string, parse_double agrees exactly with Int::to_double, and with Int64/UInt64::to_double at 19–20 significant digits, where both sides must round to nearest identically (exercises the slow path).
  • Radix round-trip: to_string(radix=b) followed by parse_*(base=b) is the identity for every base 2..=36, signed and unsigned.
  • Underscore transparency: an underscore inserted between any two digits never changes the value, for parse_uint64 and parse_double.
  • Rejection of decoration: any stray non-numeric character — including whitespace — prepended or appended makes parse_int and parse_double fail.
  • Small-grammar fuzz: structured [-]digits[.digits][e[-]digits] strings never panic; they either parse to a value whose own rendering reparses to the same bits (printing fixed point), or raise a range error, which the property only permits for genuinely huge exponents (underflow must flush to zero silently).

Counts are bumped to 300–500 per property; all pass on wasm-gc, wasm, js, and native.

Note: negative zero

parse_double("-0") correctly returns -0.0, but Double::to_string follows the ECMAScript number-to-string algorithm on every backend (ryu_to_string returns "0" for val == 0.0, which matches -0.0), so the sign bit cannot survive a trip through the string. The round-trip and fixed-point properties therefore carve out exactly this case (and require the reparse to yield exactly +0.0), rather than weakening the bitwise requirement anywhere else. No bugs were found in strconv itself.

strconv/moon.pkg gains a test-only import of moonbitlang/core/quickcheck; no .mbti changes.

🤖 Generated with Claude Code

Property tests for string<->number conversion:

- parse_double bitwise-inverts Double::to_string for doubles built from
  arbitrary 64-bit patterns (subnormals, extreme exponents, infinities),
  and for uniform doubles in [0, 1]. Negative zero is exempted from the
  bitwise requirement because the ECMAScript-style to_string renders it
  as "0" on every backend.
- Full-range 64-bit and 32-bit integer round-trips through decimal
  strings, plus agreement between the integer parsers and parse_double /
  to_double on the same string (correct rounding at 19-20 digits).
- Radix round-trip in every base 2..=36 for Int64 and UInt64.
- Underscores between digits never change the parsed value.
- A stray non-numeric character (including whitespace) is always
  rejected, prepended or appended.
- Structured [-]digits[.digits][e[-]digits] strings never panic: they
  parse to a value whose own rendering reparses to the same bits, or
  fail with a range error only for genuinely huge exponents.

Integer inputs are assembled from arbitrary bytes because the built-in
Arbitrary instances are size-bounded and never reach the interesting
regions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 14, 2026 07:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds specification-style QuickCheck property tests to the strconv package, aiming to validate correctness and rounding behavior of string↔number conversions across wide and adversarial input spaces (including full-range integer values, arbitrary double bit patterns, radix parsing, underscores, and invalid decoration).

Changes:

  • Added strconv/quickcheck_test.mbt with multiple property-based tests for parse_double, integer parsers, radix parsing, underscore handling, and decoration rejection.
  • Added a test-only dependency on moonbitlang/core/quickcheck in strconv/moon.pkg.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
strconv/quickcheck_test.mbt Introduces QuickCheck properties covering round-trips, parser agreement, radix behavior, underscore transparency, invalid decoration rejection, and structured fuzzing.
strconv/moon.pkg Adds quickcheck as a test-only import to enable the new property tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +244 to +247
}
}
Err(_) => with_exp && exp > 250
}
Comment on lines +256 to +258
test "quickcheck: parse_bool inverts to_string" {
@quickcheck.check((b : Bool) => @strconv.parse_bool(b.to_string()) == b)
}
@coveralls

coveralls commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 6036

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage remained the same at 90.29%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 17642
Covered Lines: 15929
Line Coverage: 90.29%
Coverage Strength: 134676.99 hits per line

💛 - Coveralls

@bobzhang
bobzhang enabled auto-merge (squash) August 14, 2026 07:49
@bobzhang
bobzhang merged commit 9f4ff36 into main Aug 15, 2026
11 checks passed
@bobzhang
bobzhang deleted the agent/quickcheck-strconv branch August 15, 2026 01:00
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.

3 participants