#![allow(unused_must_use, dead_code)]
use std::sync::Arc;
use fastapi_core::{
App, BoxFuture, FixtureGuard, Handler, IntegrationTest, Method, Request, RequestContext,
Response, ResponseBody, StatusCode, TestClient, TestFixture,
};
struct CounterFixture {
setup_count: u32,
request_count: u32,
}
impl TestFixture for CounterFixture {
fn setup() -> Self {
CounterFixture {
setup_count: 1,
request_count: 0,
}
}
fn teardown(&mut self) {
assert!(self.setup_count > 0, "Teardown called without setup");
}
}
struct UserFixture {
user_id: i64,
username: String,
}
impl TestFixture for UserFixture {
fn setup() -> Self {
UserFixture {
user_id: 42,
username: "test_user".to_string(),
}
}
fn teardown(&mut self) {
}
}
struct FnHandler<F: Fn() -> Response + Send + Sync>(F);
impl<F: Fn() -> Response + Send + Sync> Handler for FnHandler<F> {
fn call<'a>(
&'a self,
_ctx: &'a RequestContext,
_req: &'a mut Request,
) -> BoxFuture<'a, Response> {
let resp = (self.0)();
Box::pin(async move { resp })
}
}
#[test]
fn test_fixture_setup_and_teardown() {
let guard = FixtureGuard::<CounterFixture>::new();
assert_eq!(guard.setup_count, 1);
assert_eq!(guard.request_count, 0);
}
#[test]
fn test_app_test_client_integration() {
let app = App::builder()
.route(
"/hello",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"Hello, World!".to_vec()))
},
)
.route(
"/user",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::json(&serde_json::json!({
"id": 42,
"name": "Test User"
}))
.unwrap()
},
)
.build();
let app = Arc::new(app);
let client = app.clone().test_client();
let response = client.get("/hello").send();
response.assert_status(StatusCode::OK);
assert_eq!(response.text(), "Hello, World!");
let response = client.get("/user").send();
response.assert_status(StatusCode::OK);
let json: serde_json::Value = response.json().unwrap();
assert_eq!(json["id"], 42);
assert_eq!(json["name"], "Test User");
}
#[test]
fn test_integration_test_with_fixtures() {
let app = Arc::new(
App::builder()
.route(
"/user",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::json(&serde_json::json!({
"id": 42,
"name": "Test User"
}))
.unwrap()
},
)
.build(),
);
IntegrationTest::new("User API Test", app)
.with_fixture::<UserFixture>()
.run(|ctx| {
let user_fixture = ctx.fixture::<UserFixture>().unwrap();
assert_eq!(user_fixture.user_id, 42);
assert_eq!(user_fixture.username, "test_user");
let response = ctx.get("/user").send();
response.assert_success();
let json: serde_json::Value = response.json().unwrap();
assert_eq!(json["id"], user_fixture.user_id);
});
}
#[test]
fn test_full_request_lifecycle() {
let app = Arc::new(
App::builder()
.route(
"/hello",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"Hello!".to_vec()))
},
)
.route(
"/error",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::with_status(StatusCode::BAD_REQUEST)
.body(ResponseBody::Bytes(b"Bad Request".to_vec()))
},
)
.build(),
);
let client = TestClient::new(app);
let response = client.get("/hello").send();
assert!(response.is_success());
assert_eq!(response.status().as_u16(), 200);
let response = client.get("/error").send();
assert!(response.is_client_error());
assert_eq!(response.status().as_u16(), 400);
let response = client.get("/nonexistent").send();
assert_eq!(response.status().as_u16(), 404);
let response = client.post("/hello").send();
assert_eq!(response.status().as_u16(), 405);
}
#[test]
fn test_options_auto_handling() {
let app = Arc::new(
App::builder()
.route(
"/resource",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"GET".to_vec()))
},
)
.route(
"/resource",
Method::Post,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Empty)
},
)
.build(),
);
let client = TestClient::new(app);
let response = client.options("/resource").send();
assert_eq!(response.status().as_u16(), 204);
let allow = response.header_str("Allow").unwrap();
assert!(allow.contains("GET"));
assert!(allow.contains("POST"));
assert!(allow.contains("OPTIONS"));
}
#[test]
fn test_parallel_test_isolation() {
let app = Arc::new(
App::builder()
.route(
"/hello",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"Hello!".to_vec()))
},
)
.build(),
);
let client1 = app.clone().test_client_with_seed(42);
let client2 = app.clone().test_client_with_seed(42);
assert_eq!(client1.seed(), Some(42));
assert_eq!(client2.seed(), Some(42));
let r1 = client1.get("/hello").send();
let r2 = client2.get("/hello").send();
assert_eq!(r1.status().as_u16(), r2.status().as_u16());
assert_eq!(r1.text(), r2.text());
}
#[test]
fn test_state_reset_between_tests() {
let app = Arc::new(
App::builder()
.route(
"/hello",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"Hello!".to_vec()))
},
)
.build(),
);
let client = TestClient::new(app);
let response = client.get("/hello").cookie("session", "test123").send();
response.assert_success();
client.clear_cookies();
client.clear_dependency_overrides();
assert!(client.cookies().is_empty());
}
#[test]
fn test_integration_test_reset_hooks() {
use std::sync::atomic::{AtomicBool, Ordering};
static RESET_CALLED: AtomicBool = AtomicBool::new(false);
let app = Arc::new(
App::builder()
.route(
"/hello",
Method::Get,
|_ctx: &RequestContext, _req: &mut Request| async {
Response::ok().body(ResponseBody::Bytes(b"Hello!".to_vec()))
},
)
.build(),
);
IntegrationTest::new("Reset Hook Test", app)
.on_reset(|| {
RESET_CALLED.store(true, Ordering::SeqCst);
})
.run(|ctx| {
let response = ctx.get("/hello").send();
response.assert_success();
});
assert!(RESET_CALLED.load(Ordering::SeqCst));
}