Skip to main content

siderite_testkit/
builder.rs

1//! [`TestClientBuilder`]: configure an [`App`] for testing, then build.
2
3use crate::TestClient;
4use siderite_core::di::{Dependency, RequestHead};
5use siderite_core::{ApiError, App, ServerError};
6use siderite_orm::Db;
7use std::future::Future;
8
9/// Applies test-only configuration to an [`App`] before it becomes a
10/// [`TestClient`].
11///
12/// A built client owns an immutable service, so overrides and databases must
13/// be set here rather than on the client.
14#[derive(Debug)]
15pub struct TestClientBuilder {
16    app: App,
17}
18
19impl TestClientBuilder {
20    pub(crate) fn new(app: App) -> Self {
21        Self { app }
22    }
23
24    /// Replace `T::resolve` with `f` for every request (see
25    /// [`App::override_dependency`]).
26    #[must_use]
27    pub fn override_dependency<T, F, Fut>(self, f: F) -> Self
28    where
29        T: Dependency,
30        F: Fn(RequestHead) -> Fut + Send + Sync + 'static,
31        Fut: Future<Output = Result<T, ApiError>> + Send + 'static,
32    {
33        Self {
34            app: self.app.override_dependency(f),
35        }
36    }
37
38    /// Replace `T::resolve` with a clone of `value`.
39    #[must_use]
40    pub fn override_value<T: Dependency + Clone>(self, value: T) -> Self {
41        Self {
42            app: self.app.override_value(value),
43        }
44    }
45
46    /// Register `db` under `alias`, replacing any database the app already
47    /// registered with that alias (see [`App::database`]).
48    #[must_use]
49    pub fn with_database(self, alias: impl Into<String>, db: Db) -> Self {
50        Self {
51            app: self.app.database(alias, db),
52        }
53    }
54
55    /// Build the client without running startup hooks.
56    ///
57    /// # Errors
58    /// The app's configuration error.
59    pub fn try_build(self) -> Result<TestClient, ServerError> {
60        TestClient::try_new(self.app)
61    }
62
63    /// Build the client, for use in tests.
64    ///
65    /// # Panics
66    /// Panics if the app is misconfigured; use [`try_build`](Self::try_build)
67    /// to assert on configuration errors.
68    pub fn build(self) -> TestClient {
69        TestClient::new(self.app)
70    }
71
72    /// Build the client and run the app's startup hooks (see
73    /// [`TestClient::start`]).
74    ///
75    /// # Errors
76    /// Configuration or startup-hook failure.
77    pub async fn start(self) -> Result<TestClient, ServerError> {
78        TestClient::start(self.app).await
79    }
80}