atagen

jelq

public

an http based roguelike rpg about jelqing

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