diff --git a/Makefile b/Makefile index 1a43b56..f1147a3 100644 --- a/Makefile +++ b/Makefile @@ -18,5 +18,8 @@ clippy: ## run clippy journeytests: ## run journey tests ./tests/cat.sh +fuzz: ## run fuzz tests for 30 seconds + cargo install cargo-fuzz + cargo fuzz run round-trip -- -only_ascii=1 -max_total_time=30 -tests: docs clippy unittests journeytests ## run all tests +tests: docs clippy unittests journeytests fuzz ## run all tests diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..1a45eee --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..c470d78 --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,104 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "10.0.4" +dependencies = [ + "pulldown-cmark", +] + +[[package]] +name = "pulldown-cmark-to-cmark-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "pulldown-cmark", + "pulldown-cmark-to-cmark", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..4830225 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "pulldown-cmark-to-cmark-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +pulldown-cmark = { version = "0.9.0", default-features = false } + +[dependencies.pulldown-cmark-to-cmark] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "round-trip" +path = "fuzz_targets/round-trip.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/round-trip.rs b/fuzz/fuzz_targets/round-trip.rs new file mode 100644 index 0000000..d3d0042 --- /dev/null +++ b/fuzz/fuzz_targets/round-trip.rs @@ -0,0 +1,42 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use pulldown_cmark::Parser; +use pulldown_cmark_to_cmark::cmark; + +fn round_trip(text: &str) -> String { + let mut result = String::with_capacity(text.len()); + cmark(Parser::new(&text), &mut result).unwrap(); + result +} + +fn print_events(text: &str) { + eprintln!("{text:?} -> ["); + for event in Parser::new(&text) { + eprintln!(" {event:?}"); + } + eprintln!("]"); +} + +fuzz_target!(|text: String| { + let round_trip_1 = round_trip(&text); + let round_trip_2 = round_trip(&round_trip_1); + let round_trip_3 = round_trip(&round_trip_2); + let round_trip_4 = round_trip(&round_trip_3); + if round_trip_3 != round_trip_4 { + print_events(&text); + print_events(&round_trip_1); + print_events(&round_trip_2); + print_events(&round_trip_3); + print_events(&round_trip_4); + + panic!( + "round-trip failed:\n\ + -- {text:?}\n\ + -> {round_trip_1:?}\n\ + -> {round_trip_2:?}\n\ + -> {round_trip_3:?}\n\ + -> {round_trip_4:?}" + ); + } +});