/
nv-lang
/
nova-http
Обзор
Документация
Войти
/
nv-lang
/
nova-http
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
src/model_test.nv
123 строки
5 KB
Evgeniy Golovin
refactor(179-conv-chains, [222 №79]): А-конверсии — миграция call-сайтов по пакету
25 июл 2026, 00:36
25 июл 2026, 00:36
9217602
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // Plan 178 Ф.1 — Method / StatusCode / Version / HeaderMap / Mime / Cookie. // // Migrated from nova_tests/http/model_test.nv (Plan 182 Ф.2, 2026-07-07) after the // P67-LEGACY `module std.http` test-block blocker was fixed (see body_test.nv header). // Supersedes the transitional nova_tests/http/d358_http_message_model.nv (subset). module http test "method: parse round-trip + safety/idempotency" { ro g = "GET".to_method()!! assert(g.str() == "GET") assert(g.is_safe()) assert(g.is_idempotent()) ro pf = "PROPFIND".to_method()!! assert(match pf { Other(s) => s == "PROPFIND", _ => false }) ro post = "POST".to_method()!! assert(!post.is_safe()) assert(!post.is_idempotent()) assert(post.allows_body()) } test "method neg: non-token rejected" { assert(match "GE T".to_method() { Ok(_) => false, Err(_) => true }) assert(match "".to_method() { Ok(_) => false, Err(_) => true }) } test "status: class + reason + range guard" { ro nf = StatusCode.NOT_FOUND assert(nf.code() == 404) assert(nf.reason() == "Not Found") assert(nf.is_client_error()) assert(match nf.class() { ClientError => true, _ => false }) ro ok = StatusCode.OK assert(ok.is_success()) assert(match StatusCode.new(599)!!.class() { ServerError => true, _ => false }) assert(match StatusCode.new(700) { Ok(_) => false, Err(_) => true }) assert(match StatusCode.new(99) { Ok(_) => false, Err(_) => true }) } test "version: as_str + keepalive" { ro v11 = Version.Http11 assert(v11.str() == "HTTP/1.1") assert(v11.supports_keepalive()) ro v10 = Version.Http10 assert(!v10.supports_keepalive()) ro v2 = Version.Http2 assert(v2.str() == "HTTP/2") } fn hm_build() -> Result[HeaderMap, HttpError] { mut h = HeaderMap.new() h.insert("Content-Type", "text/html")? h.append("Set-Cookie", "a=1")? h.append("set-cookie", "b=2")? Ok(h) } test "headermap: case-insensitive, ordered, multi-value" { ro h = hm_build()!! assert(h.contains("CONTENT-TYPE")) assert(match h.get("content-type") { Some(v) => v.to_str()!! == "text/html", None => false }) ro all = h.get_all("Set-Cookie") assert(all.len() == 2) assert(match all.get(0) { Some(v) => v.to_str()!! == "a=1", None => false }) assert(match all.get(1) { Some(v) => v.to_str()!! == "b=2", None => false }) } test "headermap: insert replaces, remove returns" { // `mut` from the start (D246 canon (a)) — this test-local is mutated // right below; not shared with anything else. mut h = hm_build()!! ro r1 = h.insert("Set-Cookie", "z=9") // replace both assert(h.get_all("set-cookie").len() == 1) ro removed = h.remove("Content-Type") assert(removed.len() == 1) assert(!h.contains("content-type")) } test "headermap neg: CR/LF/NUL rejected (response-splitting defense)" { mut h = HeaderMap.new() assert(match h.append("X", "a\r\nEvil: 1") { Ok(_) => false, Err(_) => true }) assert(match h.append("X", "a\nb") { Ok(_) => false, Err(_) => true }) assert(match h.append("Bad Name", "v") { Ok(_) => false, Err(_) => true }) } fn cl_headers(cl str, te str) -> Result[HeaderMap, HttpError] { mut h = HeaderMap.new() h.append("Content-Length", cl)? h.append("Transfer-Encoding", te)? Ok(h) } test "headermap: Content-Length + Transfer-Encoding conflict → Err (smuggling)" { ro h = cl_headers("5", "chunked")!! assert(match h.content_length() { Ok(_) => false, Err(_) => true }) } test "mime + content-type parse" { ro m = "Application/JSON".to_mime()!! assert(m.essence() == "application/json") assert(m.mtype() == "application") assert(m.subtype() == "json") ro ct = "text/html; charset=utf-8".to_content_type()!! assert(ct.mime.essence() == "text/html") assert(match ct.charset() { Some(c) => c == "utf-8", None => false }) assert(match "nogielsh".to_mime() { Ok(_) => false, Err(_) => true }) } test "cookie: request header parse + SetCookie send-invariants" { ro cs = Cookie.parse_header("a=1; b=2")!! assert(cs.len() == 2) ro sc = "__Secure-sid=x; Secure; SameSite=Lax; Max-Age=60".to_setcookie()!! assert(sc.secure) assert(sc.is_persistent()) assert(!sc.is_sendable(false)) assert(sc.is_sendable(true)) } test "cookie neg: SameSite=None without Secure, __Host- misuse → Err" { assert(match "a=b; SameSite=None".to_setcookie() { Ok(_) => false, Err(_) => true }) assert(match "__Host-x=1; Secure; Domain=e.com; Path=/".to_setcookie() { Ok(_) => false, Err(_) => true }) assert(match "__Secure-x=1; SameSite=Lax".to_setcookie() { Ok(_) => false, Err(_) => true }) }