summaryrefslogtreecommitdiff
path: root/tests/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'tests/fuzz')
-rw-r--r--tests/fuzz/Cargo.toml27
-rw-r--r--tests/fuzz/src/compile.rs74
-rw-r--r--tests/fuzz/src/parse.rs8
3 files changed, 109 insertions, 0 deletions
diff --git a/tests/fuzz/Cargo.toml b/tests/fuzz/Cargo.toml
new file mode 100644
index 00000000..1b9e6b26
--- /dev/null
+++ b/tests/fuzz/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "typst-fuzz"
+version.workspace = true
+edition.workspace = true
+publish = false
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+typst = { workspace = true }
+typst-render = { workspace = true }
+typst-syntax = { workspace = true }
+comemo = { workspace = true }
+libfuzzer-sys = { workspace = true }
+
+[[bin]]
+name = "parse"
+path = "src/parse.rs"
+test = false
+doc = false
+
+[[bin]]
+name = "compile"
+path = "src/compile.rs"
+test = false
+doc = false
diff --git a/tests/fuzz/src/compile.rs b/tests/fuzz/src/compile.rs
new file mode 100644
index 00000000..deb71778
--- /dev/null
+++ b/tests/fuzz/src/compile.rs
@@ -0,0 +1,74 @@
+#![no_main]
+
+use comemo::Prehashed;
+use libfuzzer_sys::fuzz_target;
+use typst::diag::{FileError, FileResult};
+use typst::eval::Tracer;
+use typst::foundations::{Bytes, Datetime};
+use typst::syntax::{FileId, Source};
+use typst::text::{Font, FontBook};
+use typst::visualize::Color;
+use typst::{Library, World};
+
+const FONT: &[u8] = include_bytes!("../../../assets/fonts/LinLibertine_R.ttf");
+
+struct FuzzWorld {
+ library: Prehashed<Library>,
+ book: Prehashed<FontBook>,
+ font: Font,
+ source: Source,
+}
+
+impl FuzzWorld {
+ fn new(text: &str) -> Self {
+ let font = Font::new(FONT.into(), 0).unwrap();
+ let book = FontBook::from_fonts([&font]);
+ Self {
+ library: Prehashed::new(Library::build()),
+ book: Prehashed::new(book),
+ font,
+ source: Source::detached(text),
+ }
+ }
+}
+
+impl World for FuzzWorld {
+ fn library(&self) -> &Prehashed<Library> {
+ &self.library
+ }
+
+ fn book(&self) -> &Prehashed<FontBook> {
+ &self.book
+ }
+
+ fn main(&self) -> Source {
+ self.source.clone()
+ }
+
+ fn source(&self, src: FileId) -> FileResult<Source> {
+ Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
+ }
+
+ fn file(&self, src: FileId) -> FileResult<Bytes> {
+ Err(FileError::NotFound(src.vpath().as_rootless_path().into()))
+ }
+
+ fn font(&self, _: usize) -> Option<Font> {
+ Some(self.font.clone())
+ }
+
+ fn today(&self, _: Option<i64>) -> Option<Datetime> {
+ None
+ }
+}
+
+fuzz_target!(|text: &str| {
+ let world = FuzzWorld::new(text);
+ let mut tracer = Tracer::new();
+ if let Ok(document) = typst::compile(&world, &mut tracer) {
+ if let Some(page) = document.pages.first() {
+ std::hint::black_box(typst_render::render(page, 1.0, Color::WHITE));
+ }
+ }
+ comemo::evict(10);
+});
diff --git a/tests/fuzz/src/parse.rs b/tests/fuzz/src/parse.rs
new file mode 100644
index 00000000..f151661a
--- /dev/null
+++ b/tests/fuzz/src/parse.rs
@@ -0,0 +1,8 @@
+#![no_main]
+
+use libfuzzer_sys::fuzz_target;
+use typst_syntax::parse;
+
+fuzz_target!(|text: &str| {
+ std::hint::black_box(parse(text));
+});