#![allow(dead_code)]
pub mod fixtures;
use rustigram_api::{BotClient, ClientConfig};
use serde_json::Value;
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, Request, ResponseTemplate};
pub const TOKEN: &str = "123456:test-token-for-mock-tests";
pub async fn spawn() -> (MockServer, BotClient) {
let server = MockServer::start().await;
let config = ClientConfig::new(TOKEN)
.expect("the test token is well-formed")
.api_base_url(server.uri());
let client = BotClient::new(config).expect("client builds");
(server, client)
}
pub fn api_path(api_method: &str) -> String {
format!("/bot{TOKEN}/{api_method}")
}
pub async fn mount_ok(server: &MockServer, api_method: &str, result: Value) {
Mock::given(method("POST"))
.and(path(api_path(api_method)))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"ok": true,
"result": result,
})))
.mount(server)
.await;
}
pub async fn mount_catch_all(server: &MockServer) {
Mock::given(method("POST"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"ok": true,
"result": {},
})))
.mount(server)
.await;
}
pub fn api_method_of(request: &Request) -> String {
request
.url
.path()
.rsplit('/')
.next()
.unwrap_or_default()
.to_owned()
}
pub async fn mount_api_error(
server: &MockServer,
api_method: &str,
code: u16,
description: &str,
parameters: Option<Value>,
) {
let mut body = serde_json::json!({
"ok": false,
"error_code": code,
"description": description,
});
if let Some(p) = parameters {
body["parameters"] = p;
}
Mock::given(method("POST"))
.and(path(api_path(api_method)))
.respond_with(ResponseTemplate::new(200).set_body_json(body))
.mount(server)
.await;
}
pub async fn mount_raw(server: &MockServer, api_method: &str, status: u16, body: &str) {
Mock::given(method("POST"))
.and(path(api_path(api_method)))
.respond_with(ResponseTemplate::new(status).set_body_string(body))
.mount(server)
.await;
}
pub async fn mount_file(server: &MockServer, file_path: &str, bytes: &'static [u8]) {
Mock::given(method("GET"))
.and(path(format!("/file/bot{TOKEN}/{file_path}")))
.respond_with(ResponseTemplate::new(200).set_body_bytes(bytes))
.mount(server)
.await;
}
pub async fn mount_then(
server: &MockServer,
api_method: &str,
first: Value,
times: u64,
then: Value,
) {
Mock::given(method("POST"))
.and(path(api_path(api_method)))
.respond_with(ResponseTemplate::new(200).set_body_json(first))
.up_to_n_times(times)
.mount(server)
.await;
Mock::given(method("POST"))
.and(path(api_path(api_method)))
.respond_with(ResponseTemplate::new(200).set_body_json(then))
.mount(server)
.await;
}
pub fn flood_control(retry_after: u32) -> Value {
serde_json::json!({
"ok": false,
"error_code": 429,
"description": "Too Many Requests: retry after 1",
"parameters": { "retry_after": retry_after },
})
}
pub async fn requests(server: &MockServer) -> Vec<Request> {
server
.received_requests()
.await
.expect("the mock server records requests")
}
pub async fn only_request(server: &MockServer) -> Request {
let mut all = requests(server).await;
assert_eq!(
all.len(),
1,
"expected exactly one request, the server saw {}",
all.len()
);
all.remove(0)
}
pub fn json_body(request: &Request) -> Value {
serde_json::from_slice(&request.body).unwrap_or_else(|e| {
panic!(
"request body is not JSON: {e}\nbody was: {}",
String::from_utf8_lossy(&request.body)
)
})
}
pub fn multipart_field_names(request: &Request) -> Vec<String> {
let body = String::from_utf8_lossy(&request.body);
let mut names: Vec<String> = body
.split("; name=\"")
.skip(1)
.filter_map(|rest| rest.split('"').next())
.map(str::to_owned)
.collect();
names.sort();
names.dedup();
names
}
pub fn assert_multipart_fields(request: &Request, expected: &[&str]) {
let actual = multipart_field_names(request);
let mut want: Vec<String> = expected.iter().map(|s| (*s).to_owned()).collect();
want.sort();
assert_eq!(
actual, want,
"multipart fields differ\n sent: {actual:?}\n expected: {want:?}"
);
}
pub fn assert_field(body: &Value, key: &str, value: Value) {
assert_eq!(
body.get(key),
Some(&value),
"field `{key}`: expected {value}, body was {body}"
);
}
pub fn assert_absent(body: &Value, key: &str) {
assert!(
body.get(key).is_none(),
"field `{key}` should be absent when unset, body was {body}"
);
}