test(axum): harden page and media extraction

Prove explicit partial header values, full-page body and fingerprint delivery, and case-insensitive urlencoded media types through public Axum extractors and responses.

req: page_swap/001

req: abi/005

req: security/003
This commit is contained in:
slhx agent
2026-07-17 00:36:04 +02:00
parent 0fe2376874
commit 52a32cfb1f
2 changed files with 43 additions and 8 deletions
+1 -1
View File
@@ -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; the current `hemx-axum` frontier now proves page-mode, response constructors, form accessors/rejections, media-type limits, multipart success/error semantics, sync/async registry dispatch, effect/rejection responses, and embedded runtime delivery mutation-clean; remaining integration paths remain.
- **Blocked by:** none; broad survivors currently remain in `hemx-axum`, `hemx-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts; the current `hemx-axum` frontier now proves page-mode, response constructors, form accessors/rejections, media-type limits, multipart success/error semantics, sync/async registry dispatch, effect/rejection responses, and embedded runtime delivery mutation-clean; page extraction/response and media-type integration paths are now mutation-clean; remaining app/transport integration 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
+42 -7
View File
@@ -91,7 +91,7 @@ async fn interaction_boundary_honors_media_type_and_host_body_limit() {
Request::post("/mutate")
.header(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded; charset=utf-8",
"Application/X-Www-Form-Urlencoded; charset=UTF-8",
)
.body(Body::from("__h=1"))
.unwrap(),
@@ -235,12 +235,26 @@ impl hemx_core::FromForm for OpenProject {
}
#[test]
fn page_mode_detects_partial_header() {
let mut headers = HeaderMap::new();
assert_eq!(PageMode::from_headers(&headers), PageMode::Full);
headers.insert(HEMX_PARTIAL_HEADER, "true".parse().unwrap());
assert_eq!(PageMode::from_headers(&headers), PageMode::Partial);
fn page_mode_detects_only_explicit_partial_header_values() {
for value in [
None,
Some("false"),
Some("0"),
Some("TRUE"),
Some("invalid"),
] {
let mut headers = HeaderMap::new();
if let Some(value) = value {
headers.insert(HEMX_PARTIAL_HEADER, value.parse().unwrap());
}
assert_eq!(PageMode::from_headers(&headers), PageMode::Full);
}
for value in ["true", "1"] {
let mut headers = HeaderMap::new();
headers.insert(HEMX_PARTIAL_HEADER, value.parse().unwrap());
assert_eq!(PageMode::from_headers(&headers), PageMode::Partial);
}
// test req: page_swap/001
}
#[test]
@@ -365,6 +379,27 @@ fn page_response_constructors_preserve_mode_and_optional_fingerprint() {
// test req: page_swap/001 req: abi/005
}
#[tokio::test]
async fn full_page_response_preserves_html_and_fingerprint_without_partial_headers() {
let response = PageResponse::full("<html>Full</html>")
.fingerprint(BuildFingerprint(42))
.into_response();
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response.headers()[header::CONTENT_TYPE],
"text/html; charset=utf-8"
);
assert_eq!(response.headers()[HEMX_FINGERPRINT_HEADER], "42");
assert!(!response.headers().contains_key(HEMX_PARTIAL_HEADER));
assert!(!response.headers().contains_key(HEMX_TITLE_HEADER));
assert_eq!(
to_bytes(response.into_body(), 1024).await.unwrap().as_ref(),
b"<html>Full</html>"
);
// test req: page_swap/001 req: abi/005
}
#[test]
fn partial_page_response_sets_partial_and_title_headers() {
let response = PageResponse::partial("<main>Docs</main>")