1use crate::config::advanced::auth::AuthorizationRule;
5#[cfg(feature = "experimental")]
6use crate::encryption_scheme::EncryptionScheme;
7use crate::error::Error;
8use crate::error::Error::ParseError;
9use http::HeaderMap;
10use noodles::core::Position;
11use noodles::core::region::Interval as NoodlesInterval;
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14use std::cmp::{Ordering, max, min};
15use std::collections::{HashMap, HashSet};
16use std::fmt::{Debug, Display, Formatter};
17use std::{fmt, io, result};
18use thiserror::Error;
19use tracing::instrument;
20
21pub type Result<T> = result::Result<T, HtsGetError>;
23
24#[derive(JsonSchema, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
26#[serde(rename_all(serialize = "UPPERCASE"), deny_unknown_fields)]
27pub enum Format {
28 #[default]
29 #[serde(alias = "bam", alias = "BAM")]
30 Bam,
31 #[serde(alias = "cram", alias = "CRAM")]
32 Cram,
33 #[serde(alias = "vcf", alias = "VCF")]
34 Vcf,
35 #[serde(alias = "bcf", alias = "BCF")]
36 Bcf,
37}
38
39impl Format {
41 pub fn file_ending(&self) -> &str {
43 match self {
44 Format::Bam => ".bam",
45 Format::Cram => ".cram",
46 Format::Vcf => ".vcf.gz",
47 Format::Bcf => ".bcf",
48 }
49 }
50
51 pub fn fmt_file(&self, id: &str) -> String {
53 format!("{id}{}", self.file_ending())
54 }
55
56 pub fn index_file_ending(&self) -> &str {
58 match self {
59 Format::Bam => ".bam.bai",
60 Format::Cram => ".cram.crai",
61 Format::Vcf => ".vcf.gz.tbi",
62 Format::Bcf => ".bcf.csi",
63 }
64 }
65
66 pub fn fmt_index(&self, id: &str) -> String {
68 format!("{id}{}", self.index_file_ending())
69 }
70
71 pub fn gzi_index_file_ending(&self) -> io::Result<&str> {
73 match self {
74 Format::Bam => Ok(".bam.gzi"),
75 Format::Cram => Err(io::Error::other("CRAM does not support GZI".to_string())),
76 Format::Vcf => Ok(".vcf.gz.gzi"),
77 Format::Bcf => Ok(".bcf.gzi"),
78 }
79 }
80
81 pub fn fmt_gzi(&self, id: &str) -> io::Result<String> {
83 Ok(format!("{id}{}", self.gzi_index_file_ending()?))
84 }
85
86 pub fn is_index(id: &str) -> bool {
88 id.ends_with(".bai")
89 || id.ends_with(".crai")
90 || id.ends_with(".tbi")
91 || id.ends_with(".csi")
92 || id.ends_with(".gzi")
93 }
94}
95
96impl From<Format> for String {
97 fn from(format: Format) -> Self {
98 format.to_string()
99 }
100}
101
102impl Display for Format {
103 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104 match self {
105 Format::Bam => write!(f, "BAM"),
106 Format::Cram => write!(f, "CRAM"),
107 Format::Vcf => write!(f, "VCF"),
108 Format::Bcf => write!(f, "BCF"),
109 }
110 }
111}
112
113#[derive(Copy, Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default)]
115#[serde(rename_all(serialize = "lowercase"), deny_unknown_fields)]
116pub enum Class {
117 #[serde(alias = "header", alias = "HEADER")]
118 Header,
119 #[default]
120 #[serde(alias = "body", alias = "BODY")]
121 Body,
122}
123
124#[derive(JsonSchema, Copy, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
127#[serde(deny_unknown_fields)]
128pub struct Interval {
129 #[serde(skip_serializing_if = "Option::is_none")]
131 start: Option<u32>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 end: Option<u32>,
135}
136
137impl Interval {
138 pub fn contains_interval(&self, other: Interval) -> Option<Self> {
140 match self.constraint_interval(other) {
141 Some(interval) if other == interval => Some(interval),
142 _ => None,
143 }
144 }
145
146 pub fn constraint_interval(&self, other: Interval) -> Option<Self> {
151 let constrain = |self_bound, other_bound, is_start: bool| match (self_bound, other_bound) {
152 (None, None) => None,
153 (None, other_val @ Some(_)) => other_val,
154 (self_val @ Some(_), None) => self_val,
155 (Some(self_val), Some(other_val)) => {
156 if is_start {
157 Some(max(self_val, other_val))
158 } else {
159 Some(min(self_val, other_val))
160 }
161 }
162 };
163
164 let start = constrain(self.start, other.start, true);
165 let end = constrain(self.end, other.end, false);
166
167 let interval = Self::new(start, end);
168 if interval.is_valid() {
169 Some(interval)
170 } else {
171 None
172 }
173 }
174
175 pub fn order_by_range(&self, other: &Interval) -> Ordering {
178 let self_range = self.end.unwrap_or(u32::MAX) - self.start.unwrap_or(u32::MIN);
179 let other_range = other.end.unwrap_or(u32::MAX) - other.start.unwrap_or(u32::MIN);
180
181 self_range.cmp(&other_range)
182 }
183
184 pub fn is_valid(&self) -> bool {
186 if let (Some(ref start), Some(ref end)) = (self.start, self.end)
187 && start >= end
188 {
189 return false;
190 }
191
192 true
193 }
194
195 pub fn contains(&self, value: u32) -> bool {
197 match (self.start.as_ref(), self.end.as_ref()) {
198 (None, None) => true,
199 (None, Some(end)) => value < *end,
200 (Some(start), None) => value >= *start,
201 (Some(start), Some(end)) => value >= *start && value < *end,
202 }
203 }
204
205 #[instrument(level = "trace", skip_all, ret)]
207 pub fn into_one_based(self) -> io::Result<NoodlesInterval> {
208 Ok(match (self.start, self.end) {
209 (None, None) => NoodlesInterval::from(..),
210 (None, Some(end)) => NoodlesInterval::from(..=Self::convert_end(end)?),
211 (Some(start), None) => NoodlesInterval::from(Self::convert_start(start)?..),
212 (Some(start), Some(end)) => {
213 NoodlesInterval::from(Self::convert_start(start)?..=Self::convert_end(end)?)
214 }
215 })
216 }
217
218 pub fn convert_start(start: u32) -> io::Result<Position> {
220 Self::convert_position(start, |value| {
221 value
222 .checked_add(1)
223 .ok_or_else(|| io::Error::other(format!("could not convert {value} to 1-based position.")))
224 })
225 }
226
227 pub fn convert_end(end: u32) -> io::Result<Position> {
229 Self::convert_position(end, Ok)
230 }
231
232 pub fn convert_position<F>(value: u32, convert_fn: F) -> io::Result<Position>
234 where
235 F: FnOnce(u32) -> io::Result<u32>,
236 {
237 let value = convert_fn(value).map(|value| {
238 usize::try_from(value)
239 .map_err(|err| io::Error::other(format!("could not convert `u32` to `usize`: {err}")))
240 })??;
241
242 Position::try_from(value).map_err(|err| {
243 io::Error::other(format!(
244 "could not convert `{value}` into `Position`: {err}"
245 ))
246 })
247 }
248
249 pub fn start(&self) -> Option<u32> {
251 self.start
252 }
253
254 pub fn end(&self) -> Option<u32> {
256 self.end
257 }
258
259 pub fn new(start: Option<u32>, end: Option<u32>) -> Self {
261 Self { start, end }
262 }
263}
264
265#[derive(JsonSchema, Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
267#[serde(rename_all = "UPPERCASE", deny_unknown_fields)]
268pub enum Scheme {
269 #[default]
270 #[serde(alias = "Http", alias = "http")]
271 Http,
272 #[serde(alias = "Https", alias = "https")]
273 Https,
274}
275
276impl Display for Scheme {
277 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
278 match self {
279 Scheme::Http => write!(f, "http"),
280 Scheme::Https => write!(f, "https"),
281 }
282 }
283}
284
285#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
287#[serde(deny_unknown_fields)]
288pub enum TaggedTypeAll {
289 #[serde(alias = "all", alias = "ALL")]
290 All,
291}
292
293#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
295#[serde(untagged, deny_unknown_fields)]
296pub enum Fields {
297 Tagged(TaggedTypeAll),
299 List(HashSet<String>),
301}
302
303impl Default for Fields {
304 fn default() -> Self {
305 Self::Tagged(TaggedTypeAll::All)
306 }
307}
308
309#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
311#[serde(untagged, deny_unknown_fields)]
312pub enum Tags {
313 Tagged(TaggedTypeAll),
315 List(HashSet<String>),
317}
318
319impl Default for Tags {
320 fn default() -> Self {
321 Self::Tagged(TaggedTypeAll::All)
322 }
323}
324
325#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
327#[serde(deny_unknown_fields)]
328pub struct NoTags(pub Option<HashSet<String>>);
329
330#[derive(Clone, Debug, PartialEq, Eq, Default)]
333pub struct SuppressedRequest {
334 matching_rules: Vec<AuthorizationRule>,
335 constrained_interval: Option<Interval>,
336 empty_response: bool,
337 add_hint: bool,
338}
339
340impl SuppressedRequest {
341 pub fn new(
343 matching_rules: Vec<AuthorizationRule>,
344 constrained_interval: Option<Interval>,
345 empty_response: bool,
346 add_hint: bool,
347 ) -> Self {
348 Self {
349 matching_rules,
350 constrained_interval,
351 empty_response,
352 add_hint,
353 }
354 }
355
356 pub fn matching_rules(&self) -> &[AuthorizationRule] {
358 self.matching_rules.as_ref()
359 }
360
361 pub fn take_matching_rules(&mut self) -> Vec<AuthorizationRule> {
363 self.matching_rules.drain(..).collect()
364 }
365
366 pub fn constrained_interval(&self) -> Option<&Interval> {
368 self.constrained_interval.as_ref()
369 }
370
371 pub fn set_constrained_interval(&mut self, interval: Interval) {
373 self.constrained_interval = Some(interval);
374 }
375
376 pub fn set_matching_rules(&mut self, rules: Vec<AuthorizationRule>) {
378 self.matching_rules = rules;
379 }
380
381 pub fn empty_response(&self) -> bool {
384 self.empty_response
385 }
386
387 pub fn add_hint(&self) -> bool {
389 self.add_hint
390 }
391}
392
393#[derive(Clone, Debug, PartialEq, Eq, Default)]
395pub struct Request {
396 path: String,
397 query: HashMap<String, String>,
398 headers: HeaderMap,
399}
400
401impl Request {
402 pub fn new(id: String, query: HashMap<String, String>, headers: HeaderMap) -> Self {
404 Self {
405 path: id,
406 query,
407 headers,
408 }
409 }
410
411 pub fn new_with_id(id: String) -> Self {
413 Self::new(id, Default::default(), Default::default())
414 }
415
416 pub fn path(&self) -> &str {
418 &self.path
419 }
420
421 pub fn query(&self) -> &HashMap<String, String> {
423 &self.query
424 }
425
426 pub fn query_mut(&mut self) -> &mut HashMap<String, String> {
428 &mut self.query
429 }
430
431 pub fn headers(&self) -> &HeaderMap {
433 &self.headers
434 }
435}
436
437#[derive(Clone, Debug, PartialEq, Eq, Default)]
440pub struct Query {
441 id: String,
442 format: Format,
443 class: Class,
444 reference_name: Option<String>,
446 interval: Interval,
448 fields: Fields,
449 tags: Tags,
450 no_tags: NoTags,
451 request: Request,
453 matching_rules: Option<Vec<AuthorizationRule>>,
454 #[cfg(feature = "experimental")]
455 encryption_scheme: Option<EncryptionScheme>,
456}
457
458impl Query {
459 pub fn new(id: impl Into<String>, format: Format, request: Request) -> Self {
461 Self {
462 id: id.into(),
463 format,
464 request,
465 ..Default::default()
466 }
467 }
468
469 pub fn new_with_default_request(id: impl Into<String>, format: Format) -> Self {
471 let id = id.into();
472 Self::new(id.clone(), format, Request::new_with_id(id))
473 }
474
475 pub fn set_id(&mut self, id: impl Into<String>) {
477 self.id = id.into();
478 }
479
480 pub fn with_id(mut self, id: impl Into<String>) -> Self {
482 self.set_id(id);
483 self
484 }
485
486 pub fn with_format(mut self, format: Format) -> Self {
488 self.format = format;
489 self
490 }
491
492 pub fn with_class(mut self, class: Class) -> Self {
494 self.set_class(class);
495 self
496 }
497
498 pub fn set_class(&mut self, class: Class) {
500 self.class = class;
501 }
502
503 pub fn with_reference_name(mut self, reference_name: impl Into<String>) -> Self {
505 self.reference_name = Some(reference_name.into());
506 self
507 }
508
509 pub fn with_start(mut self, start: u32) -> Self {
511 self.interval.start = Some(start);
512 self
513 }
514
515 pub fn with_end(mut self, end: u32) -> Self {
517 self.interval.end = Some(end);
518 self
519 }
520
521 pub fn with_interval(mut self, interval: Interval) -> Self {
523 self.set_interval(interval);
524 self
525 }
526
527 pub fn set_interval(&mut self, interval: Interval) {
529 self.interval = interval;
530 }
531
532 pub fn with_fields(mut self, fields: Fields) -> Self {
534 self.fields = fields;
535 self
536 }
537
538 pub fn with_tags(mut self, tags: Tags) -> Self {
540 self.tags = tags;
541 self
542 }
543
544 pub fn with_no_tags(mut self, no_tags: Vec<impl Into<String>>) -> Self {
546 self.no_tags = NoTags(Some(
547 no_tags.into_iter().map(|field| field.into()).collect(),
548 ));
549 self
550 }
551
552 pub fn id(&self) -> &str {
554 &self.id
555 }
556
557 pub fn format(&self) -> Format {
559 self.format
560 }
561
562 pub fn class(&self) -> Class {
564 self.class
565 }
566
567 pub fn reference_name(&self) -> Option<&str> {
569 self.reference_name.as_deref()
570 }
571
572 pub fn interval(&self) -> Interval {
574 self.interval
575 }
576
577 pub fn fields(&self) -> &Fields {
579 &self.fields
580 }
581
582 pub fn tags(&self) -> &Tags {
584 &self.tags
585 }
586
587 pub fn no_tags(&self) -> &NoTags {
589 &self.no_tags
590 }
591
592 pub fn request(&self) -> &Request {
594 &self.request
595 }
596
597 pub fn set_matching_rules(&mut self, matching_rules: Vec<AuthorizationRule>) {
599 self.matching_rules = Some(matching_rules);
600 }
601
602 #[cfg(feature = "experimental")]
604 pub fn with_encryption_scheme(mut self, encryption_scheme: EncryptionScheme) -> Self {
605 self.encryption_scheme = Some(encryption_scheme);
606 self
607 }
608
609 #[cfg(feature = "experimental")]
611 pub fn encryption_scheme(&self) -> Option<EncryptionScheme> {
612 self.encryption_scheme
613 }
614}
615
616#[derive(Error, Debug, PartialEq, Eq)]
618pub enum HtsGetError {
619 #[error("not found: {0}")]
620 NotFound(String),
621
622 #[error("unsupported Format: {0}")]
623 UnsupportedFormat(String),
624
625 #[error("invalid input: {0}")]
626 InvalidInput(String),
627
628 #[error("invalid range: {0}")]
629 InvalidRange(String),
630
631 #[error("io error: {0}")]
632 IoError(String),
633
634 #[error("parsing error: {0}")]
635 ParseError(String),
636
637 #[error("internal error: {0}")]
638 InternalError(String),
639}
640
641impl HtsGetError {
642 pub fn not_found<S: Into<String>>(message: S) -> Self {
644 Self::NotFound(message.into())
645 }
646
647 pub fn unsupported_format<S: Into<String>>(format: S) -> Self {
649 Self::UnsupportedFormat(format.into())
650 }
651
652 pub fn invalid_input<S: Into<String>>(message: S) -> Self {
654 Self::InvalidInput(message.into())
655 }
656
657 pub fn invalid_range<S: Into<String>>(message: S) -> Self {
659 Self::InvalidRange(message.into())
660 }
661
662 pub fn io_error<S: Into<String>>(message: S) -> Self {
664 Self::IoError(message.into())
665 }
666
667 pub fn parse_error<S: Into<String>>(message: S) -> Self {
669 Self::ParseError(message.into())
670 }
671
672 pub fn internal_error<S: Into<String>>(message: S) -> Self {
674 Self::InternalError(message.into())
675 }
676}
677
678impl From<HtsGetError> for io::Error {
679 fn from(error: HtsGetError) -> Self {
680 Self::other(error)
681 }
682}
683
684impl From<io::Error> for HtsGetError {
685 fn from(err: io::Error) -> Self {
686 Self::io_error(err.to_string())
687 }
688}
689
690#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
692#[serde(deny_unknown_fields)]
693pub struct Headers(HashMap<String, String>);
694
695impl Headers {
696 pub fn new(headers: HashMap<String, String>) -> Self {
697 Self(headers)
698 }
699
700 pub fn with_header<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
703 self.insert(key, value);
704 self
705 }
706
707 pub fn is_empty(&self) -> bool {
708 self.0.is_empty()
709 }
710
711 pub fn insert<K: Into<String>, V: Into<String>>(&mut self, key: K, value: V) {
714 let entry = self.0.entry(key.into()).or_default();
715 if entry.is_empty() {
716 entry.push_str(&value.into());
717 } else {
718 entry.push_str(&format!(", {}", value.into()));
719 }
720 }
721
722 pub fn extend(&mut self, headers: Headers) {
724 self.0.extend(headers.into_inner());
725 }
726
727 pub fn into_inner(self) -> HashMap<String, String> {
729 self.0
730 }
731
732 pub fn as_ref_inner(&self) -> &HashMap<String, String> {
734 &self.0
735 }
736
737 pub fn as_mut_inner(&mut self) -> &mut HashMap<String, String> {
739 &mut self.0
740 }
741}
742
743impl TryFrom<&HeaderMap> for Headers {
744 type Error = Error;
745
746 fn try_from(headers: &HeaderMap) -> result::Result<Self, Self::Error> {
747 headers
748 .iter()
749 .try_fold(Headers::default(), |acc, (key, value)| {
750 Ok(acc.with_header(
751 key.to_string(),
752 value.to_str().map_err(|err| {
753 ParseError(format!("failed to convert header value to string: {err}"))
754 })?,
755 ))
756 })
757 }
758}
759
760#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
762#[serde(deny_unknown_fields)]
763pub struct Url {
764 pub url: String,
765 #[serde(skip_serializing_if = "Option::is_none")]
766 pub headers: Option<Headers>,
767 #[serde(skip_serializing_if = "Option::is_none")]
768 pub class: Option<Class>,
769}
770
771impl Url {
772 pub fn new<S: Into<String>>(url: S) -> Self {
774 Self {
775 url: url.into(),
776 headers: None,
777 class: None,
778 }
779 }
780
781 pub fn add_headers(mut self, headers: Headers) -> Self {
783 if !headers.is_empty() {
784 self
785 .headers
786 .get_or_insert_with(Headers::default)
787 .extend(headers);
788 }
789
790 self
791 }
792
793 pub fn with_headers(mut self, headers: Headers) -> Self {
795 self.headers = Some(headers).filter(|h| !h.is_empty());
796 self
797 }
798
799 pub fn set_class(mut self, class: Option<Class>) -> Self {
801 self.class = class;
802 self
803 }
804
805 pub fn with_class(self, class: Class) -> Self {
807 self.set_class(Some(class))
808 }
809}
810
811#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
813#[serde(deny_unknown_fields)]
814pub struct JsonResponse {
815 pub htsget: Response,
816}
817
818impl JsonResponse {
819 pub fn new(htsget: Response) -> Self {
821 Self { htsget }
822 }
823
824 #[cfg(feature = "experimental")]
825 pub fn with_allowed(mut self, allowed: Option<Vec<AuthorizationRule>>) -> Self {
827 self.htsget = self.htsget.with_allowed(allowed);
828 self
829 }
830}
831
832impl From<Response> for JsonResponse {
833 fn from(htsget: Response) -> Self {
834 Self::new(htsget)
835 }
836}
837
838#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
840#[serde(deny_unknown_fields)]
841pub struct Response {
842 pub format: Format,
843 pub urls: Vec<Url>,
844 #[cfg(feature = "experimental")]
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub allowed: Option<Vec<AuthorizationRule>>,
847}
848
849impl Response {
850 pub fn new(format: Format, urls: Vec<Url>) -> Self {
852 Self {
853 format,
854 urls,
855 #[cfg(feature = "experimental")]
856 allowed: None,
857 }
858 }
859
860 #[cfg(feature = "experimental")]
861 pub fn with_allowed(mut self, allowed: Option<Vec<AuthorizationRule>>) -> Self {
863 self.allowed = allowed;
864 self
865 }
866}
867
868#[cfg(test)]
869mod tests {
870 use std::collections::{HashMap, HashSet};
871 use std::str::FromStr;
872
873 use http::{HeaderMap, HeaderName, HeaderValue};
874 use serde_json::{json, to_value};
875
876 use crate::types::{
877 Class, Fields, Format, Headers, HtsGetError, Interval, NoTags, Query, Response, TaggedTypeAll,
878 Tags, Url,
879 };
880
881 #[test]
882 fn interval_contains() {
883 let interval = Interval {
884 start: Some(0),
885 end: Some(10),
886 };
887 assert!(interval.contains(9));
888 }
889
890 #[test]
891 fn interval_not_contains() {
892 let interval = Interval {
893 start: Some(0),
894 end: Some(10),
895 };
896 assert!(!interval.contains(10));
897 }
898
899 #[test]
900 fn interval_contains_start_not_present() {
901 let interval = Interval {
902 start: None,
903 end: Some(10),
904 };
905 assert!(interval.contains(9));
906 }
907
908 #[test]
909 fn interval_not_contains_start_not_present() {
910 let interval = Interval {
911 start: None,
912 end: Some(10),
913 };
914 assert!(!interval.contains(10));
915 }
916
917 #[test]
918 fn interval_contains_end_not_present() {
919 let interval = Interval {
920 start: Some(1),
921 end: None,
922 };
923 assert!(interval.contains(9));
924 }
925
926 #[test]
927 fn interval_not_contains_end_not_present() {
928 let interval = Interval {
929 start: Some(1),
930 end: None,
931 };
932 assert!(!interval.contains(0));
933 }
934
935 #[test]
936 fn interval_contains_both_not_present() {
937 let interval = Interval {
938 start: None,
939 end: None,
940 };
941 assert!(interval.contains(0));
942 }
943
944 #[test]
945 fn interval_constrain_and_contains() {
946 let outer = Interval::new(Some(10), Some(20));
947 let inner = Interval::new(Some(12), Some(18));
948 assert_eq!(
949 outer.constraint_interval(inner),
950 Some(Interval::new(Some(12), Some(18)))
951 );
952 assert_eq!(
953 outer.contains_interval(inner),
954 Some(Interval::new(Some(12), Some(18)))
955 );
956
957 let outer = Interval::new(Some(10), Some(20));
958 let inner = Interval::new(Some(10), Some(20));
959 assert_eq!(
960 outer.constraint_interval(inner),
961 Some(Interval::new(Some(10), Some(20)))
962 );
963 assert_eq!(
964 outer.contains_interval(inner),
965 Some(Interval::new(Some(10), Some(20)))
966 );
967
968 let outer = Interval::new(Some(10), Some(20));
969 let inner = Interval::new(Some(5), Some(15));
970 assert_eq!(
971 outer.constraint_interval(inner),
972 Some(Interval::new(Some(10), Some(15)))
973 );
974 assert_eq!(outer.contains_interval(inner), None);
975
976 let outer = Interval::new(Some(10), Some(20));
977 let inner = Interval::new(Some(15), Some(25));
978 assert_eq!(
979 outer.constraint_interval(inner),
980 Some(Interval::new(Some(15), Some(20)))
981 );
982 assert_eq!(outer.contains_interval(inner), None);
983
984 let outer = Interval::new(None, Some(20));
985 let inner = Interval::new(Some(10), Some(15));
986 assert_eq!(
987 outer.constraint_interval(inner),
988 Some(Interval::new(Some(10), Some(15)))
989 );
990 assert_eq!(
991 outer.contains_interval(inner),
992 Some(Interval::new(Some(10), Some(15)))
993 );
994
995 let outer = Interval::new(Some(10), None);
996 let inner = Interval::new(Some(15), Some(25));
997 assert_eq!(
998 outer.constraint_interval(inner),
999 Some(Interval::new(Some(15), Some(25)))
1000 );
1001 assert_eq!(
1002 outer.contains_interval(inner),
1003 Some(Interval::new(Some(15), Some(25)))
1004 );
1005
1006 let outer = Interval::new(None, None);
1007 let inner = Interval::new(Some(10), Some(20));
1008 assert_eq!(
1009 outer.constraint_interval(inner),
1010 Some(Interval::new(Some(10), Some(20)))
1011 );
1012 assert_eq!(
1013 outer.contains_interval(inner),
1014 Some(Interval::new(Some(10), Some(20)))
1015 );
1016
1017 let outer = Interval::new(Some(10), Some(20));
1018 let inner = Interval::new(None, Some(15));
1019 assert_eq!(
1020 outer.constraint_interval(inner),
1021 Some(Interval::new(Some(10), Some(15)))
1022 );
1023 assert_eq!(outer.contains_interval(inner), None);
1024
1025 let outer = Interval::new(Some(10), Some(20));
1026 let inner = Interval::new(Some(15), None);
1027 assert_eq!(
1028 outer.constraint_interval(inner),
1029 Some(Interval::new(Some(15), Some(20)))
1030 );
1031 assert_eq!(outer.contains_interval(inner), None);
1032
1033 let outer = Interval::new(None, None);
1034 let inner = Interval::new(None, None);
1035 assert_eq!(
1036 outer.constraint_interval(inner),
1037 Some(Interval::new(None, None))
1038 );
1039 assert_eq!(
1040 outer.contains_interval(inner),
1041 Some(Interval::new(None, None))
1042 );
1043 }
1044
1045 #[test]
1046 fn htsget_error_not_found() {
1047 let result = HtsGetError::not_found("error");
1048 assert!(matches!(result, HtsGetError::NotFound(message) if message == "error"));
1049 }
1050
1051 #[test]
1052 fn htsget_error_unsupported_format() {
1053 let result = HtsGetError::unsupported_format("error");
1054 assert!(matches!(result, HtsGetError::UnsupportedFormat(message) if message == "error"));
1055 }
1056
1057 #[test]
1058 fn htsget_error_invalid_input() {
1059 let result = HtsGetError::invalid_input("error");
1060 assert!(matches!(result, HtsGetError::InvalidInput(message) if message == "error"));
1061 }
1062
1063 #[test]
1064 fn htsget_error_invalid_range() {
1065 let result = HtsGetError::invalid_range("error");
1066 assert!(matches!(result, HtsGetError::InvalidRange(message) if message == "error"));
1067 }
1068
1069 #[test]
1070 fn htsget_error_io_error() {
1071 let result = HtsGetError::io_error("error");
1072 assert!(matches!(result, HtsGetError::IoError(message) if message == "error"));
1073 }
1074
1075 #[test]
1076 fn htsget_error_parse_error() {
1077 let result = HtsGetError::parse_error("error");
1078 assert!(matches!(result, HtsGetError::ParseError(message) if message == "error"));
1079 }
1080
1081 #[test]
1082 fn htsget_error_internal_error() {
1083 let result = HtsGetError::internal_error("error");
1084 assert!(matches!(result, HtsGetError::InternalError(message) if message == "error"));
1085 }
1086
1087 #[test]
1088 fn query_new() {
1089 let result = Query::new_with_default_request("NA12878", Format::Bam);
1090 assert_eq!(result.id(), "NA12878");
1091 }
1092
1093 #[test]
1094 fn query_with_format() {
1095 let result = Query::new_with_default_request("NA12878", Format::Bam);
1096 assert_eq!(result.format(), Format::Bam);
1097 }
1098
1099 #[test]
1100 fn query_with_class() {
1101 let result = Query::new_with_default_request("NA12878", Format::Bam).with_class(Class::Header);
1102 assert_eq!(result.class(), Class::Header);
1103 }
1104
1105 #[test]
1106 fn query_with_reference_name() {
1107 let result =
1108 Query::new_with_default_request("NA12878", Format::Bam).with_reference_name("chr1");
1109 assert_eq!(result.reference_name(), Some("chr1"));
1110 }
1111
1112 #[test]
1113 fn query_with_start() {
1114 let result = Query::new_with_default_request("NA12878", Format::Bam).with_start(0);
1115 assert_eq!(result.interval().start(), Some(0));
1116 }
1117
1118 #[test]
1119 fn query_with_end() {
1120 let result = Query::new_with_default_request("NA12878", Format::Bam).with_end(0);
1121 assert_eq!(result.interval().end(), Some(0));
1122 }
1123
1124 #[test]
1125 fn query_with_fields() {
1126 let result = Query::new_with_default_request("NA12878", Format::Bam).with_fields(Fields::List(
1127 HashSet::from_iter(vec!["QNAME".to_string(), "FLAG".to_string()]),
1128 ));
1129 assert_eq!(
1130 result.fields(),
1131 &Fields::List(HashSet::from_iter(vec![
1132 "QNAME".to_string(),
1133 "FLAG".to_string()
1134 ]))
1135 );
1136 }
1137
1138 #[test]
1139 fn query_with_tags() {
1140 let result = Query::new_with_default_request("NA12878", Format::Bam)
1141 .with_tags(Tags::Tagged(TaggedTypeAll::All));
1142 assert_eq!(result.tags(), &Tags::Tagged(TaggedTypeAll::All));
1143 }
1144
1145 #[test]
1146 fn query_with_no_tags() {
1147 let result =
1148 Query::new_with_default_request("NA12878", Format::Bam).with_no_tags(vec!["RG", "OQ"]);
1149 assert_eq!(
1150 result.no_tags(),
1151 &NoTags(Some(HashSet::from_iter(vec![
1152 "RG".to_string(),
1153 "OQ".to_string()
1154 ])))
1155 );
1156 }
1157
1158 #[test]
1159 fn format_from_bam() {
1160 let result = String::from(Format::Bam);
1161 assert_eq!(result, "BAM");
1162 }
1163
1164 #[test]
1165 fn format_from_cram() {
1166 let result = String::from(Format::Cram);
1167 assert_eq!(result, "CRAM");
1168 }
1169
1170 #[test]
1171 fn format_from_vcf() {
1172 let result = String::from(Format::Vcf);
1173 assert_eq!(result, "VCF");
1174 }
1175
1176 #[test]
1177 fn format_from_bcf() {
1178 let result = String::from(Format::Bcf);
1179 assert_eq!(result, "BCF");
1180 }
1181
1182 #[test]
1183 fn headers_with_header() {
1184 let header = Headers::new(HashMap::new()).with_header("Range", "bytes=0-1023");
1185 let result = header.0.get("Range");
1186 assert_eq!(result, Some(&"bytes=0-1023".to_string()));
1187 }
1188
1189 #[test]
1190 fn headers_is_empty() {
1191 assert!(Headers::new(HashMap::new()).is_empty());
1192 }
1193
1194 #[test]
1195 fn headers_insert() {
1196 let mut header = Headers::new(HashMap::new());
1197 header.insert("Range", "bytes=0-1023");
1198 let result = header.0.get("Range");
1199 assert_eq!(result, Some(&"bytes=0-1023".to_string()));
1200 }
1201
1202 #[test]
1203 fn headers_extend() {
1204 let mut headers = Headers::new(HashMap::new());
1205 headers.insert("Range", "bytes=0-1023");
1206
1207 let mut extend_with = Headers::new(HashMap::new());
1208 extend_with.insert("header", "value");
1209
1210 headers.extend(extend_with);
1211
1212 let result = headers.0.get("Range");
1213 assert_eq!(result, Some(&"bytes=0-1023".to_string()));
1214
1215 let result = headers.0.get("header");
1216 assert_eq!(result, Some(&"value".to_string()));
1217 }
1218
1219 #[test]
1220 fn headers_multiple_values() {
1221 let headers = Headers::new(HashMap::new())
1222 .with_header("Range", "bytes=0-1023")
1223 .with_header("Range", "bytes=1024-2047");
1224 let result = headers.0.get("Range");
1225
1226 assert_eq!(result, Some(&"bytes=0-1023, bytes=1024-2047".to_string()));
1227 }
1228
1229 #[test]
1230 fn headers_try_from_header_map() {
1231 let mut headers = HeaderMap::new();
1232 headers.append(
1233 HeaderName::from_str("Range").unwrap(),
1234 HeaderValue::from_str("bytes=0-1023").unwrap(),
1235 );
1236 headers.append(
1237 HeaderName::from_str("Range").unwrap(),
1238 HeaderValue::from_str("bytes=1024-2047").unwrap(),
1239 );
1240 headers.append(
1241 HeaderName::from_str("Range").unwrap(),
1242 HeaderValue::from_str("bytes=2048-3071, bytes=3072-4095").unwrap(),
1243 );
1244 let headers: Headers = (&headers).try_into().unwrap();
1245
1246 let result = headers.0.get("range");
1247 assert_eq!(
1248 result,
1249 Some(&"bytes=0-1023, bytes=1024-2047, bytes=2048-3071, bytes=3072-4095".to_string())
1250 );
1251 }
1252
1253 #[test]
1254 fn serialize_headers() {
1255 let headers = Headers::new(HashMap::new())
1256 .with_header("Range", "bytes=0-1023")
1257 .with_header("Range", "bytes=1024-2047");
1258
1259 let result = to_value(headers).unwrap();
1260 assert_eq!(
1261 result,
1262 json!({
1263 "Range" : "bytes=0-1023, bytes=1024-2047"
1264 })
1265 );
1266 }
1267
1268 #[test]
1269 fn url_with_headers() {
1270 let result = Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==")
1271 .with_headers(Headers::new(HashMap::new()));
1272 assert_eq!(result.headers, None);
1273 }
1274
1275 #[test]
1276 fn url_add_headers() {
1277 let mut headers = Headers::new(HashMap::new());
1278 headers.insert("Range", "bytes=0-1023");
1279
1280 let mut extend_with = Headers::new(HashMap::new());
1281 extend_with.insert("header", "value");
1282
1283 let result = Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==")
1284 .with_headers(headers)
1285 .add_headers(extend_with);
1286
1287 let expected_headers = Headers::new(HashMap::new())
1288 .with_header("Range", "bytes=0-1023")
1289 .with_header("header", "value");
1290
1291 assert_eq!(result.headers, Some(expected_headers));
1292 }
1293
1294 #[test]
1295 fn url_with_class() {
1296 let result =
1297 Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==").with_class(Class::Header);
1298 assert_eq!(result.class, Some(Class::Header));
1299 }
1300
1301 #[test]
1302 fn url_set_class() {
1303 let result =
1304 Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==").set_class(Some(Class::Header));
1305 assert_eq!(result.class, Some(Class::Header));
1306 }
1307
1308 #[test]
1309 fn url_new() {
1310 let result = Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==");
1311 assert_eq!(result.url, "data:application/vnd.ga4gh.bam;base64,QkFNAQ==");
1312 assert_eq!(result.headers, None);
1313 assert_eq!(result.class, None);
1314 }
1315
1316 #[test]
1317 fn response_new() {
1318 let result = Response::new(
1319 Format::Bam,
1320 vec![Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==")],
1321 );
1322 assert_eq!(result.format, Format::Bam);
1323 assert_eq!(
1324 result.urls,
1325 vec![Url::new("data:application/vnd.ga4gh.bam;base64,QkFNAQ==")]
1326 );
1327 }
1328}