summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-06-26 13:57:21 +0200
committerLaurenz <laurmaedje@gmail.com>2023-06-27 18:40:17 +0200
commit7b92bd7c340d9f9c094ed2fa57912049317d9b20 (patch)
treeb91399526ba94d87309d09d864df2935dd7a4d0a /tests
parent9c7f31870b4e1bf37df79ebbe1df9a56df83d878 (diff)
Basic package management
Diffstat (limited to 'tests')
-rw-r--r--tests/Cargo.toml1
-rw-r--r--tests/packages/adder-0.1.0/lib.typ1
-rw-r--r--tests/packages/adder-0.1.0/typst.toml4
-rw-r--r--tests/src/benches.rs31
-rw-r--r--tests/src/tests.rs143
-rw-r--r--tests/typ/compiler/hint.typ10
-rw-r--r--tests/typ/compiler/packages.typ64
-rw-r--r--tests/typ/visualize/image.typ4
8 files changed, 151 insertions, 107 deletions
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
index 1912f50a..c87ecc79 100644
--- a/tests/Cargo.toml
+++ b/tests/Cargo.toml
@@ -10,7 +10,6 @@ publish = false
typst = { path = ".." }
typst-library = { path = "../library" }
comemo = "0.3"
-elsa = "1.8"
iai = { git = "https://github.com/reknih/iai" }
once_cell = "1"
oxipng = "8.0.0"
diff --git a/tests/packages/adder-0.1.0/lib.typ b/tests/packages/adder-0.1.0/lib.typ
new file mode 100644
index 00000000..217e7930
--- /dev/null
+++ b/tests/packages/adder-0.1.0/lib.typ
@@ -0,0 +1 @@
+#let add(x, y) = x + y
diff --git a/tests/packages/adder-0.1.0/typst.toml b/tests/packages/adder-0.1.0/typst.toml
new file mode 100644
index 00000000..b8d62f99
--- /dev/null
+++ b/tests/packages/adder-0.1.0/typst.toml
@@ -0,0 +1,4 @@
+[package]
+name = "adder"
+version = "0.1.0"
+entrypoint = "lib.typ"
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<FontBook> {
+ &self.book
}
- fn resolve(&self, path: &Path) -> FileResult<SourceId> {
- Err(FileError::NotFound(path.into()))
+ fn main(&self) -> Source {
+ self.source.clone()
}
- fn source(&self, _: SourceId) -> &Source {
- &self.source
+ fn source(&self, _: FileId) -> FileResult<Source> {
+ unimplemented!()
}
- fn book(&self) -> &Prehashed<FontBook> {
- &self.book
+ fn file(&self, _: FileId) -> FileResult<Bytes> {
+ unimplemented!()
}
fn font(&self, _: usize) -> Option<Font> {
Some(self.font.clone())
}
- fn file(&self, path: &Path) -> FileResult<Buffer> {
- Err(FileError::NotFound(path.into()))
- }
-
fn today(&self, _: Option<i64>) -> Option<Datetime> {
- 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<Library>,
book: Prehashed<FontBook>,
fonts: Vec<Font>,
paths: RefCell<HashMap<PathBuf, PathSlot>>,
- sources: FrozenVec<Box<Source>>,
- 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<FileResult<SourceId>>,
- buffer: OnceCell<FileResult<Buffer>>,
+ system_path: PathBuf,
+ source: OnceCell<FileResult<Source>>,
+ buffer: OnceCell<FileResult<Bytes>>,
}
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<Library> {
&self.library
}
- fn main(&self) -> &Source {
- self.source(self.main)
+ fn book(&self) -> &Prehashed<FontBook> {
+ &self.book
+ }
+
+ fn main(&self) -> Source {
+ self.source(self.main).unwrap()
}
- fn resolve(&self, path: &Path) -> FileResult<SourceId> {
- self.slot(path)
- .source
+ fn source(&self, id: FileId) -> FileResult<Source> {
+ 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<FontBook> {
- &self.book
+ fn file(&self, id: FileId) -> FileResult<Bytes> {
+ let slot = self.slot(id)?;
+ slot.buffer
+ .get_or_init(|| read(&slot.system_path).map(Bytes::from))
+ .clone()
}
fn font(&self, id: usize) -> Option<Font> {
Some(self.fonts[id].clone())
}
- fn file(&self, path: &Path) -> FileResult<Buffer> {
- self.slot(path)
- .buffer
- .get_or_init(|| read(path).map(Buffer::from))
- .clone()
- }
-
fn today(&self, _: Option<i64>) -> Option<Datetime> {
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<RefMut<PathSlot>> {
+ 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<PathSlot> {
- 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<Frame>) {
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<UserOutput> = 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::<Vec<_>>()
})
.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);
diff --git a/tests/typ/compiler/hint.typ b/tests/typ/compiler/hint.typ
index 19d233d0..fdd5f59b 100644
--- a/tests/typ/compiler/hint.typ
+++ b/tests/typ/compiler/hint.typ
@@ -1,4 +1,4 @@
-// Test diagnostics.
+// Test hints on diagnostics.
// Ref: false
---
@@ -23,13 +23,17 @@
---
= Heading <intro>
+
// Error: 1:20-1:26 cannot reference heading without numbering
-// Hint: 1:20-1:26 did you mean to use `#set heading(numbering: "1.")`?
+// Hint: 1:20-1:26 you can enable heading numbering with `#set heading(numbering: "1.")`?
Can not be used as @intro
---
+// This test is more of a tooling test. It checks if hint annotation validation
+// can be turned off.
// Hints: false
-// This test is more of a tooling test. It checks if hint annotation validation can be turned off.
+
= Heading <intro>
+
// Error: 1:20-1:26 cannot reference heading without numbering
Can not be used as @intro
diff --git a/tests/typ/compiler/packages.typ b/tests/typ/compiler/packages.typ
new file mode 100644
index 00000000..066a31de
--- /dev/null
+++ b/tests/typ/compiler/packages.typ
@@ -0,0 +1,64 @@
+// Test package imports
+// Ref: false
+
+---
+// Test import without items.
+#import "@test/adder:0.1.0"
+#test(adder.add(2, 8), 10)
+
+---
+// Test import with items.
+#import "@test/adder:0.1.0": add
+#test(add(2, 8), 10)
+
+---
+// Error: 9-13 `@` is not a valid package namespace
+#import "@@": *
+
+---
+// Error: 9-16 package specification is missing name
+#import "@heya": *
+
+---
+// Error: 9-15 `123` is not a valid package namespace
+#import "@123": *
+
+---
+// Error: 9-17 package specification is missing name
+#import "@test/": *
+
+---
+// Error: 9-22 package specification is missing version
+#import "@test/mypkg": *
+
+---
+// Error: 9-20 `$$$` is not a valid package name
+#import "@test/$$$": *
+
+---
+// Error: 9-23 package specification is missing version
+#import "@test/mypkg:": *
+
+---
+// Error: 9-24 version number is missing minor version
+#import "@test/mypkg:0": *
+
+---
+// Error: 9-29 `latest` is not a valid major version
+#import "@test/mypkg:latest": *
+
+---
+// Error: 9-29 `-3` is not a valid major version
+#import "@test/mypkg:-3.0.0": *
+
+---
+// Error: 9-26 version number is missing patch version
+#import "@test/mypkg:0.3": *
+
+---
+// Error: 9-27 version number is missing patch version
+#import "@test/mypkg:0.3.": *
+
+---
+// Error: 9-28 file not found (searched at typ/compiler/#test/mypkg:1.0.0)
+#import "#test/mypkg:1.0.0": *
diff --git a/tests/typ/visualize/image.typ b/tests/typ/visualize/image.typ
index dc5b2ef6..7891e7e2 100644
--- a/tests/typ/visualize/image.typ
+++ b/tests/typ/visualize/image.typ
@@ -54,9 +54,9 @@ A #box(image("/tiger.jpg", height: 1cm, width: 80%)) B
#image("path/does/not/exist")
---
-// Error: 8-21 unknown image format
+// Error: 2-22 unknown image format
#image("./image.typ")
---
-// Error: 8-18 failed to parse svg: found closing tag 'g' instead of 'style' in line 4
+// Error: 2-19 failed to parse svg: found closing tag 'g' instead of 'style' in line 4
#image("/bad.svg")