From 7b92bd7c340d9f9c094ed2fa57912049317d9b20 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 26 Jun 2023 13:57:21 +0200 Subject: Basic package management --- tests/src/benches.rs | 31 +++++------ tests/src/tests.rs | 143 +++++++++++++++++++++------------------------------ 2 files changed, 73 insertions(+), 101 deletions(-) (limited to 'tests/src') diff --git a/tests/src/benches.rs b/tests/src/benches.rs index aeddcaf9..9ee7a2f3 100644 --- a/tests/src/benches.rs +++ b/tests/src/benches.rs @@ -1,13 +1,12 @@ -use std::path::Path; - use comemo::{Prehashed, Track, Tracked}; use iai::{black_box, main, Iai}; -use typst::diag::{FileError, FileResult}; +use typst::diag::FileResult; use typst::eval::{Datetime, Library}; +use typst::file::FileId; use typst::font::{Font, FontBook}; use typst::geom::Color; -use typst::syntax::{Source, SourceId}; -use typst::util::Buffer; +use typst::syntax::Source; +use typst::util::Bytes; use typst::World; use unscanny::Scanner; @@ -124,31 +123,27 @@ impl World for BenchWorld { &self.library } - fn main(&self) -> &Source { - &self.source + fn book(&self) -> &Prehashed { + &self.book } - fn resolve(&self, path: &Path) -> FileResult { - Err(FileError::NotFound(path.into())) + fn main(&self) -> Source { + self.source.clone() } - fn source(&self, _: SourceId) -> &Source { - &self.source + fn source(&self, _: FileId) -> FileResult { + unimplemented!() } - fn book(&self) -> &Prehashed { - &self.book + fn file(&self, _: FileId) -> FileResult { + unimplemented!() } fn font(&self, _: usize) -> Option { Some(self.font.clone()) } - fn file(&self, path: &Path) -> FileResult { - Err(FileError::NotFound(path.into())) - } - fn today(&self, _: Option) -> Option { - Some(Datetime::from_ymd(1970, 1, 1).unwrap()) + unimplemented!() } } diff --git a/tests/src/tests.rs b/tests/src/tests.rs index 4aa459af..a2b6e985 100644 --- a/tests/src/tests.rs +++ b/tests/src/tests.rs @@ -13,11 +13,11 @@ use std::path::{Path, PathBuf}; use clap::Parser; use comemo::{Prehashed, Track}; -use elsa::FrozenVec; use oxipng::{InFile, Options, OutFile}; use rayon::iter::{ParallelBridge, ParallelIterator}; use std::cell::OnceCell; use tiny_skia as sk; +use typst::file::FileId; use unscanny::Scanner; use walkdir::WalkDir; @@ -26,8 +26,8 @@ use typst::doc::{Document, Frame, FrameItem, Meta}; use typst::eval::{eco_format, func, Datetime, Library, NoneValue, Value}; use typst::font::{Font, FontBook}; use typst::geom::{Abs, Color, RgbaColor, Smart}; -use typst::syntax::{Source, SourceId, Span, SyntaxNode}; -use typst::util::{Buffer, PathExt}; +use typst::syntax::{Source, Span, SyntaxNode}; +use typst::util::{Bytes, PathExt}; use typst::World; use typst_library::layout::{Margin, PageElem}; use typst_library::text::{TextElem, TextSize}; @@ -197,34 +197,21 @@ fn library() -> Library { } /// A world that provides access to the tests environment. +#[derive(Clone)] struct TestWorld { print: PrintConfig, + main: FileId, library: Prehashed, book: Prehashed, fonts: Vec, paths: RefCell>, - sources: FrozenVec>, - main: SourceId, } -impl Clone for TestWorld { - fn clone(&self) -> Self { - Self { - print: self.print, - library: self.library.clone(), - book: self.book.clone(), - fonts: self.fonts.clone(), - paths: self.paths.clone(), - sources: FrozenVec::from_iter(self.sources.iter().cloned().map(Box::new)), - main: self.main, - } - } -} - -#[derive(Default, Clone)] +#[derive(Clone)] struct PathSlot { - source: OnceCell>, - buffer: OnceCell>, + system_path: PathBuf, + source: OnceCell>, + buffer: OnceCell>, } impl TestWorld { @@ -243,92 +230,81 @@ impl TestWorld { Self { print, + main: FileId::detached(), library: Prehashed::new(library()), book: Prehashed::new(FontBook::from_fonts(&fonts)), fonts, paths: RefCell::default(), - sources: FrozenVec::new(), - main: SourceId::detached(), } } } impl World for TestWorld { - fn root(&self) -> &Path { - Path::new(FILE_DIR) - } - fn library(&self) -> &Prehashed { &self.library } - fn main(&self) -> &Source { - self.source(self.main) + fn book(&self) -> &Prehashed { + &self.book + } + + fn main(&self) -> Source { + self.source(self.main).unwrap() } - fn resolve(&self, path: &Path) -> FileResult { - self.slot(path) - .source + fn source(&self, id: FileId) -> FileResult { + let slot = self.slot(id)?; + slot.source .get_or_init(|| { - let buf = read(path)?; + let buf = read(&slot.system_path)?; let text = String::from_utf8(buf)?; - Ok(self.insert(path, text)) + Ok(Source::new(id, text)) }) .clone() } - fn source(&self, id: SourceId) -> &Source { - &self.sources[id.as_u16() as usize] - } - - fn book(&self) -> &Prehashed { - &self.book + fn file(&self, id: FileId) -> FileResult { + let slot = self.slot(id)?; + slot.buffer + .get_or_init(|| read(&slot.system_path).map(Bytes::from)) + .clone() } fn font(&self, id: usize) -> Option { Some(self.fonts[id].clone()) } - fn file(&self, path: &Path) -> FileResult { - self.slot(path) - .buffer - .get_or_init(|| read(path).map(Buffer::from)) - .clone() - } - fn today(&self, _: Option) -> Option { Some(Datetime::from_ymd(1970, 1, 1).unwrap()) } } impl TestWorld { - fn set(&mut self, path: &Path, text: String) -> SourceId { - let slot = self.slot(path); - let id = if let Some(&Ok(id)) = slot.source.get() { - drop(slot); - self.sources.as_mut()[id.as_u16() as usize].replace(text); - id - } else { - let id = self.insert(path, text); - slot.source.set(Ok(id)).unwrap(); - drop(slot); - id + fn set(&mut self, path: &Path, text: String) -> Source { + self.main = FileId::new(None, path); + let mut slot = self.slot(self.main).unwrap(); + let source = Source::new(self.main, text); + slot.source = OnceCell::from(Ok(source.clone())); + source + } + + fn slot(&self, id: FileId) -> FileResult> { + let path = id.path(); + let root: PathBuf = match id.package() { + Some(spec) => format!("packages/{}-{}", spec.name, spec.version).into(), + None if path.is_relative() => PathBuf::new(), + None => FILE_DIR.into(), }; - self.main = id; - id - } - fn slot(&self, path: &Path) -> RefMut { - RefMut::map(self.paths.borrow_mut(), |paths| { - paths.entry(path.normalize()).or_default() - }) - } + let system_path = root.join_rooted(id.path()).ok_or(FileError::AccessDenied)?; - fn insert(&self, path: &Path, text: String) -> SourceId { - let id = SourceId::from_u16(self.sources.len() as u16); - let source = Source::new(id, path, text); - self.sources.push(Box::new(source)); - id + Ok(RefMut::map(self.paths.borrow_mut(), |paths| { + paths.entry(system_path.clone()).or_insert_with(|| PathSlot { + system_path, + source: OnceCell::new(), + buffer: OnceCell::new(), + }) + })) } } @@ -522,26 +498,25 @@ fn test_part( ) -> (bool, bool, Vec) { let mut ok = true; - let id = world.set(src_path, text); - let source = world.source(id); + let source = world.set(src_path, text); if world.print.syntax { writeln!(output, "Syntax Tree:\n{:#?}\n", source.root()).unwrap(); } - let metadata = parse_part_metadata(source); + let metadata = parse_part_metadata(&source); let compare_ref = metadata.part_configuration.compare_ref.unwrap_or(compare_ref); let validate_hints = metadata.part_configuration.validate_hints.unwrap_or(validate_hints); ok &= test_spans(output, source.root()); - ok &= test_reparse(output, world.source(id).text(), i, rng); + ok &= test_reparse(output, source.text(), i, rng); if world.print.model { let world = (world as &dyn World).track(); let route = typst::eval::Route::default(); let mut tracer = typst::eval::Tracer::default(); let module = - typst::eval::eval(world, route.track(), tracer.track_mut(), source).unwrap(); + typst::eval::eval(world, route.track(), tracer.track_mut(), &source).unwrap(); writeln!(output, "Model:\n{:#?}\n", module.content()).unwrap(); } @@ -563,15 +538,17 @@ fn test_part( // however, as the line of the hint is still verified. let actual_errors_and_hints: HashSet = errors .into_iter() - .filter(|error| error.span.source() == id) + .inspect(|error| assert!(!error.span.is_detached())) + .filter(|error| error.span.id() == source.id()) .flat_map(|error| { + let range = error.span.range(world); let output_error = - UserOutput::Error(error.range(world), error.message.replace('\\', "/")); + UserOutput::Error(range.clone(), error.message.replace('\\', "/")); let hints = error .hints .iter() .filter(|_| validate_hints) // No unexpected hints should be verified if disabled. - .map(|hint| UserOutput::Hint(error.range(world), hint.to_string())); + .map(|hint| UserOutput::Hint(range.clone(), hint.to_string())); iter::once(output_error).chain(hints).collect::>() }) .collect(); @@ -596,12 +573,12 @@ fn test_part( for unexpected in unexpected_outputs { write!(output, " Not annotated | ").unwrap(); - print_user_output(output, source, line, unexpected) + print_user_output(output, &source, line, unexpected) } for missing in missing_outputs { write!(output, " Not emitted | ").unwrap(); - print_user_output(output, source, line, missing) + print_user_output(output, &source, line, missing) } } @@ -820,7 +797,7 @@ fn test_reparse( let source = Source::detached(text); let leafs = leafs(source.root()); - let start = source.range(leafs[pick(0..leafs.len())].span()).start; + let start = source.find(leafs[pick(0..leafs.len())].span()).unwrap().offset(); let supplement = supplements[pick(0..supplements.len())]; ok &= apply(start..start, supplement); -- cgit v1.2.3