1use crate::{Bytes, Points};
4
5#[inline]
25#[must_use]
26pub fn calculate_percentage(part: u64, total: u64) -> f64 {
27 if total == 0 {
28 return 0.0;
29 }
30 (part as f64 / total as f64) * 100.0
31}
32
33#[inline]
53#[must_use]
54pub fn calculate_bandwidth_mbps(bytes: Bytes, duration_ms: u64) -> f64 {
55 if duration_ms == 0 {
56 return 0.0;
57 }
58
59 let bits = (bytes * 8) as f64;
60 let seconds = duration_ms as f64 / 1000.0;
61 (bits / seconds) / 1_000_000.0
62}
63
64#[inline]
66pub fn calculate_latency_ms(start_ms: i64, end_ms: i64) -> u32 {
67 (end_ms - start_ms).max(0) as u32
68}
69
70#[inline]
72#[must_use]
73pub fn estimate_transfer_time(bytes: Bytes, bandwidth_bps: u64) -> u64 {
74 if bandwidth_bps == 0 {
75 return u64::MAX;
76 }
77
78 let bits = bytes * 8;
79 bits / bandwidth_bps
80}
81
82#[inline]
111#[must_use]
112pub fn calculate_demand_multiplier(demand: u64, supply: u64) -> f64 {
113 if supply == 0 {
114 return 3.0; }
116
117 let ratio = demand as f64 / supply as f64;
118
119 if ratio <= 0.5 {
121 1.0
122 } else if ratio >= 2.0 {
123 3.0
124 } else {
125 1.0 + (ratio - 0.5) * (2.0 / 1.5)
126 }
127}
128
129#[inline]
161#[must_use]
162pub fn calculate_z_score(value: f64, mean: f64, std_dev: f64) -> f64 {
163 if std_dev == 0.0 {
164 return 0.0;
165 }
166
167 (value - mean) / std_dev
168}
169
170#[inline]
172#[must_use]
173pub fn calculate_storage_cost(size_bytes: Bytes, rate_per_gb_month: Points) -> Points {
174 let gb = (size_bytes as f64) / (1024.0 * 1024.0 * 1024.0);
175 (gb * rate_per_gb_month as f64).ceil() as Points
176}
177
178#[inline]
180pub fn bytes_to_gb_f64(bytes: Bytes) -> f64 {
181 bytes as f64 / (1024.0 * 1024.0 * 1024.0)
182}
183
184#[inline]
186pub fn gb_to_bytes_f64(gb: f64) -> Bytes {
187 (gb * 1024.0 * 1024.0 * 1024.0) as Bytes
188}
189
190#[inline]
192#[must_use]
193pub fn calculate_reward_with_penalty(
194 base_reward: Points,
195 multiplier: f64,
196 latency_ms: u32,
197 latency_threshold_ms: u32,
198) -> Points {
199 let reward_with_multiplier = (base_reward as f64 * multiplier) as Points;
200
201 if latency_ms > latency_threshold_ms {
202 reward_with_multiplier / 2
204 } else {
205 reward_with_multiplier
206 }
207}
208
209#[inline]
211#[must_use]
212pub fn calculate_ema(current: f64, new_value: f64, alpha: f64) -> f64 {
213 alpha * new_value + (1.0 - alpha) * current
214}
215
216#[inline]
218#[must_use]
219pub fn calculate_std_dev(values: &[f64]) -> f64 {
220 if values.is_empty() {
221 return 0.0;
222 }
223
224 let mean = values.iter().sum::<f64>() / values.len() as f64;
225 let variance = values.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / values.len() as f64;
226 variance.sqrt()
227}
228
229#[inline]
231#[must_use]
232pub fn calculate_mean(values: &[f64]) -> f64 {
233 if values.is_empty() {
234 return 0.0;
235 }
236 values.iter().sum::<f64>() / values.len() as f64
237}
238
239pub fn calculate_median(values: &[f64]) -> f64 {
241 if values.is_empty() {
242 return 0.0;
243 }
244
245 let mut sorted = values.to_vec();
246 sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
247
248 let mid = sorted.len() / 2;
249 if sorted.len() % 2 == 0 {
250 (sorted[mid - 1] + sorted[mid]) / 2.0
251 } else {
252 sorted[mid]
253 }
254}
255
256pub fn calculate_percentile(values: &[f64], p: f64) -> f64 {
258 if values.is_empty() {
259 return 0.0;
260 }
261
262 let p = p.clamp(0.0, 1.0);
263 let mut sorted = values.to_vec();
264 sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
265
266 let index = (p * (sorted.len() - 1) as f64).round() as usize;
267 sorted[index]
268}
269
270pub fn calculate_stats(values: &[f64]) -> (f64, f64, f64) {
272 if values.is_empty() {
273 return (0.0, 0.0, 0.0);
274 }
275
276 let min = values
277 .iter()
278 .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
279 .copied()
280 .unwrap_or(0.0);
281
282 let max = values
283 .iter()
284 .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
285 .copied()
286 .unwrap_or(0.0);
287
288 let avg = calculate_mean(values);
289
290 (min, max, avg)
291}
292
293pub fn is_outlier_iqr(values: &[f64], value: f64) -> bool {
295 if values.len() < 4 {
296 return false;
297 }
298
299 let q1 = calculate_percentile(values, 0.25);
300 let q3 = calculate_percentile(values, 0.75);
301 let iqr = q3 - q1;
302
303 let lower_bound = q1 - 1.5 * iqr;
304 let upper_bound = q3 + 1.5 * iqr;
305
306 value < lower_bound || value > upper_bound
307}
308
309pub fn calculate_moving_average(values: &[f64], window_size: usize) -> Vec<f64> {
311 if values.is_empty() || window_size == 0 {
312 return Vec::new();
313 }
314
315 let mut result = Vec::new();
316 for i in 0..values.len() {
317 let start = if i >= window_size {
318 i - window_size + 1
319 } else {
320 0
321 };
322 let window = &values[start..=i];
323 result.push(calculate_mean(window));
324 }
325
326 result
327}
328
329pub fn round_up_to_multiple(value: u64, n: u64) -> u64 {
331 if n == 0 {
332 return value;
333 }
334 value.div_ceil(n) * n
335}
336
337pub fn round_down_to_multiple(value: u64, n: u64) -> u64 {
339 if n == 0 {
340 return value;
341 }
342 (value / n) * n
343}
344
345pub fn calculate_growth_rate(initial: f64, final_val: f64, periods: u32) -> f64 {
347 if initial == 0.0 || periods == 0 {
348 return 0.0;
349 }
350 ((final_val / initial).powf(1.0 / periods as f64) - 1.0) * 100.0
351}
352
353pub fn calculate_reputation_decay(
355 current_reputation: f32,
356 days_elapsed: f32,
357 decay_rate: f32,
358) -> f32 {
359 let decayed = current_reputation - (current_reputation * decay_rate * days_elapsed);
360 decayed.clamp(crate::MIN_REPUTATION, crate::MAX_REPUTATION)
361}
362
363pub fn update_reputation(current: f32, success: bool, weight: f32) -> f32 {
365 let delta = if success { weight } else { -weight * 2.0 }; (current + delta).clamp(crate::MIN_REPUTATION, crate::MAX_REPUTATION)
367}
368
369pub fn calculate_reputation_bonus(consecutive_successes: u32) -> f32 {
371 let capped_successes = consecutive_successes.min(20);
373 (capped_successes as f32).sqrt() * 0.5 }
375
376pub fn calculate_token_bucket(
378 current_tokens: f64,
379 capacity: f64,
380 refill_rate: f64,
381 time_elapsed_secs: f64,
382) -> f64 {
383 let new_tokens = current_tokens + (refill_rate * time_elapsed_secs);
384 new_tokens.min(capacity)
385}
386
387pub fn is_rate_limit_allowed(current_tokens: f64, cost: f64) -> bool {
389 current_tokens >= cost
390}
391
392pub fn calculate_sliding_window_count(
394 timestamps: &[i64],
395 window_start_ms: i64,
396 window_end_ms: i64,
397) -> usize {
398 timestamps
399 .iter()
400 .filter(|&&ts| ts >= window_start_ms && ts <= window_end_ms)
401 .count()
402}
403
404pub fn calculate_platform_fee(total_points: Points, fee_percentage: f64) -> Points {
406 (total_points as f64 * fee_percentage) as Points
407}
408
409pub fn calculate_creator_share(total_points: Points, share_percentage: f64) -> Points {
411 (total_points as f64 * share_percentage) as Points
412}
413
414pub fn calculate_provider_earnings(
416 total_points: Points,
417 platform_fee_pct: f64,
418 creator_share_pct: f64,
419) -> Points {
420 let platform_fee = calculate_platform_fee(total_points, platform_fee_pct);
421 let creator_share = calculate_creator_share(total_points, creator_share_pct);
422 total_points
423 .saturating_sub(platform_fee)
424 .saturating_sub(creator_share)
425}
426
427pub fn calculate_content_price(
429 size_bytes: Bytes,
430 base_price_per_gb: Points,
431 demand_multiplier: f64,
432) -> Points {
433 let gb = bytes_to_gb_f64(size_bytes);
434 ((gb * base_price_per_gb as f64) * demand_multiplier).ceil() as Points
435}
436
437pub fn clamp<T: PartialOrd>(value: T, min: T, max: T) -> T {
453 if value < min {
454 min
455 } else if value > max {
456 max
457 } else {
458 value
459 }
460}
461
462#[inline]
479pub fn lerp(a: f64, b: f64, t: f64) -> f64 {
480 a + (b - a) * t
481}
482
483pub fn calculate_percentage_change(old_value: f64, new_value: f64) -> f64 {
487 if old_value == 0.0 {
488 if new_value == 0.0 {
489 0.0
490 } else {
491 100.0 }
493 } else {
494 ((new_value - old_value) / old_value) * 100.0
495 }
496}
497
498pub fn calculate_rate(event_count: u64, duration_ms: u64) -> f64 {
501 if duration_ms == 0 {
502 return 0.0;
503 }
504
505 (event_count as f64 / duration_ms as f64) * 1000.0
506}
507
508pub fn normalize(value: f64, min: f64, max: f64) -> f64 {
529 if max == min {
530 return 0.5; }
532
533 let normalized = (value - min) / (max - min);
534 normalized.clamp(0.0, 1.0)
535}
536
537pub fn average(a: f64, b: f64) -> f64 {
539 (a + b) / 2.0
540}
541
542pub fn is_within_tolerance(value: f64, target: f64, tolerance: f64) -> bool {
544 (value - target).abs() <= tolerance
545}
546
547pub fn bps_to_mbps(bps: u64) -> f64 {
549 bps as f64 / 1_000_000.0
550}
551
552pub fn mbps_to_bps(mbps: f64) -> u64 {
554 (mbps * 1_000_000.0) as u64
555}
556
557pub fn calculate_uptime_percentage(total_ms: u64, downtime_ms: u64) -> f64 {
559 if total_ms == 0 {
560 return 100.0;
561 }
562
563 let uptime_ms = total_ms.saturating_sub(downtime_ms);
564 (uptime_ms as f64 / total_ms as f64) * 100.0
565}
566
567#[inline]
570#[must_use]
571pub const fn chunk_offset(chunk_index: u64, chunk_size: u64) -> u64 {
572 chunk_index * chunk_size
573}
574
575#[inline]
578#[must_use]
579pub const fn byte_to_chunk_index(byte_offset: u64, chunk_size: u64) -> u64 {
580 if chunk_size == 0 {
581 0
582 } else {
583 byte_offset / chunk_size
584 }
585}
586
587#[inline]
590#[must_use]
591pub const fn chunk_byte_range(chunk_index: u64, chunk_size: u64, total_size: u64) -> (u64, u64) {
592 let start = chunk_index * chunk_size;
593 let end = if start + chunk_size > total_size {
594 total_size
595 } else {
596 start + chunk_size
597 };
598 (start, end)
599}
600
601#[inline]
603#[must_use]
604pub const fn is_valid_chunk_index(chunk_index: u64, total_size: u64, chunk_size: u64) -> bool {
605 if chunk_size == 0 {
606 return false;
607 }
608 let max_chunks = total_size.div_ceil(chunk_size);
609 chunk_index < max_chunks
610}
611
612#[inline]
614#[must_use]
615pub const fn actual_chunk_size(chunk_index: u64, chunk_size: u64, total_size: u64) -> u64 {
616 let start = chunk_index * chunk_size;
617 if start >= total_size {
618 0
619 } else {
620 let remaining = total_size - start;
621 if remaining < chunk_size {
622 remaining
623 } else {
624 chunk_size
625 }
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use super::*;
632
633 #[test]
634 fn test_calculate_percentage() {
635 assert_eq!(calculate_percentage(50, 100), 50.0);
636 assert_eq!(calculate_percentage(0, 100), 0.0);
637 assert_eq!(calculate_percentage(100, 100), 100.0);
638 assert_eq!(calculate_percentage(25, 0), 0.0);
639 }
640
641 #[test]
642 fn test_calculate_bandwidth_mbps() {
643 assert_eq!(calculate_bandwidth_mbps(1_048_576, 1000), 8.388_608);
645 assert_eq!(calculate_bandwidth_mbps(0, 1000), 0.0);
646 assert_eq!(calculate_bandwidth_mbps(1000, 0), 0.0);
647 }
648
649 #[test]
650 fn test_calculate_latency() {
651 assert_eq!(calculate_latency_ms(1000, 1500), 500);
652 assert_eq!(calculate_latency_ms(1500, 1000), 0);
653 }
654
655 #[test]
656 fn test_estimate_transfer_time() {
657 assert_eq!(estimate_transfer_time(1_048_576, 1_000_000), 8);
659 assert_eq!(estimate_transfer_time(1000, 0), u64::MAX);
660 }
661
662 #[test]
663 fn test_calculate_demand_multiplier() {
664 assert_eq!(calculate_demand_multiplier(1, 4), 1.0);
666 assert!((calculate_demand_multiplier(2, 2) - 1.666_666_666_666_667).abs() < 0.001);
668 assert_eq!(calculate_demand_multiplier(4, 2), 3.0);
670 assert_eq!(calculate_demand_multiplier(10, 0), 3.0);
672 }
673
674 #[test]
675 fn test_calculate_z_score() {
676 assert_eq!(calculate_z_score(100.0, 100.0, 10.0), 0.0);
677 assert_eq!(calculate_z_score(110.0, 100.0, 10.0), 1.0);
678 assert_eq!(calculate_z_score(90.0, 100.0, 10.0), -1.0);
679 assert_eq!(calculate_z_score(100.0, 100.0, 0.0), 0.0);
680 }
681
682 #[test]
683 fn test_calculate_storage_cost() {
684 assert_eq!(calculate_storage_cost(1_073_741_824, 10), 10);
686 assert_eq!(calculate_storage_cost(536_870_912, 10), 5);
688 }
689
690 #[test]
691 fn test_bytes_to_gb_f64() {
692 assert_eq!(bytes_to_gb_f64(1_073_741_824), 1.0);
693 assert_eq!(bytes_to_gb_f64(536_870_912), 0.5);
694 }
695
696 #[test]
697 fn test_gb_to_bytes_f64() {
698 assert_eq!(gb_to_bytes_f64(1.0), 1_073_741_824);
699 assert_eq!(gb_to_bytes_f64(0.5), 536_870_912);
700 }
701
702 #[test]
703 fn test_calculate_reward_with_penalty() {
704 assert_eq!(calculate_reward_with_penalty(100, 2.0, 400, 500), 200);
706 assert_eq!(calculate_reward_with_penalty(100, 2.0, 600, 500), 100);
708 }
709
710 #[test]
711 fn test_calculate_ema() {
712 let current = 100.0;
713 let new_value = 120.0;
714 let alpha = 0.3;
715 let expected = alpha * new_value + (1.0 - alpha) * current;
716 assert_eq!(calculate_ema(current, new_value, alpha), expected);
717 }
718
719 #[test]
720 fn test_calculate_std_dev() {
721 let values = vec![10.0, 12.0, 23.0, 23.0, 16.0, 23.0, 21.0, 16.0];
722 let std_dev = calculate_std_dev(&values);
723 assert!((std_dev - 4.898_979_485_566_356).abs() < 0.001);
724
725 assert_eq!(calculate_std_dev(&[]), 0.0);
726 }
727
728 #[test]
729 fn test_calculate_mean() {
730 assert_eq!(calculate_mean(&[1.0, 2.0, 3.0, 4.0, 5.0]), 3.0);
731 assert_eq!(calculate_mean(&[]), 0.0);
732 }
733
734 #[test]
735 fn test_calculate_median() {
736 assert_eq!(calculate_median(&[1.0, 2.0, 3.0, 4.0, 5.0]), 3.0);
737 assert_eq!(calculate_median(&[1.0, 2.0, 3.0, 4.0]), 2.5);
738 assert_eq!(calculate_median(&[5.0]), 5.0);
739 assert_eq!(calculate_median(&[]), 0.0);
740 }
741
742 #[test]
743 fn test_calculate_percentile() {
744 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
745 assert_eq!(calculate_percentile(&values, 0.0), 1.0);
746 assert_eq!(calculate_percentile(&values, 0.5), 6.0); assert_eq!(calculate_percentile(&values, 1.0), 10.0);
748 }
749
750 #[test]
751 fn test_calculate_stats() {
752 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
753 let (min, max, avg) = calculate_stats(&values);
754 assert_eq!(min, 1.0);
755 assert_eq!(max, 5.0);
756 assert_eq!(avg, 3.0);
757 }
758
759 #[test]
760 fn test_is_outlier_iqr() {
761 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
762 assert!(!is_outlier_iqr(&values, 5.0));
763 assert!(is_outlier_iqr(&values, 100.0));
764 assert!(is_outlier_iqr(&values, -100.0));
765 }
766
767 #[test]
768 fn test_calculate_moving_average() {
769 let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
770 let ma = calculate_moving_average(&values, 3);
771 assert_eq!(ma.len(), 5);
772 assert_eq!(ma[0], 1.0); assert_eq!(ma[1], 1.5); assert_eq!(ma[2], 2.0); assert_eq!(ma[3], 3.0); assert_eq!(ma[4], 4.0); }
778
779 #[test]
780 fn test_round_up_to_multiple() {
781 assert_eq!(round_up_to_multiple(10, 5), 10);
782 assert_eq!(round_up_to_multiple(11, 5), 15);
783 assert_eq!(round_up_to_multiple(14, 5), 15);
784 assert_eq!(round_up_to_multiple(15, 5), 15);
785 }
786
787 #[test]
788 fn test_round_down_to_multiple() {
789 assert_eq!(round_down_to_multiple(10, 5), 10);
790 assert_eq!(round_down_to_multiple(11, 5), 10);
791 assert_eq!(round_down_to_multiple(14, 5), 10);
792 assert_eq!(round_down_to_multiple(15, 5), 15);
793 }
794
795 #[test]
796 fn test_calculate_growth_rate() {
797 let rate = calculate_growth_rate(100.0, 121.0, 2);
798 assert!((rate - 10.0).abs() < 0.01); }
800
801 #[test]
802 fn test_calculate_reputation_decay() {
803 let reputation = calculate_reputation_decay(100.0, 10.0, 0.01);
804 assert_eq!(reputation, 90.0);
805
806 let decayed = calculate_reputation_decay(10.0, 1000.0, 0.01);
808 assert_eq!(decayed, crate::MIN_REPUTATION);
809
810 let no_decay = calculate_reputation_decay(100.0, 0.0, 0.01);
812 assert_eq!(no_decay, 100.0);
813 }
814
815 #[test]
816 fn test_update_reputation() {
817 let updated = update_reputation(50.0, true, 1.0);
819 assert_eq!(updated, 51.0);
820
821 let updated = update_reputation(50.0, false, 1.0);
823 assert_eq!(updated, 48.0);
824
825 let updated = update_reputation(99.0, true, 5.0);
827 assert_eq!(updated, crate::MAX_REPUTATION);
828
829 let updated = update_reputation(5.0, false, 10.0);
831 assert_eq!(updated, crate::MIN_REPUTATION);
832 }
833
834 #[test]
835 fn test_calculate_reputation_bonus() {
836 assert_eq!(calculate_reputation_bonus(0), 0.0);
837 assert_eq!(calculate_reputation_bonus(4), 1.0);
838 assert!((calculate_reputation_bonus(16) - 2.0).abs() < 0.01);
839 let bonus_20 = calculate_reputation_bonus(20);
841 let bonus_30 = calculate_reputation_bonus(30);
842 assert_eq!(bonus_20, bonus_30);
843 }
844
845 #[test]
846 fn test_calculate_token_bucket() {
847 let tokens = calculate_token_bucket(5.0, 10.0, 1.0, 3.0);
848 assert_eq!(tokens, 8.0);
849
850 let tokens = calculate_token_bucket(8.0, 10.0, 5.0, 10.0);
852 assert_eq!(tokens, 10.0);
853 }
854
855 #[test]
856 fn test_is_rate_limit_allowed() {
857 assert!(is_rate_limit_allowed(10.0, 5.0));
858 assert!(is_rate_limit_allowed(5.0, 5.0));
859 assert!(!is_rate_limit_allowed(4.0, 5.0));
860 }
861
862 #[test]
863 fn test_calculate_sliding_window_count() {
864 let timestamps = vec![1000, 2000, 3000, 4000, 5000];
865 assert_eq!(calculate_sliding_window_count(×tamps, 2000, 4000), 3);
866 assert_eq!(calculate_sliding_window_count(×tamps, 1000, 5000), 5);
867 assert_eq!(calculate_sliding_window_count(×tamps, 6000, 7000), 0);
868 }
869
870 #[test]
871 fn test_calculate_platform_fee() {
872 assert_eq!(calculate_platform_fee(1000, 0.10), 100);
873 assert_eq!(calculate_platform_fee(500, 0.05), 25);
874 }
875
876 #[test]
877 fn test_calculate_creator_share() {
878 assert_eq!(calculate_creator_share(1000, 0.20), 200);
879 assert_eq!(calculate_creator_share(500, 0.15), 75);
880 }
881
882 #[test]
883 fn test_calculate_provider_earnings() {
884 assert_eq!(calculate_provider_earnings(1000, 0.10, 0.20), 700);
886 assert_eq!(calculate_provider_earnings(500, 0.05, 0.15), 400);
888 }
889
890 #[test]
891 fn test_calculate_content_price() {
892 assert_eq!(calculate_content_price(1_073_741_824, 10, 1.0), 10);
894 assert_eq!(calculate_content_price(1_073_741_824, 10, 2.0), 20);
896 assert_eq!(calculate_content_price(536_870_912, 10, 1.0), 5);
898 }
899
900 #[test]
901 fn test_clamp() {
902 assert_eq!(clamp(5, 0, 10), 5);
903 assert_eq!(clamp(-5, 0, 10), 0);
904 assert_eq!(clamp(15, 0, 10), 10);
905 assert_eq!(clamp(5.5, 0.0, 10.0), 5.5);
906 }
907
908 #[test]
909 fn test_lerp() {
910 assert_eq!(lerp(0.0, 10.0, 0.0), 0.0);
911 assert_eq!(lerp(0.0, 10.0, 0.5), 5.0);
912 assert_eq!(lerp(0.0, 10.0, 1.0), 10.0);
913 assert_eq!(lerp(10.0, 20.0, 0.25), 12.5);
914 }
915
916 #[test]
917 fn test_calculate_percentage_change() {
918 assert_eq!(calculate_percentage_change(100.0, 150.0), 50.0);
919 assert_eq!(calculate_percentage_change(100.0, 50.0), -50.0);
920 assert_eq!(calculate_percentage_change(100.0, 100.0), 0.0);
921 assert_eq!(calculate_percentage_change(0.0, 0.0), 0.0);
922 assert_eq!(calculate_percentage_change(0.0, 50.0), 100.0);
923 }
924
925 #[test]
926 fn test_calculate_rate() {
927 assert_eq!(calculate_rate(100, 1000), 100.0); assert_eq!(calculate_rate(50, 500), 100.0); assert_eq!(calculate_rate(0, 1000), 0.0);
930 assert_eq!(calculate_rate(100, 0), 0.0); }
932
933 #[test]
934 fn test_normalize() {
935 assert_eq!(normalize(50.0, 0.0, 100.0), 0.5);
936 assert_eq!(normalize(0.0, 0.0, 100.0), 0.0);
937 assert_eq!(normalize(100.0, 0.0, 100.0), 1.0);
938 assert_eq!(normalize(150.0, 0.0, 100.0), 1.0); assert_eq!(normalize(-50.0, 0.0, 100.0), 0.0); assert_eq!(normalize(50.0, 50.0, 50.0), 0.5); }
942
943 #[test]
944 fn test_average() {
945 assert_eq!(average(10.0, 20.0), 15.0);
946 assert_eq!(average(0.0, 100.0), 50.0);
947 assert_eq!(average(-10.0, 10.0), 0.0);
948 }
949
950 #[test]
951 fn test_is_within_tolerance() {
952 assert!(is_within_tolerance(10.0, 10.0, 0.0));
953 assert!(is_within_tolerance(10.5, 10.0, 1.0));
954 assert!(is_within_tolerance(9.5, 10.0, 1.0));
955 assert!(!is_within_tolerance(11.5, 10.0, 1.0));
956 assert!(!is_within_tolerance(8.5, 10.0, 1.0));
957 }
958
959 #[test]
960 fn test_bps_to_mbps() {
961 assert_eq!(bps_to_mbps(1_000_000), 1.0);
962 assert_eq!(bps_to_mbps(10_000_000), 10.0);
963 assert_eq!(bps_to_mbps(500_000), 0.5);
964 }
965
966 #[test]
967 fn test_mbps_to_bps() {
968 assert_eq!(mbps_to_bps(1.0), 1_000_000);
969 assert_eq!(mbps_to_bps(10.0), 10_000_000);
970 assert_eq!(mbps_to_bps(0.5), 500_000);
971 }
972
973 #[test]
974 fn test_calculate_uptime_percentage() {
975 assert_eq!(calculate_uptime_percentage(1000, 0), 100.0);
976 assert_eq!(calculate_uptime_percentage(1000, 100), 90.0);
977 assert_eq!(calculate_uptime_percentage(1000, 1000), 0.0);
978 assert_eq!(calculate_uptime_percentage(0, 0), 100.0);
979 assert_eq!(calculate_uptime_percentage(1000, 1500), 0.0); }
981
982 #[test]
983 fn test_chunk_offset() {
984 assert_eq!(chunk_offset(0, 1024), 0);
985 assert_eq!(chunk_offset(1, 1024), 1024);
986 assert_eq!(chunk_offset(10, 1024), 10240);
987 assert_eq!(chunk_offset(0, 262_144), 0);
988 assert_eq!(chunk_offset(5, 262_144), 1_310_720);
989 }
990
991 #[test]
992 fn test_byte_to_chunk_index() {
993 assert_eq!(byte_to_chunk_index(0, 1024), 0);
994 assert_eq!(byte_to_chunk_index(1023, 1024), 0);
995 assert_eq!(byte_to_chunk_index(1024, 1024), 1);
996 assert_eq!(byte_to_chunk_index(2048, 1024), 2);
997 assert_eq!(byte_to_chunk_index(1_000_000, 262_144), 3);
998 assert_eq!(byte_to_chunk_index(100, 0), 0); }
1000
1001 #[test]
1002 fn test_chunk_byte_range() {
1003 assert_eq!(chunk_byte_range(0, 1024, 10240), (0, 1024));
1004 assert_eq!(chunk_byte_range(1, 1024, 10240), (1024, 2048));
1005 assert_eq!(chunk_byte_range(9, 1024, 10240), (9216, 10240)); assert_eq!(chunk_byte_range(10, 1024, 10240), (10240, 10240)); }
1008
1009 #[test]
1010 fn test_is_valid_chunk_index() {
1011 assert!(is_valid_chunk_index(0, 10240, 1024));
1013 assert!(is_valid_chunk_index(9, 10240, 1024));
1014 assert!(!is_valid_chunk_index(10, 10240, 1024));
1015 assert!(!is_valid_chunk_index(100, 10240, 1024));
1016
1017 assert!(!is_valid_chunk_index(0, 10240, 0));
1019
1020 assert!(is_valid_chunk_index(4, 5120, 1024)); assert!(!is_valid_chunk_index(5, 5120, 1024));
1023 }
1024
1025 #[test]
1026 fn test_actual_chunk_size() {
1027 assert_eq!(actual_chunk_size(0, 1024, 10240), 1024);
1029 assert_eq!(actual_chunk_size(5, 1024, 10240), 1024);
1030
1031 assert_eq!(actual_chunk_size(9, 1024, 10000), 784);
1033
1034 assert_eq!(actual_chunk_size(100, 1024, 10240), 0);
1036
1037 assert_eq!(actual_chunk_size(4, 1024, 5120), 1024);
1039 }
1040}