130 lines · 4.7 KB · Rust
RawDownload
mod fuzzed {    #[test]    fn ewah_artifacts_run_fuzzer() {        for path in artifact_paths("ewah") {            let data = std::fs::read(path).expect("artifact is readable");            let _ = gix_bitmap::ewah::decode(&data);        }    }     #[test]    fn runaway_run_length_is_rejected() {        let (bitmap, rest) = gix_bitmap::ewah::decode(include_bytes!(            "../fuzz/artifacts/ewah/slow-unit-ac817962d1a6c123d4d1f73860f5b779423ed171"        ))        .expect("fixture must decode");         assert!(rest.is_empty(), "fixture should be fully consumed");        assert_eq!(            bitmap.for_each_set_bit(|_| Some(())),            None,            "impossible run lengths must be rejected instead of iterating unboundedly"        );    }     #[test]    fn non_zero_padding_bits_in_last_literal_word_are_rejected() {        let bitmap = gix_bitmap::ewah::Vec::from_bits(&[false]).expect("small test fixtures must fit into u32");        let mut data = Vec::new();        bitmap            .write_to(&mut data)            .expect("writing a valid test fixture to bytes must succeed");        let header_size = 4 + 4;        // Skip the fixed-size header and the RLW word, then flip bit 33 in the first literal word        // so the bitmap stays logically empty while the serialized padding becomes invalid.        let literal_word_offset = header_size + 8;        let mut literal_word = u64::from_be_bytes(            data[literal_word_offset..literal_word_offset + 8]                .try_into()                .expect("literal word"),        );        literal_word |= 1u64 << 33;        data[literal_word_offset..literal_word_offset + 8].copy_from_slice(&literal_word.to_be_bytes());         let (bitmap, rest) = gix_bitmap::ewah::decode(&data).expect("fixture must decode");         assert!(rest.is_empty(), "fixture should be fully consumed");        assert_eq!(            bitmap.for_each_set_bit(|_| Some(())),            None,            "set bits outside the declared bit length must be rejected"        );    }     #[test]    fn literal_only_bitmaps_preserve_all_set_bits() {        for bits in [            vec![],            vec![false],            vec![true],            vec![true, false, true, false, true],            (0..64).map(|idx| idx % 3 == 0).collect(),            (0..65).map(|idx| idx == 0 || idx == 63 || idx == 64).collect(),            (0..130).map(|idx| idx == 1 || idx == 64 || idx == 129).collect(),        ] {            let bitmap = gix_bitmap::ewah::Vec::from_bits(&bits).expect("small test fixtures must fit into u32");            let mut encoded = Vec::new();            let expected: Vec<_> = bits                .iter()                .enumerate()                .filter_map(|(idx, bit)| bit.then_some(idx))                .collect();             bitmap                .write_to(&mut encoded)                .expect("writing a valid test fixture to bytes must succeed");            let (bitmap, rest) = gix_bitmap::ewah::decode(&encoded).expect("serialized test fixture must decode");            let mut actual = Vec::new();             assert!(rest.is_empty(), "serialized test fixture should be fully consumed");            assert_eq!(                bitmap.num_bits(),                bits.len(),                "fixture should preserve the declared bit length"            );            assert_eq!(                bitmap.for_each_set_bit(|idx| {                    actual.push(idx);                    Some(())                }),                Some(()),                "well-formed literal-only bitmaps must iterate successfully"            );            assert_eq!(                actual, expected,                "iteration should report exactly the set bits from the source bitmap"            );        }    }     #[test]    fn zero_padding_bits_in_last_literal_word_are_accepted() {        let bitmap =            gix_bitmap::ewah::Vec::from_bits(&[true, false, true]).expect("small test fixtures must fit into u32");        let mut actual = Vec::new();         assert_eq!(            bitmap.for_each_set_bit(|idx| {                actual.push(idx);                Some(())            }),            Some(()),            "unused bits in the last partial word are valid when they are zero"        );        assert_eq!(actual, vec![0, 2], "iteration should ignore zero padding bits");    }     fn artifact_paths(target: &str) -> Vec<std::path::PathBuf> {        std::fs::read_dir(            std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))                .join("fuzz/artifacts")                .join(target),        )        .ok()        .into_iter()        .flatten()        .filter_map(Result::ok)        .map(|entry| entry.path())        .collect()    }}