1use htsget_config::types::{Class, Headers, Url};
2use http::HeaderMap;
3use std::cmp::Ordering;
4use std::fmt;
5use std::fmt::{Display, Formatter};
6use tracing::instrument;
7
8#[derive(Debug, PartialEq, Eq)]
10pub enum DataBlock {
11 Range(BytesPosition),
12 Data(Vec<u8>, Option<Class>),
13}
14
15impl DataBlock {
16 pub fn from_bytes_positions(positions: Vec<BytesPosition>) -> Vec<Self> {
18 BytesPosition::merge_all(positions)
19 .into_iter()
20 .map(DataBlock::Range)
21 .collect()
22 }
23
24 pub fn update_classes(blocks: Vec<Self>) -> Vec<Self> {
27 if blocks.iter().all(|block| match block {
28 DataBlock::Range(range) => range.class.is_some(),
29 DataBlock::Data(_, class) => class.is_some(),
30 }) {
31 blocks
32 } else {
33 blocks
34 .into_iter()
35 .map(|block| match block {
36 DataBlock::Range(range) => DataBlock::Range(range.set_class(None)),
37 DataBlock::Data(data, _) => DataBlock::Data(data, None),
38 })
39 .collect()
40 }
41 }
42}
43
44#[derive(Clone, Debug, Default, PartialEq, Eq)]
50pub struct BytesPosition {
51 pub(crate) start: Option<u64>,
52 pub(crate) end: Option<u64>,
53 pub(crate) class: Option<Class>,
54}
55
56#[derive(Clone, Debug, Default, PartialEq, Eq)]
58pub struct BytesRange {
59 start: Option<u64>,
60 end: Option<u64>,
61}
62
63impl From<&BytesRange> for String {
64 fn from(ranges: &BytesRange) -> Self {
65 if ranges.start.is_none() && ranges.end.is_none() {
66 return "".to_string();
67 }
68 ranges.to_string()
69 }
70}
71
72impl Display for BytesRange {
73 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
74 let start = self
75 .start
76 .map(|start| start.to_string())
77 .unwrap_or_else(|| "0".to_string());
78 let end = self.end.map(|end| end.to_string()).unwrap_or_default();
79 write!(f, "bytes={start}-{end}")
80 }
81}
82
83impl From<&BytesPosition> for BytesRange {
84 fn from(pos: &BytesPosition) -> Self {
85 Self::new(pos.start, pos.end.map(|value| value - 1))
86 }
87}
88
89impl BytesRange {
90 pub fn new(start: Option<u64>, end: Option<u64>) -> Self {
91 Self { start, end }
92 }
93}
94
95impl BytesPosition {
96 pub fn new(start: Option<u64>, end: Option<u64>, class: Option<Class>) -> Self {
97 Self { start, end, class }
98 }
99
100 pub fn with_start(mut self, start: u64) -> Self {
101 self.start = Some(start);
102 self
103 }
104
105 pub fn with_end(mut self, end: u64) -> Self {
106 self.end = Some(end);
107 self
108 }
109
110 pub fn with_class(self, class: Class) -> Self {
111 self.set_class(Some(class))
112 }
113
114 pub fn set_class(mut self, class: Option<Class>) -> Self {
115 self.class = class;
116 self
117 }
118
119 pub fn get_start(&self) -> Option<u64> {
120 self.start
121 }
122
123 pub fn get_end(&self) -> Option<u64> {
124 self.end
125 }
126
127 pub fn overlaps(&self, range: &BytesPosition) -> bool {
128 let cond1 = match (self.start.as_ref(), range.end.as_ref()) {
129 (None, None) | (None, Some(_)) | (Some(_), None) => true,
130 (Some(start), Some(end)) => end >= start,
131 };
132 let cond2 = match (self.end.as_ref(), range.start.as_ref()) {
133 (None, None) | (None, Some(_)) | (Some(_), None) => true,
134 (Some(end), Some(start)) => end >= start,
135 };
136 cond1 && cond2
137 }
138
139 pub fn merge_with(&mut self, position: &BytesPosition) -> &Self {
141 let start = self.start;
142 let end = self.end;
143
144 self.start = match (start.as_ref(), position.start.as_ref()) {
145 (None, None) | (None, Some(_)) | (Some(_), None) => None,
146 (Some(a), Some(b)) => Some(*a.min(b)),
147 };
148 self.end = match (end.as_ref(), position.end.as_ref()) {
149 (None, None) | (None, Some(_)) | (Some(_), None) => None,
150 (Some(a), Some(b)) => Some(*a.max(b)),
151 };
152
153 self.class = match (self.class.as_ref(), position.class.as_ref()) {
154 (Some(Class::Header), Some(Class::Header)) => Some(Class::Header),
155 (Some(Class::Body), Some(Class::Body)) => Some(Class::Body),
156 (_, _) => None,
157 };
158
159 self
160 }
161
162 #[instrument(level = "trace", ret)]
164 pub fn merge_all(mut ranges: Vec<BytesPosition>) -> Vec<BytesPosition> {
165 if ranges.len() < 2 {
166 ranges
167 } else {
168 ranges.sort_by(|a, b| {
169 let a_start = a.get_start().unwrap_or(0);
170 let b_start = b.get_start().unwrap_or(0);
171 let start_ord = a_start.cmp(&b_start);
172 if start_ord == Ordering::Equal {
173 let a_end = a.get_end().unwrap_or(u64::MAX);
174 let b_end = b.get_end().unwrap_or(u64::MAX);
175 b_end.cmp(&a_end)
176 } else {
177 start_ord
178 }
179 });
180
181 let mut optimized_ranges = Vec::with_capacity(ranges.len());
182
183 let mut current_range = ranges[0].clone();
184
185 for range in ranges.iter().skip(1) {
186 if current_range.overlaps(range) {
187 current_range.merge_with(range);
188 } else {
189 optimized_ranges.push(current_range);
190 current_range = range.clone();
191 }
192 }
193
194 optimized_ranges.push(current_range);
195
196 optimized_ranges
197 }
198 }
199}
200
201#[derive(Debug, Clone)]
202pub struct GetOptions<'a> {
203 pub(crate) range: BytesPosition,
204 pub(crate) request_headers: &'a HeaderMap,
205}
206
207impl<'a> GetOptions<'a> {
208 pub fn new(range: BytesPosition, request_headers: &'a HeaderMap) -> Self {
209 Self {
210 range,
211 request_headers,
212 }
213 }
214
215 pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
216 Self::new(Default::default(), request_headers)
217 }
218
219 pub fn with_max_length(mut self, max_length: u64) -> Self {
220 self.range = BytesPosition::default().with_start(0).with_end(max_length);
221 self
222 }
223
224 pub fn with_range(mut self, range: BytesPosition) -> Self {
225 self.range = range;
226 self
227 }
228
229 pub fn range(&self) -> &BytesPosition {
231 &self.range
232 }
233
234 pub fn request_headers(&self) -> &'a HeaderMap {
236 self.request_headers
237 }
238}
239
240#[derive(Debug, Clone)]
241pub struct BytesPositionOptions<'a> {
242 pub(crate) positions: Vec<BytesPosition>,
243 pub(crate) headers: &'a HeaderMap,
244}
245
246impl<'a> BytesPositionOptions<'a> {
247 pub fn new(positions: Vec<BytesPosition>, headers: &'a HeaderMap) -> Self {
248 Self { positions, headers }
249 }
250
251 pub fn headers(&self) -> &'a HeaderMap {
253 self.headers
254 }
255
256 pub fn positions(&self) -> &Vec<BytesPosition> {
257 &self.positions
258 }
259
260 pub fn into_inner(self) -> Vec<BytesPosition> {
262 self.positions
263 }
264
265 pub fn merge_all(mut self) -> Self {
267 self.positions = BytesPosition::merge_all(self.positions);
268 self
269 }
270}
271
272#[derive(Debug, Clone)]
273pub struct RangeUrlOptions<'a> {
274 range: BytesPosition,
275 response_headers: &'a HeaderMap,
276}
277
278impl<'a> RangeUrlOptions<'a> {
279 pub fn new(range: BytesPosition, response_headers: &'a HeaderMap) -> Self {
280 Self {
281 range,
282 response_headers,
283 }
284 }
285
286 pub fn new_with_default_range(request_headers: &'a HeaderMap) -> Self {
287 Self::new(Default::default(), request_headers)
288 }
289
290 pub fn with_range(mut self, range: BytesPosition) -> Self {
291 self.range = range;
292 self
293 }
294
295 pub fn apply(self, url: Url) -> Url {
296 let range: String = String::from(&BytesRange::from(self.range()));
297
298 let url = if range.is_empty() {
299 url
300 } else {
301 url.add_headers(Headers::default().with_header("Range", range))
302 };
303
304 url.set_class(self.range().class)
305 }
306
307 pub fn range(&self) -> &BytesPosition {
309 &self.range
310 }
311
312 pub fn response_headers(&self) -> &'a HeaderMap {
314 self.response_headers
315 }
316}
317
318#[derive(Debug, Clone)]
320pub struct HeadOptions<'a> {
321 request_headers: &'a HeaderMap,
322}
323
324impl<'a> HeadOptions<'a> {
325 pub fn new(request_headers: &'a HeaderMap) -> Self {
327 Self { request_headers }
328 }
329
330 pub fn request_headers(&self) -> &'a HeaderMap {
332 self.request_headers
333 }
334}
335
336impl<'a> From<&'a GetOptions<'a>> for HeadOptions<'a> {
337 fn from(options: &'a GetOptions<'a>) -> Self {
338 Self::new(options.request_headers())
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use std::collections::HashMap;
345
346 use super::*;
347
348 #[test]
349 fn bytes_range_overlapping_and_merge() {
350 let test_cases = vec![
351 (
352 BytesPosition::new(None, Some(2), None),
353 BytesPosition::new(Some(3), Some(5), None),
354 None,
355 ),
356 (
357 BytesPosition::new(None, Some(2), None),
358 BytesPosition::new(Some(3), None, None),
359 None,
360 ),
361 (
362 BytesPosition::new(None, Some(2), None),
363 BytesPosition::new(Some(2), Some(4), None),
364 Some(BytesPosition::new(None, Some(4), None)),
365 ),
366 (
367 BytesPosition::new(None, Some(2), None),
368 BytesPosition::new(Some(2), None, None),
369 Some(BytesPosition::new(None, None, None)),
370 ),
371 (
372 BytesPosition::new(None, Some(2), None),
373 BytesPosition::new(Some(1), Some(3), None),
374 Some(BytesPosition::new(None, Some(3), None)),
375 ),
376 (
377 BytesPosition::new(None, Some(2), None),
378 BytesPosition::new(Some(1), None, None),
379 Some(BytesPosition::new(None, None, None)),
380 ),
381 (
382 BytesPosition::new(None, Some(2), None),
383 BytesPosition::new(Some(0), Some(2), None),
384 Some(BytesPosition::new(None, Some(2), None)),
385 ),
386 (
387 BytesPosition::new(None, Some(2), None),
388 BytesPosition::new(None, Some(2), None),
389 Some(BytesPosition::new(None, Some(2), None)),
390 ),
391 (
392 BytesPosition::new(None, Some(2), None),
393 BytesPosition::new(Some(0), Some(1), None),
394 Some(BytesPosition::new(None, Some(2), None)),
395 ),
396 (
397 BytesPosition::new(None, Some(2), None),
398 BytesPosition::new(None, Some(1), None),
399 Some(BytesPosition::new(None, Some(2), None)),
400 ),
401 (
402 BytesPosition::new(None, Some(2), None),
403 BytesPosition::new(None, None, None),
404 Some(BytesPosition::new(None, None, None)),
405 ),
406 (
407 BytesPosition::new(Some(2), Some(4), None),
408 BytesPosition::new(Some(6), Some(8), None),
409 None,
410 ),
411 (
412 BytesPosition::new(Some(2), Some(4), None),
413 BytesPosition::new(Some(6), None, None),
414 None,
415 ),
416 (
417 BytesPosition::new(Some(2), Some(4), None),
418 BytesPosition::new(Some(4), Some(6), None),
419 Some(BytesPosition::new(Some(2), Some(6), None)),
420 ),
421 (
422 BytesPosition::new(Some(2), Some(4), None),
423 BytesPosition::new(Some(4), None, None),
424 Some(BytesPosition::new(Some(2), None, None)),
425 ),
426 (
427 BytesPosition::new(Some(2), Some(4), None),
428 BytesPosition::new(Some(3), Some(5), None),
429 Some(BytesPosition::new(Some(2), Some(5), None)),
430 ),
431 (
432 BytesPosition::new(Some(2), Some(4), None),
433 BytesPosition::new(Some(3), None, None),
434 Some(BytesPosition::new(Some(2), None, None)),
435 ),
436 (
437 BytesPosition::new(Some(2), Some(4), None),
438 BytesPosition::new(Some(2), Some(3), None),
439 Some(BytesPosition::new(Some(2), Some(4), None)),
440 ),
441 (
442 BytesPosition::new(Some(2), Some(4), None),
443 BytesPosition::new(None, Some(3), None),
444 Some(BytesPosition::new(None, Some(4), None)),
445 ),
446 (
447 BytesPosition::new(Some(2), Some(4), None),
448 BytesPosition::new(Some(1), Some(3), None),
449 Some(BytesPosition::new(Some(1), Some(4), None)),
450 ),
451 (
452 BytesPosition::new(Some(2), Some(4), None),
453 BytesPosition::new(None, Some(3), None),
454 Some(BytesPosition::new(None, Some(4), None)),
455 ),
456 (
457 BytesPosition::new(Some(2), Some(4), None),
458 BytesPosition::new(Some(0), Some(2), None),
459 Some(BytesPosition::new(Some(0), Some(4), None)),
460 ),
461 (
462 BytesPosition::new(Some(2), Some(4), None),
463 BytesPosition::new(None, Some(2), None),
464 Some(BytesPosition::new(None, Some(4), None)),
465 ),
466 (
467 BytesPosition::new(Some(2), Some(4), None),
468 BytesPosition::new(Some(0), Some(1), None),
469 None,
470 ),
471 (
472 BytesPosition::new(Some(2), Some(4), None),
473 BytesPosition::new(None, Some(1), None),
474 None,
475 ),
476 (
477 BytesPosition::new(Some(2), Some(4), None),
478 BytesPosition::new(None, None, None),
479 Some(BytesPosition::new(None, None, None)),
480 ),
481 (
482 BytesPosition::new(Some(2), None, None),
483 BytesPosition::new(Some(4), Some(6), None),
484 Some(BytesPosition::new(Some(2), None, None)),
485 ),
486 (
487 BytesPosition::new(Some(2), None, None),
488 BytesPosition::new(Some(4), None, None),
489 Some(BytesPosition::new(Some(2), None, None)),
490 ),
491 (
492 BytesPosition::new(Some(2), None, None),
493 BytesPosition::new(Some(2), Some(4), None),
494 Some(BytesPosition::new(Some(2), None, None)),
495 ),
496 (
497 BytesPosition::new(Some(2), None, None),
498 BytesPosition::new(Some(2), None, None),
499 Some(BytesPosition::new(Some(2), None, None)),
500 ),
501 (
502 BytesPosition::new(Some(2), None, None),
503 BytesPosition::new(Some(1), Some(3), None),
504 Some(BytesPosition::new(Some(1), None, None)),
505 ),
506 (
507 BytesPosition::new(Some(2), None, None),
508 BytesPosition::new(None, Some(3), None),
509 Some(BytesPosition::new(None, None, None)),
510 ),
511 (
512 BytesPosition::new(Some(2), None, None),
513 BytesPosition::new(Some(0), Some(2), None),
514 Some(BytesPosition::new(Some(0), None, None)),
515 ),
516 (
517 BytesPosition::new(Some(2), None, None),
518 BytesPosition::new(None, Some(2), None),
519 Some(BytesPosition::new(None, None, None)),
520 ),
521 (
522 BytesPosition::new(Some(2), None, None),
523 BytesPosition::new(Some(0), Some(1), None),
524 None,
525 ),
526 (
527 BytesPosition::new(Some(2), None, None),
528 BytesPosition::new(None, Some(1), None),
529 None,
530 ),
531 (
532 BytesPosition::new(Some(2), None, None),
533 BytesPosition::new(None, None, None),
534 Some(BytesPosition::new(None, None, None)),
535 ),
536 (
537 BytesPosition::new(None, None, None),
538 BytesPosition::new(None, None, None),
539 Some(BytesPosition::new(None, None, None)),
540 ),
541 ];
542
543 for (index, (a, b, expected)) in test_cases.iter().enumerate() {
544 println!("Test case {index}");
545 println!(" {a:?}");
546 println!(" {b:?}");
547 println!(" {expected:?}");
548
549 if a.overlaps(b) {
550 assert_eq!(*a.clone().merge_with(b), expected.clone().unwrap());
551 } else {
552 assert!(expected.is_none())
553 }
554 }
555 }
556
557 #[test]
558 fn bytes_range_merge_all_when_list_is_empty() {
559 assert_eq!(BytesPosition::merge_all(Vec::new()), Vec::new());
560 }
561
562 #[test]
563 fn bytes_range_merge_all_when_list_has_one_range() {
564 assert_eq!(
565 BytesPosition::merge_all(vec![BytesPosition::default()]),
566 vec![BytesPosition::default()]
567 );
568 }
569
570 #[test]
571 fn bytes_position_merge_class_header() {
572 assert_eq!(
573 BytesPosition::merge_all(vec![
574 BytesPosition::new(None, Some(1), Some(Class::Header)),
575 BytesPosition::new(None, Some(2), Some(Class::Header))
576 ]),
577 vec![BytesPosition::new(None, Some(2), Some(Class::Header))]
578 );
579 }
580
581 #[test]
582 fn bytes_position_merge_class_body() {
583 assert_eq!(
584 BytesPosition::merge_all(vec![
585 BytesPosition::new(None, Some(1), Some(Class::Body)),
586 BytesPosition::new(None, Some(3), Some(Class::Body))
587 ]),
588 vec![BytesPosition::new(None, Some(3), Some(Class::Body))]
589 );
590 }
591
592 #[test]
593 fn bytes_position_merge_class_none() {
594 assert_eq!(
595 BytesPosition::merge_all(vec![
596 BytesPosition::new(Some(1), Some(2), None),
597 BytesPosition::new(Some(2), Some(3), None)
598 ]),
599 vec![BytesPosition::new(Some(1), Some(3), None)]
600 );
601 }
602
603 #[test]
604 fn bytes_position_merge_class_different() {
605 assert_eq!(
606 BytesPosition::merge_all(vec![
607 BytesPosition::new(Some(1), Some(2), Some(Class::Header)),
608 BytesPosition::new(Some(2), Some(3), Some(Class::Body))
609 ]),
610 vec![BytesPosition::new(Some(1), Some(3), None)]
611 );
612 }
613
614 #[test]
615 fn bytes_range_merge_all_when_list_has_many_ranges() {
616 let ranges = vec![
617 BytesPosition::new(None, Some(1), None),
618 BytesPosition::new(Some(1), Some(2), None),
619 BytesPosition::new(Some(5), Some(6), None),
620 BytesPosition::new(Some(5), Some(8), None),
621 BytesPosition::new(Some(6), Some(7), None),
622 BytesPosition::new(Some(4), Some(5), None),
623 BytesPosition::new(Some(3), Some(6), None),
624 BytesPosition::new(Some(10), Some(12), None),
625 BytesPosition::new(Some(10), Some(12), None),
626 BytesPosition::new(Some(10), Some(14), None),
627 BytesPosition::new(Some(14), Some(15), None),
628 BytesPosition::new(Some(12), Some(16), None),
629 BytesPosition::new(Some(17), Some(19), None),
630 BytesPosition::new(Some(21), Some(23), None),
631 BytesPosition::new(Some(18), Some(22), None),
632 BytesPosition::new(Some(24), None, None),
633 BytesPosition::new(Some(24), Some(30), None),
634 BytesPosition::new(Some(31), Some(33), None),
635 BytesPosition::new(Some(35), None, None),
636 ];
637
638 let expected_ranges = vec![
639 BytesPosition::new(None, Some(2), None),
640 BytesPosition::new(Some(3), Some(8), None),
641 BytesPosition::new(Some(10), Some(16), None),
642 BytesPosition::new(Some(17), Some(23), None),
643 BytesPosition::new(Some(24), None, None),
644 ];
645
646 assert_eq!(BytesPosition::merge_all(ranges), expected_ranges);
647 }
648
649 #[test]
650 fn bytes_position_new() {
651 let result = BytesPosition::new(Some(1), Some(2), Some(Class::Header));
652 assert_eq!(result.start, Some(1));
653 assert_eq!(result.end, Some(2));
654 assert_eq!(result.class, Some(Class::Header));
655 }
656
657 #[test]
658 fn bytes_position_with_start() {
659 let result = BytesPosition::default().with_start(1);
660 assert_eq!(result.start, Some(1));
661 }
662
663 #[test]
664 fn bytes_position_with_end() {
665 let result = BytesPosition::default().with_end(1);
666 assert_eq!(result.end, Some(1));
667 }
668
669 #[test]
670 fn bytes_position_with_class() {
671 let result = BytesPosition::default().with_class(Class::Header);
672 assert_eq!(result.class, Some(Class::Header));
673 }
674
675 #[test]
676 fn bytes_position_set_class() {
677 let result = BytesPosition::default().set_class(Some(Class::Header));
678 assert_eq!(result.class, Some(Class::Header));
679 }
680
681 #[test]
682 fn data_block_update_classes_all_some() {
683 let blocks = DataBlock::update_classes(vec![
684 DataBlock::Range(BytesPosition::new(None, Some(1), Some(Class::Body))),
685 DataBlock::Data(vec![], Some(Class::Header)),
686 ]);
687 for block in blocks {
688 let class = match block {
689 DataBlock::Range(pos) => pos.class,
690 DataBlock::Data(_, class) => class,
691 };
692 assert!(class.is_some());
693 }
694 }
695
696 #[test]
697 fn data_block_update_classes_one_none() {
698 let blocks = DataBlock::update_classes(vec![
699 DataBlock::Range(BytesPosition::new(None, Some(1), Some(Class::Body))),
700 DataBlock::Data(vec![], None),
701 ]);
702 for block in blocks {
703 let class = match block {
704 DataBlock::Range(pos) => pos.class,
705 DataBlock::Data(_, class) => class,
706 };
707 assert!(class.is_none());
708 }
709 }
710
711 #[test]
712 fn data_block_from_bytes_positions() {
713 let blocks = DataBlock::from_bytes_positions(vec![
714 BytesPosition::new(None, Some(1), None),
715 BytesPosition::new(Some(1), Some(2), None),
716 ]);
717 assert_eq!(
718 blocks,
719 vec![DataBlock::Range(BytesPosition::new(None, Some(2), None))]
720 );
721 }
722
723 #[test]
724 fn byte_range_from_byte_position() {
725 let result: BytesRange = BytesRange::from(&BytesPosition::default().with_start(5).with_end(10));
726 let expected = BytesRange::new(Some(5), Some(9));
727 assert_eq!(result, expected);
728 }
729
730 #[test]
731 fn get_options_with_max_length() {
732 let request_headers = Default::default();
733 let result = GetOptions::new_with_default_range(&request_headers).with_max_length(1);
734 assert_eq!(
735 result.range(),
736 &BytesPosition::default().with_start(0).with_end(1)
737 );
738 }
739
740 #[test]
741 fn get_options_with_range() {
742 let request_headers = Default::default();
743 let result = GetOptions::new_with_default_range(&request_headers)
744 .with_range(BytesPosition::new(Some(5), Some(11), Some(Class::Header)));
745 assert_eq!(
746 result.range(),
747 &BytesPosition::new(Some(5), Some(11), Some(Class::Header))
748 );
749 }
750
751 #[test]
752 fn url_options_with_range() {
753 let request_headers = Default::default();
754 let result = RangeUrlOptions::new_with_default_range(&request_headers)
755 .with_range(BytesPosition::new(Some(5), Some(11), Some(Class::Header)));
756 assert_eq!(
757 result.range(),
758 &BytesPosition::new(Some(5), Some(11), Some(Class::Header))
759 );
760 }
761
762 #[test]
763 fn url_options_apply_with_bytes_range() {
764 let result = RangeUrlOptions::new(
765 BytesPosition::new(Some(5), Some(11), Some(Class::Header)),
766 &Default::default(),
767 )
768 .apply(Url::new(""));
769 println!("{result:?}");
770 assert_eq!(
771 result,
772 Url::new("")
773 .with_headers(Headers::new(HashMap::new()).with_header("Range", "bytes=5-10"))
774 .with_class(Class::Header)
775 );
776 }
777
778 #[test]
779 fn url_options_apply_no_bytes_range() {
780 let result = RangeUrlOptions::new_with_default_range(&Default::default()).apply(Url::new(""));
781 assert_eq!(result, Url::new(""));
782 }
783
784 #[test]
785 fn url_options_apply_with_headers() {
786 let result = RangeUrlOptions::new(
787 BytesPosition::new(Some(5), Some(11), Some(Class::Header)),
788 &Default::default(),
789 )
790 .apply(Url::new("").with_headers(Headers::default().with_header("header", "value")));
791 println!("{result:?}");
792
793 assert_eq!(
794 result,
795 Url::new("")
796 .with_headers(
797 Headers::new(HashMap::new())
798 .with_header("Range", "bytes=5-10")
799 .with_header("header", "value")
800 )
801 .with_class(Class::Header)
802 );
803 }
804}