atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: testing/matrix-sdk-test/src/lib.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use std::{fmt, sync::LazyLock};
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use http::Response;
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
pub use matrix_sdk_test_macros::async_test;
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
use ruma::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
    RoomId, UserId,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
    api::{IncomingResponse, OutgoingResponse},
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
    room_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
    serde::{Base64, base64::UrlSafe},
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
    user_id,
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
use sha2::{Digest, Sha256};
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
/// Create a `Raw<AnyMessageLikeEventContent>` from arbitrary JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
/// Forwards all arguments to [`serde_json::json`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
#[macro_export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
macro_rules! message_like_event_content {
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
    ($( $tt:tt )*) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
            .cast_unchecked::<::ruma::events::AnyMessageLikeEventContent>()
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
/// Create a `Raw<AnyTimelineEvent>` from arbitrary JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
/// Forwards all arguments to [`serde_json::json`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
#[macro_export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
macro_rules! timeline_event {
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
    ($( $tt:tt )*) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
            .cast_unchecked::<::ruma::events::AnyTimelineEvent>()
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
/// Create a `Raw<AnySyncTimelineEvent>` from arbitrary JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
/// Forwards all arguments to [`serde_json::json`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
#[macro_export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
macro_rules! sync_timeline_event {
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
    ($( $tt:tt )*) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
            .cast_unchecked::<::ruma::events::AnySyncTimelineEvent>()
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
/// Create a `Raw<AnySyncStateEvent>` from arbitrary JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
/// Forwards all arguments to [`serde_json::json`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
#[macro_export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
macro_rules! sync_state_event {
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
    ($( $tt:tt )*) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
            .cast_unchecked::<::ruma::events::AnySyncStateEvent>()
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
/// Create a `Raw<AnyStrippedStateEvent>` from arbitrary JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
/// Forwards all arguments to [`serde_json::json`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
#[macro_export]
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
macro_rules! stripped_state_event {
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
    ($( $tt:tt )*) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
        ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* ))
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
            .unwrap()
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
            .cast_unchecked::<::ruma::events::AnyStrippedStateEvent>()
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
#[cfg(not(target_family = "wasm"))]
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
pub mod mocks;
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
pub mod event_factory;
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
pub mod notification_settings;
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
mod sync_builder;
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
pub mod test_json;
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
pub use self::sync_builder::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
    InvitedRoomBuilder, JoinedRoomBuilder, KnockedRoomBuilder, LeftRoomBuilder,
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
    SyncResponseBuilder, bulk_room_members,
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
pub static ALICE: LazyLock<&UserId> = LazyLock::new(|| user_id!("@alice:server.name"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
pub static BOB: LazyLock<&UserId> = LazyLock::new(|| user_id!("@bob:other.server"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
pub static CAROL: LazyLock<&UserId> = LazyLock::new(|| user_id!("@carol:other.server"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
/// The default room ID for tests.
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
pub static DEFAULT_TEST_ROOM_ID: LazyLock<&RoomId> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
    LazyLock::new(|| room_id!("!SVkFJHzfwvuaIEawgC:localhost"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
/// Build a typed Ruma [`IncomingResponse`] object from a json body.
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
pub fn ruma_response_from_json<ResponseType: IncomingResponse>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    json: &serde_json::Value,
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
) -> ResponseType {
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    let json_bytes = serde_json::to_vec(json).expect("JSON-serialization of response value failed");
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
    let http_response =
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
        Response::builder().status(200).body(json_bytes).expect("Failed to build HTTP response");
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
    ResponseType::try_from_http_response(http_response).expect("Can't parse the response json")
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
/// Serialise a typed Ruma [`OutgoingResponse`] object to JSON.
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
pub fn ruma_response_to_json<ResponseType: OutgoingResponse>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
    response: ResponseType,
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
) -> serde_json::Value {
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
    let http_response: Response<Vec<u8>> =
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
        response.try_into_http_response().expect("Failed to build HTTP response");
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
    let json_bytes = http_response.into_body();
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
    serde_json::from_slice(&json_bytes).expect("Can't parse the response JSON")
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
#[derive(Debug)] // required to be able to return TestResult from #[test] fns
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
pub enum TestError {}
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
// If this was just `T: Debug`, it would conflict with
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
// the `impl From<T> for T` in `std`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
//
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
// Adding a dummy `Display` bound works around this.
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
impl<T: fmt::Display + fmt::Debug> From<T> for TestError {
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
    #[track_caller]
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
    fn from(value: T) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
        panic!("error: {value:?}")
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
pub type TestResult = Result<(), TestError>;
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
/// Compute the sha256 hash of the given bytes and convert it to unpadded
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
/// URL-safe base64.
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
/// This matches the format of event IDs since room version 4, and of room IDs
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
/// since room version 12.
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
pub fn base64_sha256_hash(bytes: &[u8]) -> String {
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
    Base64::<UrlSafe, _>::new(Sha256::digest(bytes)).encode()
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
}