an http based roguelike rpg about jelqing
Blame: src/tests/mod.rs
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 1 | mod body; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 2 | mod floors; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 3 | mod household; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 4 | mod meta; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 5 | mod methods; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 6 | mod rolls; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 7 | mod turns; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 8 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 9 | pub use std::{sync::Arc, time::Duration}; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 10 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 11 | pub use axum::{ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 12 | Router, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 13 | body::{Body, to_bytes}, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 14 | http::{Method, Request, StatusCode, Version, header}, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 15 | response::Response, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 16 | }; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 17 | pub use serde_json::Value; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 18 | use tower::ServiceExt; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 19 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 20 | pub use crate::{ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 21 | AppState, Config, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 22 | game::{ |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 23 | Excuse, Floor, MumVisit, Run, Story, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 24 | balance::{BRANCH_TURN, SUSPICION_LIMIT}, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 25 | }, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 26 | router, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 27 | }; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 28 | |
880b29a0c11e | atagen | 2026-10-13 09:27 UTC | 29 | pub const SEED: u64 = 420; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 30 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 31 | pub async fn send( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 32 | app: &Router, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 33 | method: &str, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 34 | uri: &str, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 35 | headers: &[(&str, &str)], |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 36 | body: &str, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 37 | ) -> Response { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 38 | let mut request = Request::builder() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 39 | .method(Method::from_bytes(method.as_bytes()).unwrap()) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 40 | .uri(uri); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 41 | for (name, value) in headers { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 42 | request = request.header(*name, *value); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 43 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 44 | app.clone() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 45 | .oneshot(request.body(Body::from(body.to_owned())).unwrap()) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 46 | .await |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 47 | .unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 48 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 49 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 50 | pub async fn json(response: Response) -> Value { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 51 | serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap()).unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 52 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 53 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 54 | pub async fn text(response: Response) -> String { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 55 | String::from_utf8( |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 56 | to_bytes(response.into_body(), usize::MAX) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 57 | .await |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 58 | .unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 59 | .to_vec(), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 60 | ) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 61 | .unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 62 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 63 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 64 | pub fn header<'a>(response: &'a Response, name: &str) -> &'a str { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 65 | response.headers()[name].to_str().unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 66 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 67 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 68 | /// Every `Warning` on a response, since a turn can carry several. |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 69 | pub fn warnings(response: &Response) -> Vec<String> { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 70 | response |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 71 | .headers() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 72 | .get_all("warning") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 73 | .iter() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 74 | .map(|value| value.to_str().unwrap().to_owned()) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 75 | .collect() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 76 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 77 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 78 | /// A server holding one run, `cafebabe`, set up by `setup` before anyone can reach it. |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 79 | pub struct Harness { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 80 | pub app: Router, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 81 | pub origin: String, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 82 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 83 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 84 | pub fn harness(floor: Floor, seed: u64, setup: impl FnOnce(&mut Run)) -> Harness { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 85 | let state = Arc::new(AppState::default()); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 86 | let mut run = Run::new("cafebabe".into(), "cafe".into(), seed); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 87 | run.floor = floor; |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 88 | setup(&mut run); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 89 | let origin = run.origin_etag(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 90 | state.insert(run); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 91 | Harness { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 92 | app: router(state), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 93 | origin, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 94 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 95 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 96 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 97 | pub fn seeded_with(floor: Floor, setup: impl FnOnce(&mut Run)) -> Router { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 98 | harness(floor, SEED, setup).app |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 99 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 100 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 101 | pub fn app_with(floor: Floor, seed: u64, setup: impl FnOnce(&mut Run)) -> Router { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 102 | harness(floor, seed, setup).app |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 103 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 104 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 105 | pub fn app() -> Router { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 106 | crate::app(Config::default()).unwrap() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 107 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 108 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 109 | pub fn mum_at_the_door(run: &mut Run) { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 110 | run.household.mum = Some(MumVisit { |
886159fd0fe7 | atagen | 2026-10-13 12:48 UTC | 111 | errand: crate::game::HEARD_A_NOISE, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 112 | nonce: "abc".into(), |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 113 | strikes: 0, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 114 | knocked: false, |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 115 | }); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 116 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 117 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 118 | /// The `Link` entries on a response, as `(rel, title)` with the rel base stripped. |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 119 | pub fn links(response: &Response) -> Vec<(String, Option<String>)> { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 120 | header(response, "link") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 121 | .split(", <") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 122 | .filter_map(|entry| { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 123 | let rel = entry.split("rels/").nth(1)?.split('"').next()?.to_owned(); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 124 | let title = entry |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 125 | .split("title=\"") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 126 | .nth(1) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 127 | .and_then(|t| t.split('"').next()) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 128 | .map(str::to_owned); |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 129 | Some((rel, title)) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 130 | }) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 131 | .collect() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 132 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 133 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 134 | pub fn advertised(response: &Response) -> Vec<String> { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 135 | links(response) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 136 | .into_iter() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 137 | .filter(|(rel, _)| rel == "technique") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 138 | .filter_map(|(_, title)| title) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 139 | .collect() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 140 | } |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 141 | |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 142 | pub fn linked_rels(response: &Response) -> Vec<String> { |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 143 | links(response) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 144 | .into_iter() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 145 | .map(|(rel, _)| rel) |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 146 | .filter(|rel| rel != "technique") |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 147 | .collect() |
8b8e83329a1d | atagen | 2026-10-12 12:01 UTC | 148 | } |