Skip to content

Commit d510ace

Browse files
authored
Add additional tests for uri module (payjoin#578)
This expands the test coverage for the uri module covering all mutants that currently exist.
2 parents f5982cf + 86f9208 commit d510ace

File tree

3 files changed

+88
-11
lines changed

3 files changed

+88
-11
lines changed

payjoin-test-utils/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ pub async fn wait_for_service_ready(
253253
}
254254

255255
pub static EXAMPLE_URL: Lazy<Url> =
256-
Lazy::new(|| Url::parse("https://relay.com").expect("invalid URL"));
256+
Lazy::new(|| Url::parse("https://example.com").expect("invalid URL"));
257257

258258
pub const KEY_ID: KeyId = 1;
259259
pub const KEM: Kem = Kem::K256Sha256;

payjoin/src/uri/mod.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ impl bitcoin_uri::de::DeserializationState<'_> for DeserializationState {
207207
mod tests {
208208
use std::convert::TryFrom;
209209

210+
use bitcoin_uri::SerializeParams;
211+
210212
use super::*;
211213

212214
#[test]
@@ -269,10 +271,48 @@ mod tests {
269271

270272
#[test]
271273
fn test_unsupported() {
272-
assert!(!Uri::try_from("bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX")
274+
assert!(
275+
!Uri::try_from("bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX")
276+
.unwrap()
277+
.extras
278+
.pj_is_supported(),
279+
"Uri expected a failure with missing pj extras, but it succeeded"
280+
);
281+
}
282+
283+
#[test]
284+
fn test_supported() {
285+
assert!(
286+
Uri::try_from(
287+
"bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=0.01\
288+
&pjos=0&pj=HTTPS://EXAMPLE.COM/\
289+
%23OH1QYPM5JXYNS754Y4R45QWE336QFX6ZR8DQGVQCULVZTV20TFVEYDMFQC"
290+
)
273291
.unwrap()
274292
.extras
275-
.pj_is_supported());
293+
.pj_is_supported(),
294+
"Uri expected a success with a well formatted pj extras, but it failed"
295+
);
296+
}
297+
298+
#[test]
299+
fn test_pj_param_unknown() {
300+
use bitcoin_uri::de::DeserializationState as _;
301+
let uri = "bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?pjos=1&pj=HTTPS://EXAMPLE.COM/\
302+
%23OH1QYPM5JXYNS754Y4R45QWE336QFX6ZR8DQGVQCULVZTV20TFVEYDMFQC";
303+
let pjuri = Uri::try_from(uri).unwrap().assume_checked().check_pj_supported().unwrap();
304+
let serialized_params = pjuri.extras.serialize_params();
305+
let pjos_key = serialized_params.clone().next().expect("Missing pjos key").0;
306+
let pj_key = serialized_params.clone().next().expect("Missing pj key").0;
307+
308+
let state = DeserializationState::default();
309+
310+
assert!(state.is_param_known(pjos_key), "The pjos key should match 'pjos', but it failed");
311+
assert!(state.is_param_known(pj_key), "The pj key should match 'pj', but it failed");
312+
assert!(
313+
!state.is_param_known("unknown_param"),
314+
"An unknown_param should not match 'pj' or 'pjos'"
315+
);
276316
}
277317

278318
#[test]

payjoin/src/uri/url_ext.rs

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,26 +225,29 @@ impl std::error::Error for ParseReceiverPubkeyParamError {
225225

226226
#[cfg(test)]
227227
mod tests {
228-
use payjoin_test_utils::BoxError;
228+
use payjoin_test_utils::{BoxError, EXAMPLE_URL};
229229

230230
use super::*;
231231
use crate::{Uri, UriExt};
232232

233233
#[test]
234234
fn test_ohttp_get_set() {
235-
let mut url = Url::parse("https://example.com").unwrap();
235+
let mut url = EXAMPLE_URL.clone();
236236

237237
let serialized = "OH1QYPM5JXYNS754Y4R45QWE336QFX6ZR8DQGVQCULVZTV20TFVEYDMFQC";
238238
let ohttp_keys = OhttpKeys::from_str(serialized).unwrap();
239239
url.set_ohttp(ohttp_keys.clone());
240240

241241
assert_eq!(url.fragment(), Some(serialized));
242-
assert_eq!(url.ohttp().unwrap(), ohttp_keys);
242+
assert_eq!(
243+
url.ohttp().expect("Ohttp keys have been set but are missing on get"),
244+
ohttp_keys
245+
);
243246
}
244247

245248
#[test]
246249
fn test_errors_when_parsing_ohttp() {
247-
let missing_ohttp_url = Url::parse("https://example.com").unwrap();
250+
let missing_ohttp_url = EXAMPLE_URL.clone();
248251
assert!(matches!(
249252
missing_ohttp_url.ohttp(),
250253
Err(ParseOhttpKeysParamError::MissingOhttpKeys)
@@ -261,19 +264,19 @@ mod tests {
261264

262265
#[test]
263266
fn test_exp_get_set() {
264-
let mut url = Url::parse("https://example.com").unwrap();
267+
let mut url = EXAMPLE_URL.clone();
265268

266269
let exp_time =
267270
std::time::SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1720547781);
268271
url.set_exp(exp_time);
269272
assert_eq!(url.fragment(), Some("EX1C4UC6ES"));
270273

271-
assert_eq!(url.exp().unwrap(), exp_time);
274+
assert_eq!(url.exp().expect("Expiry has been set but is missing on get"), exp_time);
272275
}
273276

274277
#[test]
275278
fn test_errors_when_parsing_exp() {
276-
let missing_exp_url = Url::parse("http://example.com").unwrap();
279+
let missing_exp_url = EXAMPLE_URL.clone();
277280
assert!(matches!(missing_exp_url.exp(), Err(ParseExpParamError::MissingExp)));
278281

279282
let invalid_bech32_exp_url =
@@ -290,7 +293,41 @@ mod tests {
290293
// Not enough data to decode into a u32
291294
let invalid_timestamp_exp_url =
292295
Url::parse("http://example.com?pj=https://test-payjoin-url#EX10").unwrap();
293-
assert!(matches!(invalid_timestamp_exp_url.exp(), Err(ParseExpParamError::InvalidExp(_))))
296+
assert!(matches!(invalid_timestamp_exp_url.exp(), Err(ParseExpParamError::InvalidExp(_))));
297+
}
298+
299+
#[test]
300+
fn test_errors_when_parsing_receiver_pubkey() {
301+
let missing_receiver_pubkey_url = EXAMPLE_URL.clone();
302+
assert!(matches!(
303+
missing_receiver_pubkey_url.receiver_pubkey(),
304+
Err(ParseReceiverPubkeyParamError::MissingPubkey)
305+
));
306+
307+
let invalid_bech32_receiver_pubkey_url =
308+
Url::parse("http://example.com?pj=https://test-payjoin-url#RK1invalid_bech_32")
309+
.unwrap();
310+
assert!(matches!(
311+
invalid_bech32_receiver_pubkey_url.receiver_pubkey(),
312+
Err(ParseReceiverPubkeyParamError::DecodeBech32(_))
313+
));
314+
315+
// Since the HRP is everything to the left of the right-most separator, the invalid url in
316+
// this test would have it's HRP being parsed as RK101 instead of the expected RK1
317+
let invalid_hrp_receiver_pubkey_url =
318+
Url::parse("http://example.com?pj=https://test-payjoin-url#RK101").unwrap();
319+
assert!(matches!(
320+
invalid_hrp_receiver_pubkey_url.receiver_pubkey(),
321+
Err(ParseReceiverPubkeyParamError::InvalidHrp(_))
322+
));
323+
324+
// Not enough data to decode into a u32
325+
let invalid_receiver_pubkey_url =
326+
Url::parse("http://example.com?pj=https://test-payjoin-url#RK10").unwrap();
327+
assert!(matches!(
328+
invalid_receiver_pubkey_url.receiver_pubkey(),
329+
Err(ParseReceiverPubkeyParamError::InvalidPubkey(_))
330+
));
294331
}
295332

296333
#[test]

0 commit comments

Comments
 (0)