summaryrefslogtreecommitdiff
path: root/cli/tools/test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/test.rs')
-rw-r--r--cli/tools/test.rs305
1 files changed, 117 insertions, 188 deletions
diff --git a/cli/tools/test.rs b/cli/tools/test.rs
index 6f32d69e4..159de8ec8 100644
--- a/cli/tools/test.rs
+++ b/cli/tools/test.rs
@@ -2,18 +2,20 @@
use crate::args::CliOptions;
use crate::args::FilesConfig;
-use crate::args::TestOptions;
+use crate::args::Flags;
+use crate::args::TestFlags;
use crate::colors;
use crate::display;
use crate::factory::CliFactory;
+use crate::factory::CliFactoryBuilder;
use crate::file_fetcher::File;
use crate::file_fetcher::FileFetcher;
use crate::graph_util::graph_valid_with_cli_options;
+use crate::graph_util::has_graph_root_local_dependent_changed;
use crate::module_loader::ModuleLoadPreparer;
use crate::ops;
use crate::util::checksum;
use crate::util::file_watcher;
-use crate::util::file_watcher::ResolutionResult;
use crate::util::fs::collect_specifiers;
use crate::util::path::get_extension;
use crate::util::path::is_supported_ext;
@@ -62,7 +64,6 @@ use std::io::Read;
use std::io::Write;
use std::num::NonZeroUsize;
use std::path::Path;
-use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
@@ -1641,11 +1642,12 @@ async fn fetch_specifiers_with_test_mode(
}
pub async fn run_tests(
- cli_options: CliOptions,
- test_options: TestOptions,
+ flags: Flags,
+ test_flags: TestFlags,
) -> Result<(), AnyError> {
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
+ let factory = CliFactory::from_flags(flags).await?;
let cli_options = factory.cli_options();
+ let test_options = cli_options.resolve_test_options(test_flags)?;
let file_fetcher = factory.file_fetcher()?;
let module_load_preparer = factory.module_load_preparer().await?;
// Various test files should not share the same permissions in terms of
@@ -1708,186 +1710,9 @@ pub async fn run_tests(
}
pub async fn run_tests_with_watch(
- cli_options: CliOptions,
- test_options: TestOptions,
+ flags: Flags,
+ test_flags: TestFlags,
) -> Result<(), AnyError> {
- let factory = CliFactory::from_cli_options(Arc::new(cli_options));
- let cli_options = factory.cli_options();
- let module_graph_builder = factory.module_graph_builder().await?;
- let module_load_preparer = factory.module_load_preparer().await?;
- let file_fetcher = factory.file_fetcher()?;
- let file_watcher = factory.file_watcher()?;
- // Various test files should not share the same permissions in terms of
- // `PermissionsContainer` - otherwise granting/revoking permissions in one
- // file would have impact on other files, which is undesirable.
- let permissions =
- Permissions::from_options(&cli_options.permissions_options())?;
- let graph_kind = cli_options.type_check_mode().as_graph_kind();
- let log_level = cli_options.log_level();
-
- let resolver = |changed: Option<Vec<PathBuf>>| {
- let paths_to_watch = test_options.files.include.clone();
- let paths_to_watch_clone = paths_to_watch.clone();
- let files_changed = changed.is_some();
- let test_options = &test_options;
- let cli_options = cli_options.clone();
- let module_graph_builder = module_graph_builder.clone();
-
- async move {
- let test_modules = if test_options.doc {
- collect_specifiers(&test_options.files, is_supported_test_ext)
- } else {
- collect_specifiers(&test_options.files, is_supported_test_path)
- }?;
-
- let mut paths_to_watch = paths_to_watch_clone;
- let mut modules_to_reload = if files_changed {
- Vec::new()
- } else {
- test_modules.clone()
- };
- let graph = module_graph_builder
- .create_graph(graph_kind, test_modules.clone())
- .await?;
- graph_valid_with_cli_options(&graph, &test_modules, &cli_options)?;
-
- // TODO(@kitsonk) - This should be totally derivable from the graph.
- for specifier in test_modules {
- fn get_dependencies<'a>(
- graph: &'a deno_graph::ModuleGraph,
- maybe_module: Option<&'a deno_graph::Module>,
- // This needs to be accessible to skip getting dependencies if they're already there,
- // otherwise this will cause a stack overflow with circular dependencies
- output: &mut HashSet<&'a ModuleSpecifier>,
- ) {
- if let Some(module) = maybe_module.and_then(|m| m.esm()) {
- for dep in module.dependencies.values() {
- if let Some(specifier) = &dep.get_code() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- if let Some(specifier) = &dep.get_type() {
- if !output.contains(specifier) {
- output.insert(specifier);
- get_dependencies(graph, graph.get(specifier), output);
- }
- }
- }
- }
- }
-
- // This test module and all it's dependencies
- let mut modules = HashSet::new();
- modules.insert(&specifier);
- get_dependencies(&graph, graph.get(&specifier), &mut modules);
-
- paths_to_watch.extend(
- modules
- .iter()
- .filter_map(|specifier| specifier.to_file_path().ok()),
- );
-
- if let Some(changed) = &changed {
- for path in changed
- .iter()
- .filter_map(|path| ModuleSpecifier::from_file_path(path).ok())
- {
- if modules.contains(&path) {
- modules_to_reload.push(specifier);
- break;
- }
- }
- }
- }
-
- Ok((paths_to_watch, modules_to_reload))
- }
- .map(move |result| {
- if files_changed
- && matches!(result, Ok((_, ref modules)) if modules.is_empty())
- {
- ResolutionResult::Ignore
- } else {
- match result {
- Ok((paths_to_watch, modules_to_reload)) => {
- ResolutionResult::Restart {
- paths_to_watch,
- result: Ok(modules_to_reload),
- }
- }
- Err(e) => ResolutionResult::Restart {
- paths_to_watch,
- result: Err(e),
- },
- }
- }
- })
- };
-
- let create_cli_main_worker_factory =
- factory.create_cli_main_worker_factory_func().await?;
- let operation = |modules_to_reload: Vec<ModuleSpecifier>| {
- let permissions = &permissions;
- let test_options = &test_options;
- file_watcher.reset();
- let cli_options = cli_options.clone();
- let file_fetcher = file_fetcher.clone();
- let module_load_preparer = module_load_preparer.clone();
- let create_cli_main_worker_factory = create_cli_main_worker_factory.clone();
-
- async move {
- let worker_factory = Arc::new(create_cli_main_worker_factory());
- let specifiers_with_mode = fetch_specifiers_with_test_mode(
- &file_fetcher,
- &test_options.files,
- &test_options.doc,
- )
- .await?
- .into_iter()
- .filter(|(specifier, _)| modules_to_reload.contains(specifier))
- .collect::<Vec<(ModuleSpecifier, TestMode)>>();
-
- check_specifiers(
- &cli_options,
- &file_fetcher,
- &module_load_preparer,
- specifiers_with_mode.clone(),
- )
- .await?;
-
- if test_options.no_run {
- return Ok(());
- }
-
- test_specifiers(
- worker_factory,
- permissions,
- specifiers_with_mode
- .into_iter()
- .filter_map(|(s, m)| match m {
- TestMode::Documentation => None,
- _ => Some(s),
- })
- .collect(),
- TestSpecifiersOptions {
- concurrent_jobs: test_options.concurrent_jobs,
- fail_fast: test_options.fail_fast,
- log_level,
- specifier: TestSpecifierOptions {
- filter: TestFilter::from_flag(&test_options.filter),
- shuffle: test_options.shuffle,
- trace_ops: test_options.trace_ops,
- },
- },
- )
- .await?;
-
- Ok(())
- }
- };
-
// On top of the sigint handlers which are added and unbound for each test
// run, a process-scoped basic exit handler is required due to a tokio
// limitation where it doesn't unbind its own handler for the entire process
@@ -1901,14 +1726,118 @@ pub async fn run_tests_with_watch(
}
});
- let clear_screen = !cli_options.no_clear_screen();
+ let clear_screen = !flags.no_clear_screen;
file_watcher::watch_func(
- resolver,
- operation,
+ flags,
file_watcher::PrintConfig {
job_name: "Test".to_string(),
clear_screen,
},
+ move |flags, sender, changed_paths| {
+ let test_flags = test_flags.clone();
+ Ok(async move {
+ let factory = CliFactoryBuilder::new()
+ .with_watcher(sender.clone())
+ .build_from_flags(flags)
+ .await?;
+ let cli_options = factory.cli_options();
+ let test_options = cli_options.resolve_test_options(test_flags)?;
+
+ if let Some(watch_paths) = cli_options.watch_paths() {
+ let _ = sender.send(watch_paths);
+ }
+ let _ = sender.send(test_options.files.include.clone());
+
+ let graph_kind = cli_options.type_check_mode().as_graph_kind();
+ let log_level = cli_options.log_level();
+ let cli_options = cli_options.clone();
+ let module_graph_builder = factory.module_graph_builder().await?;
+ let file_fetcher = factory.file_fetcher()?;
+ let test_modules = if test_options.doc {
+ collect_specifiers(&test_options.files, is_supported_test_ext)
+ } else {
+ collect_specifiers(&test_options.files, is_supported_test_path)
+ }?;
+ let permissions =
+ Permissions::from_options(&cli_options.permissions_options())?;
+
+ let graph = module_graph_builder
+ .create_graph(graph_kind, test_modules.clone())
+ .await?;
+ graph_valid_with_cli_options(&graph, &test_modules, &cli_options)?;
+
+ let test_modules_to_reload = if let Some(changed_paths) = changed_paths
+ {
+ let changed_specifiers = changed_paths
+ .into_iter()
+ .filter_map(|p| ModuleSpecifier::from_file_path(p).ok())
+ .collect::<HashSet<_>>();
+ let mut result = Vec::new();
+ for test_module_specifier in test_modules {
+ if has_graph_root_local_dependent_changed(
+ &graph,
+ &test_module_specifier,
+ &changed_specifiers,
+ ) {
+ result.push(test_module_specifier.clone());
+ }
+ }
+ result
+ } else {
+ test_modules.clone()
+ };
+
+ let worker_factory =
+ Arc::new(factory.create_cli_main_worker_factory().await?);
+ let module_load_preparer = factory.module_load_preparer().await?;
+ let specifiers_with_mode = fetch_specifiers_with_test_mode(
+ file_fetcher,
+ &test_options.files,
+ &test_options.doc,
+ )
+ .await?
+ .into_iter()
+ .filter(|(specifier, _)| test_modules_to_reload.contains(specifier))
+ .collect::<Vec<(ModuleSpecifier, TestMode)>>();
+
+ check_specifiers(
+ &cli_options,
+ file_fetcher,
+ module_load_preparer,
+ specifiers_with_mode.clone(),
+ )
+ .await?;
+
+ if test_options.no_run {
+ return Ok(());
+ }
+
+ test_specifiers(
+ worker_factory,
+ &permissions,
+ specifiers_with_mode
+ .into_iter()
+ .filter_map(|(s, m)| match m {
+ TestMode::Documentation => None,
+ _ => Some(s),
+ })
+ .collect(),
+ TestSpecifiersOptions {
+ concurrent_jobs: test_options.concurrent_jobs,
+ fail_fast: test_options.fail_fast,
+ log_level,
+ specifier: TestSpecifierOptions {
+ filter: TestFilter::from_flag(&test_options.filter),
+ shuffle: test_options.shuffle,
+ trace_ops: test_options.trace_ops,
+ },
+ },
+ )
+ .await?;
+
+ Ok(())
+ })
+ },
)
.await?;