//! ## Octant iterator tests mod octant_bounds { use clipline::{Octant0, Octant1, Octant2, Octant3, Octant4, Octant5, Octant6, Octant7}; #[test] fn all_octants_exclude_empty_line() { assert!(Octant0::::new((0, 0), (0, 0)).is_none()); assert!(Octant1::::new((0, 0), (0, 0)).is_none()); assert!(Octant2::::new((0, 0), (0, 0)).is_none()); assert!(Octant3::::new((0, 0), (0, 0)).is_none()); assert!(Octant4::::new((0, 0), (0, 0)).is_none()); assert!(Octant5::::new((0, 0), (0, 0)).is_none()); assert!(Octant6::::new((0, 0), (0, 0)).is_none()); assert!(Octant7::::new((0, 0), (0, 0)).is_none()); } #[test] fn octant_0_excludes_0_and_includes_45_degrees() { assert!(Octant0::::new((0, 0), (1, 0)).is_none()); assert!(Octant0::::new((0, 0), (1, 1)).is_some()); } #[test] fn octant_1_excludes_45_degrees_and_excludes_90_degrees() { assert!(Octant1::::new((0, 0), (1, 1)).is_none()); assert!(Octant1::::new((0, 0), (0, 1)).is_none()); } #[test] fn octant_2_includes_315_degrees_and_excludes_0_degrees() { assert!(Octant2::::new((0, 0), (1, -1)).is_some()); assert!(Octant2::::new((0, 0), (1, 0)).is_none()); } #[test] fn octant_3_excludes_270_degrees_and_excludes_315_degrees() { assert!(Octant3::::new((0, 0), (0, -1)).is_none()); assert!(Octant3::::new((0, 0), (1, -1)).is_none()); } #[test] fn octant_4_includes_135_and_excludes_180_degrees() { assert!(Octant4::::new((0, 0), (-1, 1)).is_some()); assert!(Octant4::::new((0, 0), (-1, 0)).is_none()); } #[test] fn octant_5_excludes_90_and_excludes_135_degrees() { assert!(Octant5::::new((0, 0), (0, 1)).is_none()); assert!(Octant5::::new((0, 0), (-1, 1)).is_none()); } #[test] fn octant_6_excludes_180_degrees_and_includes_225_degrees() { assert!(Octant6::::new((0, 0), (-1, 0)).is_none()); assert!(Octant6::::new((0, 0), (-1, -1)).is_some()); } #[test] fn octant_7_excludes_225_degrees_and_excludes_270_degrees() { assert!(Octant7::::new((0, 0), (-1, -1)).is_none()); assert!(Octant7::::new((0, 0), (0, -1)).is_none()); } } mod iterator { use clipline::{Octant0, Octant1, Octant2, Octant3, Octant4, Octant5, Octant6, Octant7}; #[test] fn octant_0_produces_correct_points() { let points = vec![(0, 0), (1, 0), (2, 1), (3, 1), (4, 2)]; assert_eq!(Octant0::::new((0, 0), (5, 2)).unwrap().collect::>(), points); } #[test] fn octant_1_produces_correct_points() { let points = vec![(0, 0), (0, 1), (1, 2), (1, 3), (2, 4)]; assert_eq!(Octant1::::new((0, 0), (2, 5)).unwrap().collect::>(), points); } #[test] fn octant_2_produces_correct_points() { let points = vec![(0, 0), (1, 0), (2, -1), (3, -1), (4, -2)]; assert_eq!(Octant2::::new((0, 0), (5, -2)).unwrap().collect::>(), points); } #[test] fn octant_3_produces_correct_points() { let points = vec![(0, 0), (0, -1), (1, -2), (1, -3), (2, -4)]; assert_eq!(Octant3::::new((0, 0), (2, -5)).unwrap().collect::>(), points); } #[test] fn octant_4_produces_correct_points() { let points = vec![(0, 0), (-1, 0), (-2, 1), (-3, 1), (-4, 2)]; assert_eq!(Octant4::::new((0, 0), (-5, 2)).unwrap().collect::>(), points); } #[test] fn octant_5_produces_correct_points() { let points = vec![(0, 0), (0, 1), (-1, 2), (-1, 3), (-2, 4)]; assert_eq!(Octant5::::new((0, 0), (-2, 5)).unwrap().collect::>(), points); } #[test] fn octant_6_produces_correct_points() { let points = vec![(0, 0), (-1, 0), (-2, -1), (-3, -1), (-4, -2)]; assert_eq!(Octant6::::new((0, 0), (-5, -2)).unwrap().collect::>(), points); } #[test] fn octant_7_produces_correct_points() { let points = vec![(0, 0), (0, -1), (-1, -2), (-1, -3), (-2, -4)]; assert_eq!(Octant7::::new((0, 0), (-2, -5)).unwrap().collect::>(), points); } } mod proptest { use clipline::{AnyOctant, Clip, Point}; use proptest::prelude::{prop_assert, proptest, ProptestConfig}; fn config() -> ProptestConfig { ProptestConfig { cases: 4000000, failure_persistence: None, ..ProptestConfig::default() } } mod u8 { use super::*; const MIN: u8 = 0; const MAX: u8 = 255; const HALF_0: u8 = 127; const HALF_1: u8 = 128; const QUARTER_0: u8 = 63; const QUARTER_1: u8 = 64; const QUARTER_2: u8 = 191; const QUARTER_3: u8 = 192; const CLIPS: [(&str, Point, Point); 37] = [ ("FULL", (MIN, MIN), (MAX, MAX)), ("POINT", (HALF_0, HALF_0), (HALF_0, HALF_0)), ("SMALL", (HALF_0, HALF_0), (HALF_1, HALF_1)), ("CENTER HALF-SIZE 0", (QUARTER_0, QUARTER_1), (QUARTER_2, QUARTER_3)), ("CENTER HALF-SIZE 1", (QUARTER_1, QUARTER_0), (QUARTER_3, QUARTER_2)), ("TOP-LEFT-CENTER QUARTER-SIZE 0", (QUARTER_0, QUARTER_0), (HALF_0, HALF_0)), ("TOP-LEFT-CENTER QUARTER-SIZE 1", (QUARTER_0, QUARTER_1), (HALF_1, HALF_0)), ("TOP-LEFT-CENTER QUARTER-SIZE 2", (QUARTER_1, QUARTER_0), (HALF_0, HALF_1)), ("TOP-LEFT-CENTER QUARTER-SIZE 3", (QUARTER_1, QUARTER_1), (HALF_1, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 0", (HALF_0, QUARTER_0), (QUARTER_2, HALF_0)), ("TOP-RIGHT-CENTER QUARTER-SIZE 1", (HALF_0, QUARTER_1), (QUARTER_3, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 2", (HALF_1, QUARTER_0), (QUARTER_2, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 3", (HALF_1, QUARTER_1), (QUARTER_3, HALF_0)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 0", (QUARTER_0, HALF_0), (HALF_0, QUARTER_2)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 1", (QUARTER_0, HALF_1), (HALF_1, QUARTER_3)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 2", (QUARTER_1, HALF_0), (HALF_0, QUARTER_2)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 3", (QUARTER_1, HALF_1), (HALF_1, QUARTER_3)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 0", (HALF_0, HALF_0), (QUARTER_3, QUARTER_2)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 1", (HALF_0, HALF_1), (QUARTER_3, QUARTER_3)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 2", (HALF_1, HALF_0), (QUARTER_2, QUARTER_2)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 3", (HALF_1, HALF_1), (QUARTER_2, QUARTER_3)), ("TOP-LEFT QUARTER 0", (MIN, MIN), (QUARTER_0, QUARTER_0)), ("TOP-LEFT QUARTER 1", (MIN, MIN), (QUARTER_1, QUARTER_1)), ("TOP-RIGHT QUARTER 0", (QUARTER_2, MIN), (MAX, QUARTER_2)), ("TOP-RIGHT QUARTER 1", (QUARTER_3, MIN), (MAX, QUARTER_3)), ("BOTTOM-LEFT QUARTER 0", (MIN, QUARTER_2), (QUARTER_2, MAX)), ("BOTTOM-LEFT QUARTER 1", (MIN, QUARTER_3), (QUARTER_3, MAX)), ("BOTTOM-RIGHT QUARTER 0", (QUARTER_2, QUARTER_2), (MAX, MAX)), ("BOTTOM-RIGHT QUARTER 1", (QUARTER_3, QUARTER_3), (MAX, MAX)), ("TOP HALF 0", (MIN, MIN), (MAX, HALF_0)), ("TOP HALF 1", (MIN, MIN), (MAX, HALF_1)), ("BOTTOM HALF 0", (MIN, HALF_0), (MAX, MAX)), ("BOTTOM HALF 1", (MIN, HALF_1), (MAX, MAX)), ("LEFT HALF 0", (MIN, MIN), (HALF_0, MAX)), ("LEFT HALF 1", (MIN, MIN), (HALF_1, MAX)), ("RIGHT HALF 0", (HALF_0, MIN), (MAX, MAX)), ("RIGHT HALF 1", (HALF_1, MIN), (MAX, MAX)), ]; proptest! { #![proptest_config(config())] #[test] fn clipped_matches_unclipped( clip in proptest::sample::select(&CLIPS), ((p1, p2)): (Point, Point) ) { let (_, w1, w2) = clip; let clip = Clip::::new(w1, w2).unwrap(); let clipped = clip.any_octant(p1, p2).into_iter().flatten(); let naive_clipped = AnyOctant::::new(p1, p2).filter(|&xy| clip.point(xy)); prop_assert!(clipped.eq(naive_clipped)); } } } mod i8 { use super::*; const MIN: i8 = -128; const MAX: i8 = 127; const HALF_0: i8 = 0; const HALF_1: i8 = 1; const QUARTER_0: i8 = -64; const QUARTER_1: i8 = -63; const QUARTER_2: i8 = 64; const QUARTER_3: i8 = 65; const CLIPS: [(&str, Point, Point); 37] = [ ("FULL", (MIN, MIN), (MAX, MAX)), ("POINT", (HALF_0, HALF_0), (HALF_0, HALF_0)), ("SMALL", (HALF_0, HALF_0), (HALF_1, HALF_1)), ("CENTER HALF-SIZE 0", (QUARTER_0, QUARTER_1), (QUARTER_2, QUARTER_3)), ("CENTER HALF-SIZE 1", (QUARTER_1, QUARTER_0), (QUARTER_3, QUARTER_2)), ("TOP-LEFT-CENTER QUARTER-SIZE 0", (QUARTER_0, QUARTER_0), (HALF_0, HALF_0)), ("TOP-LEFT-CENTER QUARTER-SIZE 1", (QUARTER_0, QUARTER_1), (HALF_1, HALF_0)), ("TOP-LEFT-CENTER QUARTER-SIZE 2", (QUARTER_1, QUARTER_0), (HALF_0, HALF_1)), ("TOP-LEFT-CENTER QUARTER-SIZE 3", (QUARTER_1, QUARTER_1), (HALF_1, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 0", (HALF_0, QUARTER_0), (QUARTER_2, HALF_0)), ("TOP-RIGHT-CENTER QUARTER-SIZE 1", (HALF_0, QUARTER_1), (QUARTER_3, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 2", (HALF_1, QUARTER_0), (QUARTER_2, HALF_1)), ("TOP-RIGHT-CENTER QUARTER-SIZE 3", (HALF_1, QUARTER_1), (QUARTER_3, HALF_0)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 0", (QUARTER_0, HALF_0), (HALF_0, QUARTER_2)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 1", (QUARTER_0, HALF_1), (HALF_1, QUARTER_3)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 2", (QUARTER_1, HALF_0), (HALF_0, QUARTER_2)), ("BOTTOM-LEFT-CENTER QUARTER-SIZE 3", (QUARTER_1, HALF_1), (HALF_1, QUARTER_3)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 0", (HALF_0, HALF_0), (QUARTER_3, QUARTER_2)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 1", (HALF_0, HALF_1), (QUARTER_3, QUARTER_3)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 2", (HALF_1, HALF_0), (QUARTER_2, QUARTER_2)), ("BOTTOM-RIGHT-CENTER QUARTER-SIZE 3", (HALF_1, HALF_1), (QUARTER_2, QUARTER_3)), ("TOP-LEFT QUARTER 0", (MIN, MIN), (QUARTER_0, QUARTER_0)), ("TOP-LEFT QUARTER 1", (MIN, MIN), (QUARTER_1, QUARTER_1)), ("TOP-RIGHT QUARTER 0", (QUARTER_2, MIN), (MAX, QUARTER_2)), ("TOP-RIGHT QUARTER 1", (QUARTER_3, MIN), (MAX, QUARTER_3)), ("BOTTOM-LEFT QUARTER 0", (MIN, QUARTER_2), (QUARTER_2, MAX)), ("BOTTOM-LEFT QUARTER 1", (MIN, QUARTER_3), (QUARTER_3, MAX)), ("BOTTOM-RIGHT QUARTER 0", (QUARTER_2, QUARTER_2), (MAX, MAX)), ("BOTTOM-RIGHT QUARTER 1", (QUARTER_3, QUARTER_3), (MAX, MAX)), ("TOP HALF 0", (MIN, MIN), (MAX, HALF_0)), ("TOP HALF 1", (MIN, MIN), (MAX, HALF_1)), ("BOTTOM HALF 0", (MIN, HALF_0), (MAX, MAX)), ("BOTTOM HALF 1", (MIN, HALF_1), (MAX, MAX)), ("LEFT HALF 0", (MIN, MIN), (HALF_0, MAX)), ("LEFT HALF 1", (MIN, MIN), (HALF_1, MAX)), ("RIGHT HALF 0", (HALF_0, MIN), (MAX, MAX)), ("RIGHT HALF 1", (HALF_1, MIN), (MAX, MAX)), ]; proptest! { #![proptest_config(config())] #[test] fn clipped_matches_unclipped( clip in proptest::sample::select(&CLIPS), ((p1, p2)): (Point, Point) ) { let (_, w1, w2) = clip; let clip = Clip::::new(w1, w2).unwrap(); let clipped = clip.any_octant(p1, p2).into_iter().flatten(); let naive_clipped = AnyOctant::::new(p1, p2).filter(|&xy| clip.point(xy)); prop_assert!(clipped.eq(naive_clipped)); } } } }