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