diff --git a/PLAN.md b/PLAN.md index 5577993..9179151 100644 --- a/PLAN.md +++ b/PLAN.md @@ -21,7 +21,7 @@ - [ ] **State:** In progress — the package-native capped xtask entry point is reachable, rejects unknown packages, propagates mutest failure, and mutation-tests `hemx-core`, `hemx-js`, and the full `hemx-test` package cleanly; full package closure remains. - **User value:** maintainers can run one bounded repository command and trust that meaningful Rust logic across every mutation-applicable library is either killed or explicitly justified. - **Build:** add a capped `hemx-xtask` mutation command that invokes `/opt/repositories/mutest`/`mutest` through package-native test targets rather than the broken workspace-wide example path; enumerate only current mutation-applicable library/proc-macro packages; finish adversarial tests or simplify code until every survivor is classified; keep equivalent, invariant-only, and infrastructure-inapplicable classifications inspectable and minimal; document the exact local release command in the existing readiness surface. -- **Blocked by:** none; broad survivors currently remain in `hemx-axum`, `hemx-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts. +- **Blocked by:** none; broad survivors currently remain in `hemx-axum`, `hemx-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts; the next `hemx-axum` slice now proves page-mode and response-constructor semantics, while form/registry/rejection paths remain. - **Proof:** the new xtask mutation command exits zero within its documented bound, covers each applicable package, emits no unexplained missed mutant, and a deliberate adjacent mutation makes it fail. `cargo run -p hemx-xtask -- test` remains green. req: test/020 req: test/021 ## 3. Elect and enforce the release license policy diff --git a/hemx-axum/tests/response.rs b/hemx-axum/tests/response.rs index 0a1e478..709b089 100644 --- a/hemx-axum/tests/response.rs +++ b/hemx-axum/tests/response.rs @@ -118,6 +118,14 @@ fn page_mode_detects_partial_header() { #[test] fn page_request_wraps_full_pages_and_leaves_partials_unwrapped() { // req: test/005 + assert!(!PageRequest { + mode: PageMode::Full + } + .is_partial()); + assert!(PageRequest { + mode: PageMode::Partial + } + .is_partial()); let full = PageRequest { mode: PageMode::Full, } @@ -209,6 +217,26 @@ fn page_request_wraps_safe_html_full_pages_and_leaves_partials_unwrapped() { ); } +#[test] +fn page_response_constructors_preserve_mode_and_optional_fingerprint() { + let full = PageResponse::full("Full"); + assert_eq!(full.mode, PageMode::Full); + assert_eq!(full.html, "Full"); + assert_eq!(full.fingerprint, None); + + let partial = PageResponse::partial("
Partial
"); + assert_eq!(partial.mode, PageMode::Partial); + assert_eq!(partial.html, "
Partial
"); + assert_eq!(partial.fingerprint, None); + + let fingerprint = BuildFingerprint(42); + assert_eq!( + partial.fingerprint(fingerprint).fingerprint, + Some(fingerprint) + ); + // test req: page_swap/001 req: abi/005 +} + #[test] fn partial_page_response_sets_partial_and_title_headers() { let response = PageResponse::partial("
Docs
")