atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
aef6f6498ea2ef0c39d1079a0ca0bc99afdd9bac
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/tests/methods.rs

8b8e83329a1datagen2026-10-12 12:01 UTC1
use super::*;
8b8e83329a1datagen2026-10-12 12:01 UTC2
8b8e83329a1datagen2026-10-12 12:01 UTC3
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC4
async fn creating_a_run_returns_location_and_etag() {
8b8e83329a1datagen2026-10-12 12:01 UTC5
    let response = send(&app(), "POST", "/runs?seed=1", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC6
    assert_eq!(response.status(), StatusCode::CREATED);
8b8e83329a1datagen2026-10-12 12:01 UTC7
    assert!(header(&response, "location").starts_with("/runs/"));
8b8e83329a1datagen2026-10-12 12:01 UTC8
    assert!(response.headers().contains_key(header::ETAG));
8b8e83329a1datagen2026-10-12 12:01 UTC9
    assert_eq!(header(&response, "server"), "jelqd/0.6.9");
8b8e83329a1datagen2026-10-12 12:01 UTC10
}
8b8e83329a1datagen2026-10-12 12:01 UTC11
8b8e83329a1datagen2026-10-12 12:01 UTC12
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC13
async fn bodies_do_not_repeat_the_headers() {
8b8e83329a1datagen2026-10-12 12:01 UTC14
    let Harness { app, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC15
    let response = send(&app, "GET", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC16
    assert!(response.headers().contains_key("x-eq"));
8b8e83329a1datagen2026-10-12 12:01 UTC17
    let body = json(response).await;
8b8e83329a1datagen2026-10-12 12:01 UTC18
    for stat in [
8b8e83329a1datagen2026-10-12 12:01 UTC19
        "eq",
8b8e83329a1datagen2026-10-12 12:01 UTC20
        "girth",
8b8e83329a1datagen2026-10-12 12:01 UTC21
        "foreskin",
8b8e83329a1datagen2026-10-12 12:01 UTC22
        "stamina",
8b8e83329a1datagen2026-10-12 12:01 UTC23
        "cash",
8b8e83329a1datagen2026-10-12 12:01 UTC24
        "self_reported_length",
8b8e83329a1datagen2026-10-12 12:01 UTC25
    ] {
8b8e83329a1datagen2026-10-12 12:01 UTC26
        assert!(body.get(stat).is_none(), "{stat} is already a header");
8b8e83329a1datagen2026-10-12 12:01 UTC27
    }
8b8e83329a1datagen2026-10-12 12:01 UTC28
}
8b8e83329a1datagen2026-10-12 12:01 UTC29
8b8e83329a1datagen2026-10-12 12:01 UTC30
#[tokio::test]
4b1f5f88827datagen2026-10-13 10:18 UTC31
async fn jelqing_cold_goes_through_at_a_price() {
4b1f5f88827datagen2026-10-13 10:18 UTC32
    let friction = async |warm: bool| {
4b1f5f88827datagen2026-10-13 10:18 UTC33
        let app = seeded_with(Floor::Bedroom, |run| {
4b1f5f88827datagen2026-10-13 10:18 UTC34
            run.body.warmed_up = warm;
4b1f5f88827datagen2026-10-13 10:18 UTC35
            run.body.foreskin = Some(1.0);
4b1f5f88827datagen2026-10-13 10:18 UTC36
        });
4b1f5f88827datagen2026-10-13 10:18 UTC37
        let response = send(&app, "JELQ", "/runs/cafebabe?technique=stretch", &[], "").await;
4b1f5f88827datagen2026-10-13 10:18 UTC38
        let noted = warnings(&response)
4b1f5f88827datagen2026-10-13 10:18 UTC39
            .iter()
4b1f5f88827datagen2026-10-13 10:18 UTC40
            .any(|w| w.contains("Warm-up was skipped"));
4b1f5f88827datagen2026-10-13 10:18 UTC41
        assert_eq!(noted, !warm);
4b1f5f88827datagen2026-10-13 10:18 UTC42
        header(&response, "x-friction").to_owned()
4b1f5f88827datagen2026-10-13 10:18 UTC43
    };
4b1f5f88827datagen2026-10-13 10:18 UTC44
    assert_eq!(friction(true).await, "1/10");
4b1f5f88827datagen2026-10-13 10:18 UTC45
    assert_eq!(friction(false).await, "3/10");
8b8e83329a1datagen2026-10-12 12:01 UTC46
}
8b8e83329a1datagen2026-10-12 12:01 UTC47
8b8e83329a1datagen2026-10-12 12:01 UTC48
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC49
async fn wet_without_lube_is_unsupported_media() {
8b8e83329a1datagen2026-10-12 12:01 UTC50
    let Harness { app, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC51
    send(&app, "JELQ", "/runs/cafebabe?technique=warmup", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC52
    let response = send(&app, "JELQ", "/runs/cafebabe?technique=wet", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC53
    assert_eq!(response.status(), StatusCode::UNSUPPORTED_MEDIA_TYPE);
8b8e83329a1datagen2026-10-12 12:01 UTC54
    let images = send(
8b8e83329a1datagen2026-10-12 12:01 UTC55
        &app,
8b8e83329a1datagen2026-10-12 12:01 UTC56
        "JELQ",
8b8e83329a1datagen2026-10-12 12:01 UTC57
        "/runs/cafebabe?technique=wet",
8b8e83329a1datagen2026-10-12 12:01 UTC58
        &[("content-type", "image/jpeg")],
8b8e83329a1datagen2026-10-12 12:01 UTC59
        "",
8b8e83329a1datagen2026-10-12 12:01 UTC60
    )
8b8e83329a1datagen2026-10-12 12:01 UTC61
    .await;
8b8e83329a1datagen2026-10-12 12:01 UTC62
    assert_eq!(json(images).await["detail"], "No.");
8b8e83329a1datagen2026-10-12 12:01 UTC63
}
8b8e83329a1datagen2026-10-12 12:01 UTC64
8b8e83329a1datagen2026-10-12 12:01 UTC65
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC66
async fn unknown_methods_are_not_implemented() {
8b8e83329a1datagen2026-10-12 12:01 UTC67
    let Harness { app, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC68
    let response = send(&app, "MILK", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC69
    assert_eq!(response.status(), StatusCode::NOT_IMPLEMENTED);
8b8e83329a1datagen2026-10-12 12:01 UTC70
    let teapot = send(&app, "BREW", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC71
    assert_eq!(teapot.status(), StatusCode::IM_A_TEAPOT);
8b8e83329a1datagen2026-10-12 12:01 UTC72
}
8b8e83329a1datagen2026-10-12 12:01 UTC73
8b8e83329a1datagen2026-10-12 12:01 UTC74
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC75
async fn the_clinic_does_not_advertise_jelq() {
8b8e83329a1datagen2026-10-12 12:01 UTC76
    let Harness { app, .. } = harness(Floor::Clinic, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC77
    let options = send(&app, "OPTIONS", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC78
    assert!(!header(&options, "allow").contains("JELQ"));
8b8e83329a1datagen2026-10-12 12:01 UTC79
    let jelq = send(&app, "JELQ", "/runs/cafebabe?technique=wet", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC80
    assert_eq!(jelq.status(), StatusCode::METHOD_NOT_ALLOWED);
8b8e83329a1datagen2026-10-12 12:01 UTC81
    assert!(!header(&jelq, "allow").contains("JELQ"));
8b8e83329a1datagen2026-10-12 12:01 UTC82
    let Harness { app: bedroom, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC83
    let options = send(&bedroom, "OPTIONS", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC84
    assert!(header(&options, "allow").contains("JELQ"));
8b8e83329a1datagen2026-10-12 12:01 UTC85
}
8b8e83329a1datagen2026-10-12 12:01 UTC86
8b8e83329a1datagen2026-10-12 12:01 UTC87
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC88
async fn patch_only_accepts_the_truth() {
8b8e83329a1datagen2026-10-12 12:01 UTC89
    let Harness { app, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC90
    let patch = [("content-type", "application/json-patch+json")];
8b8e83329a1datagen2026-10-12 12:01 UTC91
    let replace = send(
8b8e83329a1datagen2026-10-12 12:01 UTC92
        &app,
8b8e83329a1datagen2026-10-12 12:01 UTC93
        "PATCH",
8b8e83329a1datagen2026-10-12 12:01 UTC94
        "/runs/cafebabe",
8b8e83329a1datagen2026-10-12 12:01 UTC95
        &patch,
8b8e83329a1datagen2026-10-12 12:01 UTC96
        r#"[{"op":"replace","path":"/length","value":12}]"#,
8b8e83329a1datagen2026-10-12 12:01 UTC97
    )
8b8e83329a1datagen2026-10-12 12:01 UTC98
    .await;
8b8e83329a1datagen2026-10-12 12:01 UTC99
    assert_eq!(replace.status(), StatusCode::UNPROCESSABLE_ENTITY);
8b8e83329a1datagen2026-10-12 12:01 UTC100
    let lie = send(
8b8e83329a1datagen2026-10-12 12:01 UTC101
        &app,
8b8e83329a1datagen2026-10-12 12:01 UTC102
        "PATCH",
8b8e83329a1datagen2026-10-12 12:01 UTC103
        "/runs/cafebabe",
8b8e83329a1datagen2026-10-12 12:01 UTC104
        &patch,
8b8e83329a1datagen2026-10-12 12:01 UTC105
        r#"[{"op":"test","path":"/length","value":40}]"#,
8b8e83329a1datagen2026-10-12 12:01 UTC106
    )
8b8e83329a1datagen2026-10-12 12:01 UTC107
    .await;
8b8e83329a1datagen2026-10-12 12:01 UTC108
    assert_eq!(
8b8e83329a1datagen2026-10-12 12:01 UTC109
        json(lie).await["type"],
8b8e83329a1datagen2026-10-12 12:01 UTC110
        "https://jelq.dev/problems/exaggeration"
8b8e83329a1datagen2026-10-12 12:01 UTC111
    );
8b8e83329a1datagen2026-10-12 12:01 UTC112
}
8b8e83329a1datagen2026-10-12 12:01 UTC113
8b8e83329a1datagen2026-10-12 12:01 UTC114
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC115
async fn http_1_0_gets_the_pdf_treatment() {
8b8e83329a1datagen2026-10-12 12:01 UTC116
    let request = Request::builder()
8b8e83329a1datagen2026-10-12 12:01 UTC117
        .uri("/graveyard")
8b8e83329a1datagen2026-10-12 12:01 UTC118
        .version(Version::HTTP_10)
8b8e83329a1datagen2026-10-12 12:01 UTC119
        .body(Body::empty())
8b8e83329a1datagen2026-10-12 12:01 UTC120
        .unwrap();
8b8e83329a1datagen2026-10-12 12:01 UTC121
    let response = app().oneshot(request).await.unwrap();
8b8e83329a1datagen2026-10-12 12:01 UTC122
    assert_eq!(response.status(), StatusCode::HTTP_VERSION_NOT_SUPPORTED);
8b8e83329a1datagen2026-10-12 12:01 UTC123
}
8b8e83329a1datagen2026-10-12 12:01 UTC124
8b8e83329a1datagen2026-10-12 12:01 UTC125
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC126
async fn links_offer_only_usable_techniques() {
8b8e83329a1datagen2026-10-12 12:01 UTC127
    let app = seeded_with(Floor::Bedroom, |run| run.body.foreskin = Some(1.0));
8b8e83329a1datagen2026-10-12 12:01 UTC128
    let cold = send(&app, "GET", "/runs/cafebabe", &[], "").await;
4b1f5f88827datagen2026-10-13 10:18 UTC129
    assert!(
4b1f5f88827datagen2026-10-13 10:18 UTC130
        advertised(&cold).contains(&"stretch".to_owned()),
4b1f5f88827datagen2026-10-13 10:18 UTC131
        "a cold jelq is allowed"
4b1f5f88827datagen2026-10-13 10:18 UTC132
    );
8b8e83329a1datagen2026-10-12 12:01 UTC133
    let warm = send(&app, "JELQ", "/runs/cafebabe?technique=warmup", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC134
    let usable = advertised(&warm);
8b8e83329a1datagen2026-10-12 12:01 UTC135
    assert!(usable.contains(&"wet".to_owned()) && usable.contains(&"dry".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC136
    assert!(!usable.contains(&"uli".to_owned()), "uli needs the forum");
8b8e83329a1datagen2026-10-12 12:01 UTC137
    assert!(!usable.contains(&"pump".to_owned()), "pump needs a pump");
8b8e83329a1datagen2026-10-12 12:01 UTC138
    assert!(
8b8e83329a1datagen2026-10-12 12:01 UTC139
        header(&warm, "link").contains("title=\"wet\"; allow=\"JELQ\"; lubricant=\"required\"")
8b8e83329a1datagen2026-10-12 12:01 UTC140
    );
8b8e83329a1datagen2026-10-12 12:01 UTC141
8b8e83329a1datagen2026-10-12 12:01 UTC142
    let Harness { app: forum, .. } = harness(Floor::Forum, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC143
    let response = send(&forum, "GET", "/runs/cafebabe", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC144
    assert!(advertised(&response).is_empty());
8b8e83329a1datagen2026-10-12 12:01 UTC145
}
8b8e83329a1datagen2026-10-12 12:01 UTC146
8b8e83329a1datagen2026-10-12 12:01 UTC147
#[tokio::test]
8b8e83329a1datagen2026-10-12 12:01 UTC148
async fn links_hide_resources_that_would_do_nothing() {
8b8e83329a1datagen2026-10-12 12:01 UTC149
    let Harness { app: bedroom, .. } = harness(Floor::Bedroom, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC150
    let before = linked_rels(&send(&bedroom, "GET", "/runs/cafebabe", &[], "").await);
8b8e83329a1datagen2026-10-12 12:01 UTC151
    assert!(before.contains(&"drawer".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC152
    assert!(!before.contains(&"diagnosis".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC153
    assert!(!before.contains(&"thread".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC154
    let searched = send(&bedroom, "POST", "/runs/cafebabe/drawer", &[], "").await;
8b8e83329a1datagen2026-10-12 12:01 UTC155
    assert!(!linked_rels(&searched).contains(&"drawer".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC156
8b8e83329a1datagen2026-10-12 12:01 UTC157
    let Harness { app: clinic, .. } = harness(Floor::Clinic, SEED, |_| {});
8b8e83329a1datagen2026-10-12 12:01 UTC158
    let rels = linked_rels(&send(&clinic, "GET", "/runs/cafebabe", &[], "").await);
8b8e83329a1datagen2026-10-12 12:01 UTC159
    assert!(rels.contains(&"diagnosis".to_owned()) && rels.contains(&"thread".to_owned()));
8b8e83329a1datagen2026-10-12 12:01 UTC160
}