Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/hgvs/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ pub enum HGVSError {
"Variant Validator did not accept submitted HGVS {hgvs}. Validation warnings: {problems:?}"
)]
InvalidHgvs { hgvs: String, problems: Vec<String> },
#[error(
"Could not find corresponding HgvsVariant object in the MockHGVSClient for unvalidated hgvs {unvalidated_hgvs}."
)]
MockClient { unvalidated_hgvs: String },
#[error("Hgvs string {hgvs} not accepted due to format problem: {problem}.")]
HgvsFormatNotAccepted { hgvs: String, problem: String },
#[error(
Expand Down
175 changes: 175 additions & 0 deletions src/hgvs/mock_hgvs_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use crate::hgvs::{HGVSData, HGVSError, HgvsVariant};
use std::collections::HashMap;

/// A Mock client for the HGVS interface.
///
/// This struct is intended for use in unit testing. Instead of making live HTTP
/// requests to the VariantValidator API, it serves data from an internal `HashMap`.
/// This allows for deterministic testing of components that rely on `HGVSData`.
#[derive(Debug)]
pub struct MockHGVSClient {
hgvs_variants: HashMap<String, HgvsVariant>,
}

impl MockHGVSClient {
pub fn new(hgvs_variants: HashMap<String, HgvsVariant>) -> MockHGVSClient {
MockHGVSClient { hgvs_variants }
}
}

impl HGVSData for MockHGVSClient {
fn request_and_validate_hgvs(&self, unvalidated_hgvs: &str) -> Result<HgvsVariant, HGVSError> {
self.hgvs_variants
.get(unvalidated_hgvs)
.cloned()
.ok_or(HGVSError::MockClient {
unvalidated_hgvs: unvalidated_hgvs.to_string(),
})
}
}

impl Default for MockHGVSClient {
fn default() -> Self {
let mut hgvs_variants = HashMap::new();

//coding autosomal variant
hgvs_variants.insert(
"NM_001173464.1:c.2860C>T".to_string(),
HgvsVariant::new(
"hg38",
"chr12",
39332405,
"G",
"A",
"KIF21A",
"HGNC:19349",
"NM_001173464.1",
"c.2860C>T",
"NM_001173464.1:c.2860C>T",
"NC_000012.12:g.39332405G>A",
Some("NP_001166935.1:p.(Arg954Trp)"),
),
);

//another coding autosomal variant
hgvs_variants.insert(
"NM_001173464.1:c.2861G>A".to_string(),
HgvsVariant::new(
"hg38",
"chr12",
39332404,
"C",
"T",
"KIF21A",
"HGNC:19349",
"NM_001173464.1",
"c.2861G>A",
"NM_001173464.1:c.2861G>A",
"NC_000012.12:g.39332404C>T",
Some("NP_001166935.1:p.(Arg954Gln)"),
),
);

//coding x variant
hgvs_variants.insert(
"NM_000132.4:c.3637A>T".to_string(),
HgvsVariant::new(
"hg38",
"chrX",
154930153,
"T",
"A",
"F8",
"HGNC:3546",
"NM_000132.4",
"c.3637A>T",
"NM_000132.4:c.3637A>T",
"NC_000023.11:g.154930153T>A",
Some("NP_000123.1:p.(Ile1213Phe)"),
),
);

//non-coding variant
hgvs_variants.insert(
"NR_002196.1:n.601G>T".to_string(),
HgvsVariant::new(
"hg38",
"chr11",
1997235,
"C",
"A",
"H19",
"HGNC:4713",
"NR_002196.1",
"n.601G>T",
"NR_002196.1:n.601G>T",
"NC_000011.10:g.1997235C>A",
None::<&str>,
),
);

//another non-coding variant
hgvs_variants.insert(
"NR_002196.1:n.602C>T".to_string(),
HgvsVariant::new(
"hg38",
"chr11",
1997234,
"G",
"A",
"H19",
"HGNC:4713",
"NR_002196.1",
"n.601C>T",
"NR_002196.1:n.602C>T",
"NC_000011.10:g.1997234G>A",
None::<&str>,
),
);

//mitochondrial variant
hgvs_variants.insert(
"NC_012920.1:m.616T>C".to_string(),
HgvsVariant::new(
"hg38",
"chrM",
616,
"T",
"C",
"",
"",
"NC_012920.1",
"m.616T>C",
"NC_012920.1:m.616T>C",
"NC_012920.1:m.616T>C",
None::<&str>,
),
);

MockHGVSClient::new(hgvs_variants)
}
}

#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;

#[rstest]
fn test_validate_hgvs_success() {
let mock = MockHGVSClient::default();

let unvalidated_hgvs = "NM_001173464.1:c.2860C>T";

let hgvs_variant = mock.request_and_validate_hgvs(unvalidated_hgvs).unwrap();
assert_eq!(hgvs_variant.transcript_hgvs(), unvalidated_hgvs);
}

#[rstest]
fn test_request_gene_data_not_found() {
let mock = MockHGVSClient::default();

let invalid_hgvs = "INVALID_HGVS";
assert!(mock.request_and_validate_hgvs(invalid_hgvs).is_err());
}
}
6 changes: 6 additions & 0 deletions src/hgvs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
//!
//! A cached implementation of the HGVSData trait. The HgvsVariant objects will be cached and can thereafter be accessed without an API call.
//!
//! # [`MockHGVSClient`]
//!
//! A mocked implementation of the HGVSData trait for tests and CI.
//!
//! # [`AlleleCount`]
//!
//! An enum with two variants Single and Double. This is used for create a VariantInterpretation from a HgvsVariant object.
Expand Down Expand Up @@ -81,6 +85,7 @@ pub use enums::ChromosomalSex;
pub use error::HGVSError;
pub use hgvs_client::HGVSClient;
pub use hgvs_variant::HgvsVariant;
pub use mock_hgvs_client::MockHGVSClient;
pub use traits::HGVSData;

mod cached_hgvs_client;
Expand All @@ -89,5 +94,6 @@ mod error;
mod hgvs_client;
mod hgvs_variant;
mod json_schema;
mod mock_hgvs_client;
mod traits;
mod utils;
Loading