1use perfgate_types::{HostInfo, HostMismatchInfo};
48
49pub fn detect_host_mismatch(baseline: &HostInfo, current: &HostInfo) -> Option<HostMismatchInfo> {
233 let mut reasons = Vec::new();
234
235 if baseline.os != current.os {
236 reasons.push(format!(
237 "OS mismatch: baseline={}, current={}",
238 baseline.os, current.os
239 ));
240 }
241
242 if baseline.arch != current.arch {
243 reasons.push(format!(
244 "architecture mismatch: baseline={}, current={}",
245 baseline.arch, current.arch
246 ));
247 }
248
249 if let (Some(base_cpu), Some(curr_cpu)) = (baseline.cpu_count, current.cpu_count) {
250 let ratio = if base_cpu > 0 && curr_cpu > 0 {
251 (base_cpu as f64 / curr_cpu as f64).max(curr_cpu as f64 / base_cpu as f64)
252 } else {
253 1.0
254 };
255 if ratio > 2.0 {
256 reasons.push(format!(
257 "CPU count differs significantly: baseline={}, current={} ({:.1}x)",
258 base_cpu, curr_cpu, ratio
259 ));
260 }
261 }
262
263 if let (Some(base_mem), Some(curr_mem)) = (baseline.memory_bytes, current.memory_bytes) {
264 let ratio = if base_mem > 0 && curr_mem > 0 {
265 (base_mem as f64 / curr_mem as f64).max(curr_mem as f64 / base_mem as f64)
266 } else {
267 1.0
268 };
269 if ratio > 2.0 {
270 let base_gb = base_mem as f64 / (1024.0 * 1024.0 * 1024.0);
271 let curr_gb = curr_mem as f64 / (1024.0 * 1024.0 * 1024.0);
272 reasons.push(format!(
273 "memory differs significantly: baseline={:.1}GB, current={:.1}GB ({:.1}x)",
274 base_gb, curr_gb, ratio
275 ));
276 }
277 }
278
279 if let (Some(base_hash), Some(curr_hash)) = (&baseline.hostname_hash, ¤t.hostname_hash)
280 && base_hash != curr_hash
281 {
282 reasons.push("hostname mismatch (different machines)".to_string());
283 }
284
285 if reasons.is_empty() {
286 None
287 } else {
288 Some(HostMismatchInfo { reasons })
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 fn make_host_info(os: &str, arch: &str) -> HostInfo {
297 HostInfo {
298 os: os.to_string(),
299 arch: arch.to_string(),
300 cpu_count: None,
301 memory_bytes: None,
302 hostname_hash: None,
303 }
304 }
305
306 #[test]
307 fn no_mismatch_when_identical() {
308 let baseline = make_host_info("linux", "x86_64");
309 let current = make_host_info("linux", "x86_64");
310 assert!(detect_host_mismatch(&baseline, ¤t).is_none());
311 }
312
313 #[test]
314 fn detects_os_mismatch() {
315 let baseline = make_host_info("linux", "x86_64");
316 let current = make_host_info("windows", "x86_64");
317 let mismatch = detect_host_mismatch(&baseline, ¤t);
318 assert!(mismatch.is_some());
319 let reasons = mismatch.unwrap().reasons;
320 assert!(reasons.iter().any(|r| r.contains("OS mismatch")));
321 assert!(reasons.iter().any(|r| r.contains("baseline=linux")));
322 assert!(reasons.iter().any(|r| r.contains("current=windows")));
323 }
324
325 #[test]
326 fn detects_arch_mismatch() {
327 let baseline = make_host_info("linux", "x86_64");
328 let current = make_host_info("linux", "aarch64");
329 let mismatch = detect_host_mismatch(&baseline, ¤t);
330 assert!(mismatch.is_some());
331 let reasons = mismatch.unwrap().reasons;
332 assert!(reasons.iter().any(|r| r.contains("architecture mismatch")));
333 assert!(reasons.iter().any(|r| r.contains("baseline=x86_64")));
334 assert!(reasons.iter().any(|r| r.contains("current=aarch64")));
335 }
336
337 #[test]
338 fn detects_cpu_count_significant_difference() {
339 let mut baseline = make_host_info("linux", "x86_64");
340 let mut current = make_host_info("linux", "x86_64");
341 baseline.cpu_count = Some(4);
342 current.cpu_count = Some(16);
343 let mismatch = detect_host_mismatch(&baseline, ¤t);
344 assert!(mismatch.is_some());
345 let reasons = mismatch.unwrap().reasons;
346 assert!(reasons.iter().any(|r| r.contains("CPU count differs")));
347 assert!(reasons.iter().any(|r| r.contains("4.0x")));
348 }
349
350 #[test]
351 fn ignores_cpu_count_minor_difference() {
352 let mut baseline = make_host_info("linux", "x86_64");
353 let mut current = make_host_info("linux", "x86_64");
354 baseline.cpu_count = Some(8);
355 current.cpu_count = Some(12);
356 let mismatch = detect_host_mismatch(&baseline, ¤t);
357 assert!(mismatch.is_none());
358 }
359
360 #[test]
361 fn cpu_count_at_exact_2x_threshold_is_not_mismatch() {
362 let mut baseline = make_host_info("linux", "x86_64");
363 let mut current = make_host_info("linux", "x86_64");
364 baseline.cpu_count = Some(4);
365 current.cpu_count = Some(8);
366 let mismatch = detect_host_mismatch(&baseline, ¤t);
367 assert!(mismatch.is_none());
368 }
369
370 #[test]
371 fn cpu_count_just_over_2x_is_mismatch() {
372 let mut baseline = make_host_info("linux", "x86_64");
373 let mut current = make_host_info("linux", "x86_64");
374 baseline.cpu_count = Some(4);
375 current.cpu_count = Some(9);
376 let mismatch = detect_host_mismatch(&baseline, ¤t);
377 assert!(mismatch.is_some());
378 let reasons = mismatch.unwrap().reasons;
379 assert!(reasons.iter().any(|r| r.contains("CPU count differs")));
380 }
381
382 #[test]
383 fn detects_memory_significant_difference() {
384 let mut baseline = make_host_info("linux", "x86_64");
385 let mut current = make_host_info("linux", "x86_64");
386 baseline.memory_bytes = Some(8 * 1024 * 1024 * 1024);
387 current.memory_bytes = Some(32 * 1024 * 1024 * 1024);
388 let mismatch = detect_host_mismatch(&baseline, ¤t);
389 assert!(mismatch.is_some());
390 let reasons = mismatch.unwrap().reasons;
391 assert!(reasons.iter().any(|r| r.contains("memory differs")));
392 assert!(reasons.iter().any(|r| r.contains("8.0GB")));
393 assert!(reasons.iter().any(|r| r.contains("32.0GB")));
394 }
395
396 #[test]
397 fn ignores_memory_minor_difference() {
398 let mut baseline = make_host_info("linux", "x86_64");
399 let mut current = make_host_info("linux", "x86_64");
400 baseline.memory_bytes = Some(16 * 1024 * 1024 * 1024);
401 current.memory_bytes = Some(24 * 1024 * 1024 * 1024);
402 let mismatch = detect_host_mismatch(&baseline, ¤t);
403 assert!(mismatch.is_none());
404 }
405
406 #[test]
407 fn memory_at_exact_2x_threshold_is_not_mismatch() {
408 let mut baseline = make_host_info("linux", "x86_64");
409 let mut current = make_host_info("linux", "x86_64");
410 baseline.memory_bytes = Some(8 * 1024 * 1024 * 1024);
411 current.memory_bytes = Some(16 * 1024 * 1024 * 1024);
412 let mismatch = detect_host_mismatch(&baseline, ¤t);
413 assert!(mismatch.is_none());
414 }
415
416 #[test]
417 fn detects_hostname_difference() {
418 let mut baseline = make_host_info("linux", "x86_64");
419 let mut current = make_host_info("linux", "x86_64");
420 baseline.hostname_hash = Some("abc123".to_string());
421 current.hostname_hash = Some("def456".to_string());
422 let mismatch = detect_host_mismatch(&baseline, ¤t);
423 assert!(mismatch.is_some());
424 let reasons = mismatch.unwrap().reasons;
425 assert!(reasons.iter().any(|r| r.contains("hostname mismatch")));
426 }
427
428 #[test]
429 fn ignores_hostname_when_only_baseline_has_it() {
430 let mut baseline = make_host_info("linux", "x86_64");
431 let current = make_host_info("linux", "x86_64");
432 baseline.hostname_hash = Some("abc123".to_string());
433 let mismatch = detect_host_mismatch(&baseline, ¤t);
434 assert!(mismatch.is_none());
435 }
436
437 #[test]
438 fn ignores_hostname_when_only_current_has_it() {
439 let baseline = make_host_info("linux", "x86_64");
440 let mut current = make_host_info("linux", "x86_64");
441 current.hostname_hash = Some("def456".to_string());
442 let mismatch = detect_host_mismatch(&baseline, ¤t);
443 assert!(mismatch.is_none());
444 }
445
446 #[test]
447 fn ignores_hostname_when_both_are_none() {
448 let baseline = make_host_info("linux", "x86_64");
449 let current = make_host_info("linux", "x86_64");
450 let mismatch = detect_host_mismatch(&baseline, ¤t);
451 assert!(mismatch.is_none());
452 }
453
454 #[test]
455 fn same_hostname_hash_is_not_mismatch() {
456 let mut baseline = make_host_info("linux", "x86_64");
457 let mut current = make_host_info("linux", "x86_64");
458 baseline.hostname_hash = Some("abc123".to_string());
459 current.hostname_hash = Some("abc123".to_string());
460 let mismatch = detect_host_mismatch(&baseline, ¤t);
461 assert!(mismatch.is_none());
462 }
463
464 #[test]
465 fn detects_multiple_simultaneous_mismatches() {
466 let baseline = HostInfo {
467 os: "linux".to_string(),
468 arch: "x86_64".to_string(),
469 cpu_count: Some(4),
470 memory_bytes: Some(8 * 1024 * 1024 * 1024),
471 hostname_hash: Some("abc".to_string()),
472 };
473 let current = HostInfo {
474 os: "windows".to_string(),
475 arch: "aarch64".to_string(),
476 cpu_count: Some(32),
477 memory_bytes: Some(64 * 1024 * 1024 * 1024),
478 hostname_hash: Some("def".to_string()),
479 };
480 let mismatch = detect_host_mismatch(&baseline, ¤t);
481 assert!(mismatch.is_some());
482 let reasons = mismatch.unwrap().reasons;
483 assert_eq!(reasons.len(), 5);
484 }
485
486 #[test]
487 fn partial_fields_none_handling_cpu() {
488 let mut baseline = make_host_info("linux", "x86_64");
489 let mut current = make_host_info("linux", "x86_64");
490 baseline.cpu_count = Some(4);
491 current.cpu_count = None;
492 let mismatch = detect_host_mismatch(&baseline, ¤t);
493 assert!(mismatch.is_none());
494 }
495
496 #[test]
497 fn partial_fields_none_handling_memory() {
498 let mut baseline = make_host_info("linux", "x86_64");
499 let mut current = make_host_info("linux", "x86_64");
500 baseline.memory_bytes = None;
501 current.memory_bytes = Some(32 * 1024 * 1024 * 1024);
502 let mismatch = detect_host_mismatch(&baseline, ¤t);
503 assert!(mismatch.is_none());
504 }
505
506 #[test]
507 fn zero_cpu_count_is_handled_gracefully() {
508 let mut baseline = make_host_info("linux", "x86_64");
509 let mut current = make_host_info("linux", "x86_64");
510 baseline.cpu_count = Some(0);
511 current.cpu_count = Some(8);
512 let mismatch = detect_host_mismatch(&baseline, ¤t);
513 assert!(mismatch.is_none());
514 }
515
516 #[test]
517 fn zero_memory_is_handled_gracefully() {
518 let mut baseline = make_host_info("linux", "x86_64");
519 let mut current = make_host_info("linux", "x86_64");
520 baseline.memory_bytes = Some(0);
521 current.memory_bytes = Some(32 * 1024 * 1024 * 1024);
522 let mismatch = detect_host_mismatch(&baseline, ¤t);
523 assert!(mismatch.is_none());
524 }
525
526 #[test]
527 fn cpu_count_ratio_works_both_directions() {
528 let mut baseline = make_host_info("linux", "x86_64");
529 let mut current = make_host_info("linux", "x86_64");
530
531 baseline.cpu_count = Some(16);
532 current.cpu_count = Some(4);
533 let mismatch = detect_host_mismatch(&baseline, ¤t);
534 assert!(mismatch.is_some());
535 }
536
537 #[test]
538 fn memory_ratio_works_both_directions() {
539 let mut baseline = make_host_info("linux", "x86_64");
540 let mut current = make_host_info("linux", "x86_64");
541
542 baseline.memory_bytes = Some(64 * 1024 * 1024 * 1024);
543 current.memory_bytes = Some(8 * 1024 * 1024 * 1024);
544 let mismatch = detect_host_mismatch(&baseline, ¤t);
545 assert!(mismatch.is_some());
546 }
547
548 #[test]
549 fn identical_fully_populated_no_mismatch() {
550 let host = HostInfo {
551 os: "linux".to_string(),
552 arch: "x86_64".to_string(),
553 cpu_count: Some(8),
554 memory_bytes: Some(16 * 1024 * 1024 * 1024),
555 hostname_hash: Some("abc123def456".to_string()),
556 };
557 assert!(detect_host_mismatch(&host, &host.clone()).is_none());
558 }
559
560 #[test]
561 fn equal_cpu_count_no_mismatch() {
562 let mut baseline = make_host_info("linux", "x86_64");
563 let mut current = make_host_info("linux", "x86_64");
564 baseline.cpu_count = Some(16);
565 current.cpu_count = Some(16);
566 assert!(detect_host_mismatch(&baseline, ¤t).is_none());
567 }
568
569 #[test]
570 fn equal_memory_no_mismatch() {
571 let mut baseline = make_host_info("linux", "x86_64");
572 let mut current = make_host_info("linux", "x86_64");
573 baseline.memory_bytes = Some(32 * 1024 * 1024 * 1024);
574 current.memory_bytes = Some(32 * 1024 * 1024 * 1024);
575 assert!(detect_host_mismatch(&baseline, ¤t).is_none());
576 }
577
578 #[test]
579 fn os_mismatch_reason_contains_both_values() {
580 let baseline = make_host_info("macos", "x86_64");
581 let current = make_host_info("linux", "x86_64");
582 let reasons = detect_host_mismatch(&baseline, ¤t).unwrap().reasons;
583 assert_eq!(reasons.len(), 1);
584 assert!(reasons[0].contains("macos"));
585 assert!(reasons[0].contains("linux"));
586 }
587
588 #[test]
589 fn arch_mismatch_reason_contains_both_values() {
590 let baseline = make_host_info("linux", "arm64");
591 let current = make_host_info("linux", "x86_64");
592 let reasons = detect_host_mismatch(&baseline, ¤t).unwrap().reasons;
593 assert_eq!(reasons.len(), 1);
594 assert!(reasons[0].contains("arm64"));
595 assert!(reasons[0].contains("x86_64"));
596 }
597
598 #[test]
599 fn cpu_mismatch_reason_contains_counts_and_ratio() {
600 let mut baseline = make_host_info("linux", "x86_64");
601 let mut current = make_host_info("linux", "x86_64");
602 baseline.cpu_count = Some(2);
603 current.cpu_count = Some(8);
604 let reasons = detect_host_mismatch(&baseline, ¤t).unwrap().reasons;
605 assert!(reasons[0].contains("baseline=2"));
606 assert!(reasons[0].contains("current=8"));
607 assert!(reasons[0].contains("4.0x"));
608 }
609
610 #[test]
611 fn hostname_mismatch_only_one_reason() {
612 let mut baseline = make_host_info("linux", "x86_64");
613 let mut current = make_host_info("linux", "x86_64");
614 baseline.hostname_hash = Some("aaa".to_string());
615 current.hostname_hash = Some("bbb".to_string());
616 let reasons = detect_host_mismatch(&baseline, ¤t).unwrap().reasons;
617 assert_eq!(reasons.len(), 1);
618 assert!(reasons[0].contains("hostname mismatch"));
619 }
620
621 #[test]
622 fn multiple_mismatches_os_and_arch() {
623 let baseline = make_host_info("linux", "x86_64");
624 let current = make_host_info("windows", "aarch64");
625 let reasons = detect_host_mismatch(&baseline, ¤t).unwrap().reasons;
626 assert_eq!(reasons.len(), 2);
627 assert!(reasons.iter().any(|r| r.contains("OS mismatch")));
628 assert!(reasons.iter().any(|r| r.contains("architecture mismatch")));
629 }
630
631 #[test]
632 fn all_none_optional_fields_no_mismatch() {
633 let baseline = HostInfo {
634 os: "linux".to_string(),
635 arch: "x86_64".to_string(),
636 cpu_count: None,
637 memory_bytes: None,
638 hostname_hash: None,
639 };
640 let current = baseline.clone();
641 assert!(detect_host_mismatch(&baseline, ¤t).is_none());
642 }
643
644 #[test]
645 fn both_zero_cpu_and_zero_memory_no_mismatch() {
646 let mut baseline = make_host_info("linux", "x86_64");
647 let mut current = make_host_info("linux", "x86_64");
648 baseline.cpu_count = Some(0);
649 current.cpu_count = Some(0);
650 baseline.memory_bytes = Some(0);
651 current.memory_bytes = Some(0);
652 assert!(detect_host_mismatch(&baseline, ¤t).is_none());
653 }
654}
655
656#[cfg(test)]
657mod property_tests {
658 use super::*;
659 use proptest::prelude::*;
660
661 fn host_info_strategy() -> impl Strategy<Value = HostInfo> {
662 (
663 "[a-z]{3,10}",
664 "[a-z0-9_]{3,10}",
665 proptest::option::of(1u32..256u32),
666 proptest::option::of(1u64..68719476736u64),
667 proptest::option::of("[a-f0-9]{16}"),
668 )
669 .prop_map(
670 |(os, arch, cpu_count, memory_bytes, hostname_hash)| HostInfo {
671 os,
672 arch,
673 cpu_count,
674 memory_bytes,
675 hostname_hash,
676 },
677 )
678 }
679
680 proptest! {
681 #[test]
682 fn idempotence_same_host_returns_none(host in host_info_strategy()) {
683 prop_assert!(detect_host_mismatch(&host, &host).is_none());
684 }
685
686 #[test]
687 fn symmetry_detect_a_b_implies_detect_b_a(
688 baseline in host_info_strategy(),
689 current in host_info_strategy()
690 ) {
691 let forward = detect_host_mismatch(&baseline, ¤t);
692 let reverse = detect_host_mismatch(¤t, &baseline);
693
694 match (&forward, &reverse) {
695 (None, None) => prop_assert!(true),
696 (Some(f), Some(r)) => {
697 prop_assert_eq!(f.reasons.len(), r.reasons.len());
698 }
699 _ => prop_assert!(false, "symmetry violated: forward={:?}, reverse={:?}", forward, reverse),
700 }
701 }
702
703 #[test]
704 fn os_difference_always_detected(
705 os1 in "[a-z]{3,10}",
706 os2 in "[a-z]{3,10}",
707 arch in "[a-z0-9_]{3,10}"
708 ) {
709 prop_assume!(os1 != os2);
710 let baseline = HostInfo {
711 os: os1.clone(),
712 arch: arch.clone(),
713 cpu_count: None,
714 memory_bytes: None,
715 hostname_hash: None,
716 };
717 let current = HostInfo {
718 os: os2.clone(),
719 arch,
720 cpu_count: None,
721 memory_bytes: None,
722 hostname_hash: None,
723 };
724 let mismatch = detect_host_mismatch(&baseline, ¤t);
725 prop_assert!(mismatch.is_some());
726 prop_assert!(mismatch.unwrap().reasons.iter().any(|r| r.contains("OS mismatch")));
727 }
728
729 #[test]
730 fn arch_difference_always_detected(
731 arch1 in "[a-z0-9_]{3,10}",
732 arch2 in "[a-z0-9_]{3,10}",
733 os in "[a-z]{3,10}"
734 ) {
735 prop_assume!(arch1 != arch2);
736 let baseline = HostInfo {
737 os: os.clone(),
738 arch: arch1.clone(),
739 cpu_count: None,
740 memory_bytes: None,
741 hostname_hash: None,
742 };
743 let current = HostInfo {
744 os,
745 arch: arch2.clone(),
746 cpu_count: None,
747 memory_bytes: None,
748 hostname_hash: None,
749 };
750 let mismatch = detect_host_mismatch(&baseline, ¤t);
751 prop_assert!(mismatch.is_some());
752 prop_assert!(mismatch.unwrap().reasons.iter().any(|r| r.contains("architecture mismatch")));
753 }
754
755 #[test]
756 fn cpu_count_2x_plus_1_always_detected(
757 small_cpu in 1u32..100u32,
758 ) {
759 let large_cpu = small_cpu * 2 + 1;
760 let mut baseline = HostInfo {
761 os: "linux".to_string(),
762 arch: "x86_64".to_string(),
763 cpu_count: Some(small_cpu),
764 memory_bytes: None,
765 hostname_hash: None,
766 };
767 let mut current = HostInfo {
768 os: "linux".to_string(),
769 arch: "x86_64".to_string(),
770 cpu_count: Some(large_cpu),
771 memory_bytes: None,
772 hostname_hash: None,
773 };
774
775 let mismatch_forward = detect_host_mismatch(&baseline, ¤t);
776 prop_assert!(mismatch_forward.is_some());
777
778 std::mem::swap(&mut baseline.cpu_count, &mut current.cpu_count);
779 let mismatch_reverse = detect_host_mismatch(&baseline, ¤t);
780 prop_assert!(mismatch_reverse.is_some());
781 }
782
783 #[test]
784 fn cpu_count_exact_2x_not_detected(
785 cpu in 1u32..100u32,
786 ) {
787 let baseline = HostInfo {
788 os: "linux".to_string(),
789 arch: "x86_64".to_string(),
790 cpu_count: Some(cpu),
791 memory_bytes: None,
792 hostname_hash: None,
793 };
794 let current = HostInfo {
795 os: "linux".to_string(),
796 arch: "x86_64".to_string(),
797 cpu_count: Some(cpu * 2),
798 memory_bytes: None,
799 hostname_hash: None,
800 };
801 let mismatch = detect_host_mismatch(&baseline, ¤t);
802 prop_assert!(mismatch.is_none());
803 }
804
805 #[test]
806 fn memory_2x_plus_1gb_always_detected(
807 small_mem_gb in 1u64..32u64,
808 ) {
809 let small_mem = small_mem_gb * 1024 * 1024 * 1024;
810 let large_mem = small_mem * 2 + (1024 * 1024 * 1024);
811 let mut baseline = HostInfo {
812 os: "linux".to_string(),
813 arch: "x86_64".to_string(),
814 cpu_count: None,
815 memory_bytes: Some(small_mem),
816 hostname_hash: None,
817 };
818 let mut current = HostInfo {
819 os: "linux".to_string(),
820 arch: "x86_64".to_string(),
821 cpu_count: None,
822 memory_bytes: Some(large_mem),
823 hostname_hash: None,
824 };
825
826 let mismatch_forward = detect_host_mismatch(&baseline, ¤t);
827 prop_assert!(mismatch_forward.is_some());
828
829 std::mem::swap(&mut baseline.memory_bytes, &mut current.memory_bytes);
830 let mismatch_reverse = detect_host_mismatch(&baseline, ¤t);
831 prop_assert!(mismatch_reverse.is_some());
832 }
833
834 #[test]
835 fn hostname_hash_difference_detected_when_both_present(
836 hash1 in "[a-f0-9]{16}",
837 hash2 in "[a-f0-9]{16}"
838 ) {
839 prop_assume!(hash1 != hash2);
840 let baseline = HostInfo {
841 os: "linux".to_string(),
842 arch: "x86_64".to_string(),
843 cpu_count: None,
844 memory_bytes: None,
845 hostname_hash: Some(hash1),
846 };
847 let current = HostInfo {
848 os: "linux".to_string(),
849 arch: "x86_64".to_string(),
850 cpu_count: None,
851 memory_bytes: None,
852 hostname_hash: Some(hash2),
853 };
854 let mismatch = detect_host_mismatch(&baseline, ¤t);
855 prop_assert!(mismatch.is_some());
856 prop_assert!(mismatch.unwrap().reasons.iter().any(|r| r.contains("hostname mismatch")));
857 }
858
859 #[test]
860 fn none_fields_do_not_cause_mismatch(
861 host in host_info_strategy()
862 ) {
863 let minimal = HostInfo {
864 os: host.os.clone(),
865 arch: host.arch.clone(),
866 cpu_count: None,
867 memory_bytes: None,
868 hostname_hash: None,
869 };
870 let mismatch = detect_host_mismatch(&host, &minimal);
871 prop_assert!(mismatch.is_none());
872 }
873 }
874}