Skip to content

test: add serde serialization roundtrip tests#140

Merged
EffortlessSteven merged 1 commit into
mainfrom
wave-106/serde-roundtrips
Mar 2, 2026
Merged

test: add serde serialization roundtrip tests#140
EffortlessSteven merged 1 commit into
mainfrom
wave-106/serde-roundtrips

Conversation

@EffortlessSteven

Copy link
Copy Markdown
Member

Adds 51 serde serialization roundtrip tests for JWK shape types across three crates: uselesskey-core-jwk-shape (39 tests), uselesskey-core-jwk-builder (8 tests), and uselesskey-core-jwk (4 tests). Tests cover JSON structure, deterministic serialization, roundtrip via Value, untagged enum serialization, serde rename attributes, malformed input handling, and builder ordering.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Mar 2, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 14 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between a34c9ca and 05ed6a9.

📒 Files selected for processing (3)
  • crates/uselesskey-core-jwk-builder/tests/serde_roundtrip.rs
  • crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs
  • crates/uselesskey-core-jwk/tests/serde_roundtrip.rs

Walkthrough

Three test modules are added across related JWK crates to validate serde serialization and deserialization roundtrips. Tests comprehensively cover JSON structure integrity, deterministic ordering, field naming consistency, and type preservation for multiple JWK variants and the JwksBuilder.

Changes

Cohort / File(s) Summary
JwksBuilder Roundtrip Tests
crates/uselesskey-core-jwk-builder/tests/serde_roundtrip.rs
Tests JwksBuilder output integrity including JSON structure, deterministic key ordering by kid, roundtrip consistency across serialization methods, handling of empty/mixed key types, and public/private type preservation across RSA, EC, OKP, and oct variants.
JWK Shape Roundtrip Tests
crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs
Validates serde behavior for all JWK shape types (RSA, EC, OKP, symmetric) in public/private variants, field renaming (use_ to use), deterministic serialization across Value and String representations, roundtrip integrity, and correct struct field presence validation.
JWK Facade Roundtrip Tests
crates/uselesskey-core-jwk/tests/serde_roundtrip.rs
Tests re-exported JWK types and JwksBuilder facade to ensure serialization parity with underlying shapes; validates specific field values, builder determinism, mixed key types, and AnyJwk wrapping behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #21: Introduced the JWK/JWKS types and JwksBuilder that are directly validated by the comprehensive roundtrip test suite added in this PR.

Poem

🐰 Keys align with perfect care,
JSON shapes that roundtrip fair,
Deterministic, pure, and true,
Serde tests in every hue! 🔐

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'test: add serde serialization roundtrip tests' directly and accurately summarizes the main change—adding serde serialization roundtrip tests across the codebase.
Description check ✅ Passed The description is directly related to the changeset, providing specific detail about the 51 tests added across three crates, test coverage areas, and implementation details.
Docstring Coverage ✅ Passed Docstring coverage is 82.26% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wave-106/serde-roundtrips

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs`:
- Around line 348-361: Replace the single loop-based test function
public_jwk_all_variants_roundtrip_via_value with parameterized rstest cases so
each PublicJwk variant is its own test case: create separate rstest parameters
that supply PublicJwk::Rsa(rsa_public("rsa")), PublicJwk::Ec(ec_public("ec")),
and PublicJwk::Okp(okp_public("okp")) to a test function that performs the same
serde_json to_string/from_str and to_value assertions and uses jwk.kid() in the
assert message; ensure you add the rstest attribute and import so failures are
reported per-variant instead of as one loop.
- Around line 519-556: The test
all_concrete_jwk_types_deterministic_serialization manually builds a Vec of
serialized pairs for each JWK constructor (rsa_public, rsa_private, ec_public,
ec_private, okp_public, okp_private, oct_jwk); refactor it to an
rstest-parameterized test that takes each constructor name/value as a case,
import and use #[rstest] (and the rstest::rstest macro) to supply the 7 inputs,
then inside the body call serde_json::to_string twice for the given constructor
and assert_eq! the results. Keep references to the original helper functions
(rsa_public, rsa_private, ec_public, ec_private, okp_public, okp_private,
oct_jwk) as the sources for test values and remove the manual Vec-based loop.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8a2127 and a34c9ca.

📒 Files selected for processing (3)
  • crates/uselesskey-core-jwk-builder/tests/serde_roundtrip.rs
  • crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs
  • crates/uselesskey-core-jwk/tests/serde_roundtrip.rs

Comment on lines +348 to +361
fn public_jwk_all_variants_roundtrip_via_value() {
let variants: Vec<PublicJwk> = vec![
PublicJwk::Rsa(rsa_public("rsa")),
PublicJwk::Ec(ec_public("ec")),
PublicJwk::Okp(okp_public("okp")),
];

for jwk in &variants {
let json_str = serde_json::to_string(jwk).unwrap();
let parsed: Value = serde_json::from_str(&json_str).unwrap();
let direct = serde_json::to_value(jwk).unwrap();
assert_eq!(parsed, direct, "roundtrip failed for kid={}", jwk.kid());
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Loop-based variant testing works but could use rstest for test isolation.

The loop approach produces a single test that iterates over variants. With rstest, each variant would be a separate test case, providing better failure isolation and clearer CI output. This is optional since the current implementation works correctly and includes meaningful error messages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs` around lines 348 -
361, Replace the single loop-based test function
public_jwk_all_variants_roundtrip_via_value with parameterized rstest cases so
each PublicJwk variant is its own test case: create separate rstest parameters
that supply PublicJwk::Rsa(rsa_public("rsa")), PublicJwk::Ec(ec_public("ec")),
and PublicJwk::Okp(okp_public("okp")) to a test function that performs the same
serde_json to_string/from_str and to_value assertions and uses jwk.kid() in the
assert message; ensure you add the rstest attribute and import so failures are
reported per-variant instead of as one loop.

Comment on lines +519 to +556
#[test]
fn all_concrete_jwk_types_deterministic_serialization() {
// Test each concrete type produces identical output on repeated serialization
let json_pairs: Vec<(String, String)> = vec![
(
serde_json::to_string(&rsa_public("det")).unwrap(),
serde_json::to_string(&rsa_public("det")).unwrap(),
),
(
serde_json::to_string(&rsa_private("det")).unwrap(),
serde_json::to_string(&rsa_private("det")).unwrap(),
),
(
serde_json::to_string(&ec_public("det")).unwrap(),
serde_json::to_string(&ec_public("det")).unwrap(),
),
(
serde_json::to_string(&ec_private("det")).unwrap(),
serde_json::to_string(&ec_private("det")).unwrap(),
),
(
serde_json::to_string(&okp_public("det")).unwrap(),
serde_json::to_string(&okp_public("det")).unwrap(),
),
(
serde_json::to_string(&okp_private("det")).unwrap(),
serde_json::to_string(&okp_private("det")).unwrap(),
),
(
serde_json::to_string(&oct_jwk("det")).unwrap(),
serde_json::to_string(&oct_jwk("det")).unwrap(),
),
];

for (first, second) in &json_pairs {
assert_eq!(first, second, "deterministic serialization failed");
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using rstest for parameterized deterministic serialization tests.

This test creates pairs manually for each JWK type. Per coding guidelines, rstest is recommended for parameterized tests, which would make this more maintainable:

♻️ Suggested refactor using rstest
+use rstest::rstest;
+
+#[rstest]
+#[case::rsa_public(|| serde_json::to_string(&rsa_public("det")).unwrap())]
+#[case::rsa_private(|| serde_json::to_string(&rsa_private("det")).unwrap())]
+#[case::ec_public(|| serde_json::to_string(&ec_public("det")).unwrap())]
+#[case::ec_private(|| serde_json::to_string(&ec_private("det")).unwrap())]
+#[case::okp_public(|| serde_json::to_string(&okp_public("det")).unwrap())]
+#[case::okp_private(|| serde_json::to_string(&okp_private("det")).unwrap())]
+#[case::oct(|| serde_json::to_string(&oct_jwk("det")).unwrap())]
+fn jwk_type_deterministic_serialization<F: Fn() -> String>(#[case] serializer: F) {
+    let first = serializer();
+    let second = serializer();
+    assert_eq!(first, second, "deterministic serialization failed");
+}

As per coding guidelines: "Use rstest for parameterized tests".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/uselesskey-core-jwk-shape/tests/serde_roundtrip.rs` around lines 519 -
556, The test all_concrete_jwk_types_deterministic_serialization manually builds
a Vec of serialized pairs for each JWK constructor (rsa_public, rsa_private,
ec_public, ec_private, okp_public, okp_private, oct_jwk); refactor it to an
rstest-parameterized test that takes each constructor name/value as a case,
import and use #[rstest] (and the rstest::rstest macro) to supply the 7 inputs,
then inside the body call serde_json::to_string twice for the given constructor
and assert_eq! the results. Keep references to the original helper functions
(rsa_public, rsa_private, ec_public, ec_private, okp_public, okp_private,
oct_jwk) as the sources for test values and remove the manual Vec-based loop.

@EffortlessSteven EffortlessSteven force-pushed the wave-106/serde-roundtrips branch 3 times, most recently from c313a10 to 41a1a50 Compare March 2, 2026 17:20
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@EffortlessSteven EffortlessSteven force-pushed the wave-106/serde-roundtrips branch from 41a1a50 to 05ed6a9 Compare March 2, 2026 18:10
@EffortlessSteven EffortlessSteven merged commit 38550d8 into main Mar 2, 2026
3 of 4 checks passed
@EffortlessSteven EffortlessSteven deleted the wave-106/serde-roundtrips branch March 5, 2026 15:13
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.

1 participant