1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate*;
use HeaderMap;
use HashMap;
use debug;
use Message;
pub use crate*;
pub use crate*;
pub use crate*;
/// Re-exports every part of the public API for ease of use.
/// Anything that implements `Match` can be used to constrain when a [`Mock`] is activated.
///
/// This type is more complicated than the `Match` trait in wiremock because of the differences in
/// websocket connections and the data interchanged. As such there are 3 domains where we can match
/// a request:
///
/// 1. At the initial request - headers, URL, query parameters
/// 2. A single websocket message in isolation
/// 3. Behaviour over the stream of messages
///
/// Point 2. is actually a subset of 3. but it is much simpler hence it's own method. Because a
/// `Match` may not be applied in all 3 domains there is the ability for it to return `None`. For
/// example, if we have a [`CloseFrameReceivedMatcher`](crate::matchers::CloseFrameReceivedMatcher)
/// this only checks if a close frame is received, every other component of the request is irrelevant
/// and when checking them will return a `None`. Likewise the `PatchExactMatcher` can only return
/// `Some(true)` when we look at the initial request parameters. Once the body is being received
/// it's irrelevant.
///
/// # Temporal Matching
///
/// Here we care about the state of the stream of messages. When `Match::temporal_match` is called
/// it will be after a message is received. [`MatchState::last`](crate::match_state::MatchState::last)
/// will return the most recent message.
///
/// To avoid storing all messages if your `Match` implementation will require access to a message
/// in future passes use [`MatchState::keep_message`](crate::match_state::MatchState::keep_message)
/// to retain the message in the buffer. Likewise when your `Match` doesn't want the message anymore call
/// [`MatchState::forget_message`](crate::match_state::MatchState::forget_message).
///
/// One thing to note is because unary message matching is a special case of temporal message
/// handling the default temporal matcher calls the unary method with
/// [`MatchState::last`](crate::match_state::MatchState::last) as the argument.
///
/// ## Note
///
/// If you call [`MatchState::forget_message`](crate::match_state::MatchState::forget_message)
/// twice for the same index in the same `Match` instance during a connection you may evict a
/// message which another `Match` required for temporal checking. Take care you don't over-forget
/// messages to avoid tests failing erroneous (or worse passing eroneously).
///
/// This is done in part to allow for reduced resource usage (and ease of implementation).
///
/// # Implementing
///
/// [`Match::unary_match`] isn't called directly by wiremocket which instead relies on the default
/// implementation of [`Match::temporal_match`]. It is expected that a `Match` is implemented over
/// 1 of the listed domains.
///
/// If a `Match` returns `Some(true)` this is stored as part of the request state and failure for
/// every `Match` to return this during a request results in the verify check failing. Therefore
/// having a `Match` which checks multiple things that are independent of each other is likely to
/// lead to incorrect test results.
///
/// Simple implementation example on making a `Match` which checks if a `Ping` is received during
/// the session:
///
/// ```rust
/// use wiremocket::Match;
/// use tungstenite::Message;
///
/// pub struct PingOccursMatcher;
///
/// impl Match for PingOccursMatcher {
/// fn unary_match(&self, message: &Message) -> Option<bool> {
/// match message {
/// Message::Ping(_) => Some(true),
/// _ => None,
/// }
/// }
/// }
/// ```