diff options
Diffstat (limited to 'cli/tools')
-rw-r--r-- | cli/tools/test_runner.rs | 109 |
1 files changed, 98 insertions, 11 deletions
diff --git a/cli/tools/test_runner.rs b/cli/tools/test_runner.rs index e24d8b458..fdb4be664 100644 --- a/cli/tools/test_runner.rs +++ b/cli/tools/test_runner.rs @@ -1,9 +1,11 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. +use crate::ast; use crate::colors; use crate::create_main_worker; use crate::file_fetcher::File; -use crate::fs_util; +use crate::fs_util::collect_files; +use crate::fs_util::normalize_path; use crate::media_type::MediaType; use crate::module_graph; use crate::program_state::ProgramState; @@ -18,6 +20,7 @@ use deno_core::serde_json::json; use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_runtime::permissions::Permissions; +use regex::Regex; use serde::Deserialize; use std::path::Path; use std::path::PathBuf; @@ -25,6 +28,7 @@ use std::sync::mpsc::channel; use std::sync::mpsc::Sender; use std::sync::Arc; use std::time::Instant; +use swc_common::comments::CommentKind; #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] @@ -198,7 +202,7 @@ fn create_reporter(concurrent: bool) -> Box<dyn TestReporter + Send> { Box::new(PrettyTestReporter::new(concurrent)) } -fn is_supported(p: &Path) -> bool { +pub(crate) fn is_supported(p: &Path) -> bool { use std::path::Component; if let Some(Component::Normal(basename_os_str)) = p.components().next_back() { let basename = basename_os_str.to_string_lossy(); @@ -222,19 +226,22 @@ fn is_supported(p: &Path) -> bool { } } -pub fn collect_test_module_specifiers( +pub fn collect_test_module_specifiers<P>( include: Vec<String>, root_path: &Path, -) -> Result<Vec<Url>, AnyError> { + predicate: P, +) -> Result<Vec<Url>, AnyError> +where + P: Fn(&Path) -> bool, +{ let (include_paths, include_urls): (Vec<String>, Vec<String>) = include.into_iter().partition(|n| !is_remote_url(n)); - let mut prepared = vec![]; for path in include_paths { - let p = fs_util::normalize_path(&root_path.join(path)); + let p = normalize_path(&root_path.join(path)); if p.is_dir() { - let test_files = fs_util::collect_files(&[p], &[], is_supported).unwrap(); + let test_files = collect_files(&[p], &[], &predicate).unwrap(); let test_files_as_urls = test_files .iter() .map(|f| Url::from_file_path(f).unwrap()) @@ -311,6 +318,7 @@ pub async fn run_tests( program_state: Arc<ProgramState>, permissions: Permissions, lib: module_graph::TypeLib, + doc_modules: Vec<ModuleSpecifier>, test_modules: Vec<ModuleSpecifier>, no_run: bool, fail_fast: bool, @@ -327,6 +335,80 @@ pub async fn run_tests( return Ok(false); } + if !doc_modules.is_empty() { + let mut test_programs = Vec::new(); + + let blocks_regex = Regex::new(r"```([^\n]*)\n([\S\s]*?)```")?; + let lines_regex = Regex::new(r"(?:\* ?)(?:\# ?)?(.*)")?; + + for specifier in &doc_modules { + let file = program_state.file_fetcher.get_source(&specifier).unwrap(); + + let parsed_module = + ast::parse(&file.specifier.as_str(), &file.source, &file.media_type)?; + + let mut comments = parsed_module.get_comments(); + comments.sort_by_key(|comment| { + let location = parsed_module.get_location(&comment.span); + location.line + }); + + for comment in comments { + if comment.kind != CommentKind::Block || !comment.text.starts_with('*') + { + continue; + } + + for block in blocks_regex.captures_iter(&comment.text) { + let body = block.get(2).unwrap(); + let text = body.as_str(); + + // TODO(caspervonb) generate an inline source map + let mut source = String::new(); + for line in lines_regex.captures_iter(&text) { + let text = line.get(1).unwrap(); + source.push_str(&format!("{}\n", text.as_str())); + } + + source.push_str("export {};"); + + let element = block.get(0).unwrap(); + let span = comment + .span + .from_inner_byte_pos(element.start(), element.end()); + let location = parsed_module.get_location(&span); + + let specifier = deno_core::resolve_url_or_path(&format!( + "{}:{}-{}", + location.filename, + location.line, + location.line + element.as_str().split('\n').count(), + ))?; + + let file = File { + local: specifier.to_file_path().unwrap(), + maybe_types: None, + media_type: MediaType::TypeScript, // media_type.clone(), + source: source.clone(), + specifier: specifier.clone(), + }; + + program_state.file_fetcher.insert_cached(file.clone()); + test_programs.push(file.specifier.clone()); + } + } + } + + program_state + .prepare_module_graph( + test_programs.clone(), + lib.clone(), + permissions.clone(), + program_state.maybe_import_map.clone(), + ) + .await?; + } + program_state .prepare_module_graph( test_modules.clone(), @@ -343,8 +425,8 @@ pub async fn run_tests( // Because scripts, and therefore worker.execute cannot detect unresolved promises at the moment // we generate a module for the actual test execution. let test_options = json!({ - "disableLog": quiet, - "filter": filter, + "disableLog": quiet, + "filter": filter, }); let test_module = deno_core::resolve_path("$deno$test.js")?; @@ -487,6 +569,7 @@ mod tests { "http://example.com/printf_test.ts".to_string(), ], &test_data_path, + is_supported, ) .unwrap(); let test_data_url = @@ -535,8 +618,12 @@ mod tests { .join("std") .join("http"); println!("root {:?}", root); - let mut matched_urls = - collect_test_module_specifiers(vec![".".to_string()], &root).unwrap(); + let mut matched_urls = collect_test_module_specifiers( + vec![".".to_string()], + &root, + is_supported, + ) + .unwrap(); matched_urls.sort(); let root_url = Url::from_file_path(root).unwrap().to_string(); println!("root_url {}", root_url); |