Skip to content

feat: add comprehensive fuzz testing suite with 11 targets - #52

Open
sunsided wants to merge 1 commit into
ge3224:mainfrom
sunsided:feature/fuzzing
Open

feat: add comprehensive fuzz testing suite with 11 targets#52
sunsided wants to merge 1 commit into
ge3224:mainfrom
sunsided:feature/fuzzing

Conversation

@sunsided

@sunsided sunsided commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Hey hey. I figured that parsing is a good candidate for fuzz testing, so I added the following suites for cargo-fuzz to the project:

  • parse_str: main Gedcom::new + parse_data on UTF-8 text
  • parse_bytes: GedcomBuilder with encoding detection and size limit
  • stream_parser: streaming parser via BufRead
  • detect_encoding: encoding detection + ANSEL decoder exercise
  • detect_version: version line scanner
  • escape_at_roundtrip: property-based @ escaping roundtrip
  • name_parse: NameType::parse for name string parsing
  • date_qualifier: DateQualifier::parse (ABT, BEF, AFT, etc.)
  • writer_roundtrip: parse → write → re-parse idempotence
  • encode_decode_roundtrip: encode_to_bytes → decode roundtrip
  • gedzip_read: ZIP reader + full GEDCOM parse

It includes a seed corpus from test fixtures, GEDCOM dictionary file, fuzz README with invocations, and .cargo/config.toml aliases.

The sad reality? Nothing is found, the parser was already perfect. 🤡 No hard feelings at all if this is closed as-is.

How to run

To run the main parser test, this should work:

cargo +nightly fuzz-all

- parse_str: main Gedcom::new + parse_data on UTF-8 text
- parse_bytes: GedcomBuilder with encoding detection and size limit
- stream_parser: streaming parser via BufRead
- detect_encoding: encoding detection + ANSEL decoder exercise
- detect_version: version line scanner
- escape_at_roundtrip: property-based @ escaping roundtrip
- name_parse: NameType::parse for name string parsing
- date_qualifier: DateQualifier::parse (ABT, BEF, AFT, etc.)
- writer_roundtrip: parse → write → re-parse idempotence
- encode_decode_roundtrip: encode_to_bytes → decode roundtrip
- gedzip_read: ZIP reader + full GEDCOM parse

Includes seed corpus from test fixtures, GEDCOM dictionary file,
fuzz README with invocations, and .cargo/config.toml aliases
Copilot AI review requested due to automatic review settings April 29, 2026 23:03

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a cargo-fuzz harness to stress-test ged_io’s parsing/encoding/writing pipelines with multiple fuzz targets plus supporting docs/config.

Changes:

  • Introduces 11 new libFuzzer fuzz targets covering parsing, streaming parsing, encoding detection, writer roundtrips, and GEDZIP reading.
  • Adds fuzzing infrastructure (fuzz/ crate, seed dictionary, README) and Cargo aliases for common fuzz invocations.
  • Updates lockfiles (both fuzz/Cargo.lock and the repository root Cargo.lock).

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
fuzz/fuzz_targets/writer_roundtrip.rs Roundtrip parse → write → parse fuzz target
fuzz/fuzz_targets/stream_parser.rs Streaming parser fuzz target via BufRead
fuzz/fuzz_targets/parse_str.rs UTF-8 &str parser fuzz target
fuzz/fuzz_targets/parse_bytes.rs Byte pipeline fuzz target via GedcomBuilder
fuzz/fuzz_targets/name_parse.rs NameType::parse fuzz target
fuzz/fuzz_targets/gedzip_read.rs GEDZIP reader fuzz target
fuzz/fuzz_targets/escape_at_roundtrip.rs Property-style fuzz target for @ escaping
fuzz/fuzz_targets/encode_decode_roundtrip.rs Encode/decode roundtrip fuzz target per encoding
fuzz/fuzz_targets/detect_version.rs Version detection fuzz target
fuzz/fuzz_targets/detect_encoding.rs Encoding detection + decode fuzz target
fuzz/fuzz_targets/date_qualifier.rs DateQualifier::parse fuzz target
fuzz/dict/gedcom.dict Fuzzing dictionary tokens for GEDCOM inputs
fuzz/README.md Fuzzing documentation and invocation examples
fuzz/Cargo.toml cargo-fuzz crate manifest and target registration
fuzz/Cargo.lock Lockfile for fuzz crate dependencies
fuzz/.gitignore Ignores fuzz artifacts/corpus/coverage
.cargo/config.toml Cargo aliases for running fuzz targets
Cargo.lock Root lockfile dependency updates

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fuzz/Cargo.toml
Comment on lines +19 to +25
name = "fuzz_target_1"
path = "fuzz_targets/fuzz_target_1.rs"
test = false
doc = false
bench = false

[[bin]]
};
let escaped = ged_io::util::escape_at_signs(&input.s, input.is_gedcom_7);
let unescaped = ged_io::util::unescape_at_signs(&escaped, input.is_gedcom_7);
if !input.is_gedcom_7 || !input.s[1..].contains('@') {
Comment thread .cargo/config.toml
Comment on lines +2 to +3
# run with "cargo +nightly fuzz-..."
fuzz-all = "fuzz run parse_str -- -dict=fuzz/dict/gedcom.dict -max_len=65536"
Comment on lines +5 to +12
fuzz_target!(|data: &[u8]| {
if data.is_empty() {
return;
}
let _ = ged_io::detect_encoding(data);
let _ = ged_io::decode_gedcom_bytes(data);
for enc in [
ged_io::GedcomEncoding::Utf8,
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
Comment on lines +28 to +30
if let Ok(mut g2) = ged_io::Gedcom::new(output.chars()) {
let _ = g2.parse_data();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants