feat: pass tests if warnings happens (#1535)

This commit is contained in:
Myriad-Dreamin 2025-03-19 12:02:40 +08:00 committed by GitHub
parent 4bb16b5b93
commit c8c891fbc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 61 additions and 51 deletions

1
.gitignore vendored
View file

@ -12,3 +12,4 @@ editors/lapce/out/
*.pdf *.pdf
.vscode/*.code-workspace .vscode/*.code-workspace
refs/

View file

@ -66,6 +66,10 @@ where
} }
impl<F: CompilerFeat, I: Instrumenter> SourceWorld for InstrumentWorld<'_, F, I> { impl<F: CompilerFeat, I: Instrumenter> SourceWorld for InstrumentWorld<'_, F, I> {
fn as_world(&self) -> &dyn typst::World {
self
}
fn path_for_id(&self, id: FileId) -> FileResult<PathResolution> { fn path_for_id(&self, id: FileId) -> FileResult<PathResolution> {
self.base.path_for_id(id) self.base.path_for_id(id)
} }

View file

@ -7,5 +7,5 @@ pub use tinymist_world::entry::*;
pub use tinymist_world::{font, package, system, vfs}; pub use tinymist_world::{font, package, system, vfs};
pub use tinymist_world::{ pub use tinymist_world::{
with_main, CompilerUniverse, CompilerWorld, DiagnosticFormat, EntryOpts, EntryState, with_main, CompilerUniverse, CompilerWorld, DiagnosticFormat, EntryOpts, EntryState,
RevisingUniverse, TaskInputs, RevisingUniverse, SourceWorld, TaskInputs,
}; };

View file

@ -11,9 +11,9 @@ use tinymist_std::Result;
use tinymist_vfs::FileId; use tinymist_vfs::FileId;
use typst::diag::{eco_format, Severity, SourceDiagnostic}; use typst::diag::{eco_format, Severity, SourceDiagnostic};
use typst::syntax::Span; use typst::syntax::Span;
use typst::{World, WorldExt}; use typst::WorldExt;
use crate::{DiagnosticFormat, SourceWorld}; use crate::{CodeSpanReportWorld, DiagnosticFormat, SourceWorld};
/// Get stderr with color support if desirable. /// Get stderr with color support if desirable.
fn color_stream() -> StandardStream { fn color_stream() -> StandardStream {
@ -25,12 +25,12 @@ fn color_stream() -> StandardStream {
} }
/// Print diagnostic messages to the terminal. /// Print diagnostic messages to the terminal.
pub fn print_diagnostics<'d, 'files, W: SourceWorld>( pub fn print_diagnostics<'d, 'files>(
world: &'files W, world: &'files dyn SourceWorld,
errors: impl Iterator<Item = &'d SourceDiagnostic>, errors: impl Iterator<Item = &'d SourceDiagnostic>,
diagnostic_format: DiagnosticFormat, diagnostic_format: DiagnosticFormat,
) -> Result<(), codespan_reporting::files::Error> { ) -> Result<(), codespan_reporting::files::Error> {
let world = world.for_codespan_reporting(); let world = CodeSpanReportWorld::new(world);
let mut w = match diagnostic_format { let mut w = match diagnostic_format {
DiagnosticFormat::Human => color_stream(), DiagnosticFormat::Human => color_stream(),
@ -77,6 +77,6 @@ pub fn print_diagnostics<'d, 'files, W: SourceWorld>(
} }
/// Create a label for a span. /// Create a label for a span.
fn label<W: World>(world: &W, span: Span) -> Option<Label<FileId>> { fn label(world: &dyn SourceWorld, span: Span) -> Option<Label<FileId>> {
Some(Label::primary(span.id()?, world.range(span)?)) Some(Label::primary(span.id()?, world.range(span)?))
} }

View file

@ -772,43 +772,37 @@ impl typst::World for WorldWithMain<'_> {
} }
pub trait SourceWorld: World { pub trait SourceWorld: World {
fn as_world(&self) -> &dyn World;
fn path_for_id(&self, id: FileId) -> Result<PathResolution, FileError>; fn path_for_id(&self, id: FileId) -> Result<PathResolution, FileError>;
fn lookup(&self, id: FileId) -> Source { fn lookup(&self, id: FileId) -> Source {
self.source(id) self.source(id)
.expect("file id does not point to any source file") .expect("file id does not point to any source file")
} }
fn map_source_or_default<T>(
&self,
id: FileId,
default_v: T,
f: impl FnOnce(Source) -> CodespanResult<T>,
) -> CodespanResult<T> {
match self.source(id).ok() {
Some(source) => f(source),
None => Ok(default_v),
}
}
fn for_codespan_reporting(&self) -> CodeSpanReportWorld<Self>
where
Self: Sized,
{
CodeSpanReportWorld { world: self }
}
} }
impl<F: CompilerFeat> SourceWorld for CompilerWorld<F> { impl<F: CompilerFeat> SourceWorld for CompilerWorld<F> {
fn as_world(&self) -> &dyn World {
self
}
/// Resolve the real path for a file id. /// Resolve the real path for a file id.
fn path_for_id(&self, id: FileId) -> Result<PathResolution, FileError> { fn path_for_id(&self, id: FileId) -> Result<PathResolution, FileError> {
self.path_for_id(id) self.path_for_id(id)
} }
} }
pub struct CodeSpanReportWorld<'a, T> { pub struct CodeSpanReportWorld<'a> {
pub world: &'a T, pub world: &'a dyn SourceWorld,
} }
impl<'a, T: SourceWorld> codespan_reporting::files::Files<'a> for CodeSpanReportWorld<'a, T> { impl<'a> CodeSpanReportWorld<'a> {
pub fn new(world: &'a dyn SourceWorld) -> Self {
Self { world }
}
}
impl<'a> codespan_reporting::files::Files<'a> for CodeSpanReportWorld<'a> {
/// A unique identifier for files in the file provider. This will be used /// A unique identifier for files in the file provider. This will be used
/// for rendering `diagnostic::Label`s in the corresponding source files. /// for rendering `diagnostic::Label`s in the corresponding source files.
type FileId = FileId; type FileId = FileId;
@ -858,14 +852,17 @@ impl<'a, T: SourceWorld> codespan_reporting::files::Files<'a> for CodeSpanReport
/// See [`codespan_reporting::files::Files::line_range`]. /// See [`codespan_reporting::files::Files::line_range`].
fn line_range(&'a self, id: FileId, given: usize) -> CodespanResult<std::ops::Range<usize>> { fn line_range(&'a self, id: FileId, given: usize) -> CodespanResult<std::ops::Range<usize>> {
self.world.map_source_or_default(id, 0..0, |source| { match self.world.source(id).ok() {
source Some(source) => {
.line_to_range(given) source
.ok_or_else(|| CodespanError::LineTooLarge { .line_to_range(given)
given, .ok_or_else(|| CodespanError::LineTooLarge {
max: source.len_lines(), given,
}) max: source.len_lines(),
}) })
}
None => Ok(0..0),
}
} }
} }
@ -883,27 +880,27 @@ impl<'a, F: CompilerFeat> codespan_reporting::files::Files<'a> for CompilerWorld
/// The user-facing name of a file. /// The user-facing name of a file.
fn name(&'a self, id: FileId) -> CodespanResult<Self::Name> { fn name(&'a self, id: FileId) -> CodespanResult<Self::Name> {
self.for_codespan_reporting().name(id) CodeSpanReportWorld::new(self).name(id)
} }
/// The source code of a file. /// The source code of a file.
fn source(&'a self, id: FileId) -> CodespanResult<Self::Source> { fn source(&'a self, id: FileId) -> CodespanResult<Self::Source> {
self.for_codespan_reporting().source(id) CodeSpanReportWorld::new(self).source(id)
} }
/// See [`codespan_reporting::files::Files::line_index`]. /// See [`codespan_reporting::files::Files::line_index`].
fn line_index(&'a self, id: FileId, given: usize) -> CodespanResult<usize> { fn line_index(&'a self, id: FileId, given: usize) -> CodespanResult<usize> {
self.for_codespan_reporting().line_index(id, given) CodeSpanReportWorld::new(self).line_index(id, given)
} }
/// See [`codespan_reporting::files::Files::column_number`]. /// See [`codespan_reporting::files::Files::column_number`].
fn column_number(&'a self, id: FileId, _: usize, given: usize) -> CodespanResult<usize> { fn column_number(&'a self, id: FileId, _: usize, given: usize) -> CodespanResult<usize> {
self.for_codespan_reporting().column_number(id, 0, given) CodeSpanReportWorld::new(self).column_number(id, 0, given)
} }
/// See [`codespan_reporting::files::Files::line_range`]. /// See [`codespan_reporting::files::Files::line_range`].
fn line_range(&'a self, id: FileId, given: usize) -> CodespanResult<std::ops::Range<usize>> { fn line_range(&'a self, id: FileId, given: usize) -> CodespanResult<std::ops::Range<usize>> {
self.for_codespan_reporting().line_range(id, given) CodeSpanReportWorld::new(self).line_range(id, given)
} }
} }

View file

@ -10,14 +10,14 @@ use itertools::Either;
use parking_lot::Mutex; use parking_lot::Mutex;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use reflexo::ImmutPath; use reflexo::ImmutPath;
use reflexo_typst::{vfs::FileId, SourceWorld, TypstDocument, TypstHtmlDocument}; use reflexo_typst::{vfs::FileId, TypstDocument, TypstHtmlDocument};
use tinymist_debug::CoverageResult; use tinymist_debug::CoverageResult;
use tinymist_project::world::{system::print_diagnostics, DiagnosticFormat}; use tinymist_project::world::{system::print_diagnostics, DiagnosticFormat};
use tinymist_query::analysis::Analysis; use tinymist_query::analysis::Analysis;
use tinymist_query::syntax::{cast_include_expr, find_source_by_expr, node_ancestors}; use tinymist_query::syntax::{cast_include_expr, find_source_by_expr, node_ancestors};
use tinymist_query::testing::{TestCaseKind, TestSuites}; use tinymist_query::testing::{TestCaseKind, TestSuites};
use tinymist_std::{bail, error::prelude::*, fs::paths::write_atomic, typst::TypstPagedDocument}; use tinymist_std::{bail, error::prelude::*, fs::paths::write_atomic, typst::TypstPagedDocument};
use typst::diag::SourceDiagnostic; use typst::diag::{Severity, SourceDiagnostic};
use typst::ecow::EcoVec; use typst::ecow::EcoVec;
use typst::foundations::{Context, Label}; use typst::foundations::{Context, Label};
use typst::syntax::{ast, LinkedNode, Source, Span}; use typst::syntax::{ast, LinkedNode, Source, Span};
@ -25,7 +25,7 @@ use typst::{utils::PicoStr, World};
use typst_shim::eval::TypstEngine; use typst_shim::eval::TypstEngine;
use super::project::{start_project, StartProjectResult}; use super::project::{start_project, StartProjectResult};
use crate::world::with_main; use crate::world::{with_main, SourceWorld};
use crate::{project::*, utils::exit_on_ctrl_c}; use crate::{project::*, utils::exit_on_ctrl_c};
const TEST_EVICT_MAX_AGE: usize = 30; const TEST_EVICT_MAX_AGE: usize = 30;
@ -239,7 +239,7 @@ fn test_once(world: &LspWorld, ctx: &TestContext) -> Result<bool> {
let result = if ctx.args.coverage { let result = if ctx.args.coverage {
let (cov, result) = tinymist_debug::with_cov(world, |world| { let (cov, result) = tinymist_debug::with_cov(world, |world| {
let suites = suites.recheck(world); let suites = suites.recheck(world);
let runner = TestRunner::new(ctx, &world, &suites); let runner = TestRunner::new(ctx, world, &suites);
let result = print_diag_or_error(world, runner.run()); let result = print_diag_or_error(world, runner.run());
comemo::evict(TEST_EVICT_MAX_AGE); comemo::evict(TEST_EVICT_MAX_AGE);
result result
@ -248,7 +248,7 @@ fn test_once(world: &LspWorld, ctx: &TestContext) -> Result<bool> {
result result
} else { } else {
let suites = suites.recheck(world); let suites = suites.recheck(world);
let runner = TestRunner::new(ctx, &world, &suites); let runner = TestRunner::new(ctx, world, &suites);
comemo::evict(TEST_EVICT_MAX_AGE); comemo::evict(TEST_EVICT_MAX_AGE);
runner.run() runner.run()
}; };
@ -294,7 +294,7 @@ impl TestContext {
struct TestRunner<'a> { struct TestRunner<'a> {
ctx: &'a TestContext, ctx: &'a TestContext,
world: &'a dyn World, world: &'a dyn SourceWorld,
suites: &'a TestSuites, suites: &'a TestSuites,
diagnostics: Mutex<Vec<EcoVec<SourceDiagnostic>>>, diagnostics: Mutex<Vec<EcoVec<SourceDiagnostic>>>,
examples: Mutex<HashSet<String>>, examples: Mutex<HashSet<String>>,
@ -302,7 +302,7 @@ struct TestRunner<'a> {
} }
impl<'a> TestRunner<'a> { impl<'a> TestRunner<'a> {
fn new(ctx: &'a TestContext, world: &'a dyn World, suites: &'a TestSuites) -> Self { fn new(ctx: &'a TestContext, world: &'a dyn SourceWorld, suites: &'a TestSuites) -> Self {
Self { Self {
ctx, ctx,
world, world,
@ -366,7 +366,7 @@ impl<'a> TestRunner<'a> {
let name = &test.name; let name = &test.name;
let func = &test.function; let func = &test.function;
let world = with_main(self.world, test.location); let world = with_main(self.world.as_world(), test.location);
let mut engine = TypstEngine::new(&world); let mut engine = TypstEngine::new(&world);
// Executes the function // Executes the function
@ -409,7 +409,15 @@ impl<'a> TestRunner<'a> {
{ {
let diagnostics = self.diagnostics.into_inner(); let diagnostics = self.diagnostics.into_inner();
if !diagnostics.is_empty() { if !diagnostics.is_empty() {
Err(diagnostics.into_iter().flatten().collect::<EcoVec<_>>())? let diagnostics = diagnostics.into_iter().flatten().collect::<EcoVec<_>>();
let any_error = diagnostics.iter().any(|d| d.severity == Severity::Error);
if any_error {
Err(diagnostics)?
} else {
print_diagnostics(self.world, diagnostics.iter(), DiagnosticFormat::Human)
.context_ut("print diagnostics")?;
}
} }
} }
Ok(!self.failed.load(std::sync::atomic::Ordering::SeqCst)) Ok(!self.failed.load(std::sync::atomic::Ordering::SeqCst))
@ -425,7 +433,7 @@ impl<'a> TestRunner<'a> {
return; return;
} }
let world = with_main(self.world, test.id()); let world = with_main(self.world.as_world(), test.id());
let mut has_err = false; let mut has_err = false;
let (has_err_, doc) = self.build_example::<TypstPagedDocument>(&world); let (has_err_, doc) = self.build_example::<TypstPagedDocument>(&world);
has_err |= has_err_ || self.render_paged(name, doc.as_ref()); has_err |= has_err_ || self.render_paged(name, doc.as_ref());