diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2023-08-30 16:31:31 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-30 16:31:31 +0100 |
commit | d28384c3deec1497d28f0f6bd16cf51de832e572 (patch) | |
tree | b65eb37b3c066f95d69c5ae36798426d617a9119 /cli/lsp/testing/collectors.rs | |
parent | 329698cf73e98bd3347f5b03f5ecb562a6ce9925 (diff) |
refactor(lsp): store test definitions in adjacency list (#20330)
Previously:
```rust
pub struct TestDefinition {
pub id: String,
pub name: String,
pub range: SourceRange,
pub steps: Vec<TestDefinition>,
}
pub struct TestDefinitions {
pub discovered: Vec<TestDefinition>,
pub injected: Vec<lsp_custom::TestData>,
pub script_version: String,
}
```
Now:
```rust
pub struct TestDefinition {
pub id: String,
pub name: String,
pub range: Option<Range>,
pub is_dynamic: bool, // True for 'injected' module, not statically detected but added at runtime.
pub parent_id: Option<String>,
pub step_ids: HashSet<String>,
}
pub struct TestModule {
pub specifier: ModuleSpecifier,
pub script_version: String,
pub defs: HashMap<String, TestDefinition>,
}
```
Storing the test tree as a literal tree diminishes the value of IDs,
even though vscode stores them that way. This makes all data easily
accessible from `TestModule`. It unifies the interface between
'discovered' and 'injected' tests. This unblocks some enhancements wrt
syncing tests between the LSP and extension, such as this TODO:
https://github.com/denoland/vscode_deno/blob/61f08d5a71536a0a5f7dce965955b09e6bd957e1/client/src/testing.ts#L251-L259
and https://github.com/denoland/vscode_deno/issues/900. We should also
get more flexibility overall.
`TestCollector` is cleaned up, now stores a `&mut TestModule` directly
and registers tests as it comes across them with
`TestModule::register()`. This method ensures sanity in the redundant
data from having both of `TestDefinition::{parent_id,step_ids}`.
All of the messy conversions between `TestDescription`,
`LspTestDescription`, `TestDefinition`, `TestData` and `TestIdentifier`
are cleaned up. They shouldn't have been using `impl From` and now the
full list of tests is available to their implementations.
Diffstat (limited to 'cli/lsp/testing/collectors.rs')
-rw-r--r-- | cli/lsp/testing/collectors.rs | 883 |
1 files changed, 559 insertions, 324 deletions
diff --git a/cli/lsp/testing/collectors.rs b/cli/lsp/testing/collectors.rs index 6976cffb9..f5f1ea0d1 100644 --- a/cli/lsp/testing/collectors.rs +++ b/cli/lsp/testing/collectors.rs @@ -1,51 +1,59 @@ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. -use super::definitions::TestDefinition; +use crate::lsp::analysis::source_range_to_lsp_range; + +use super::definitions::TestModule; use deno_ast::swc::ast; use deno_ast::swc::visit::Visit; use deno_ast::swc::visit::VisitWith; -use deno_ast::SourceRange; use deno_ast::SourceRangedForSpanned; use deno_ast::SourceTextInfo; use deno_core::ModuleSpecifier; +use lsp::Range; use std::collections::HashMap; use std::collections::HashSet; +use tower_lsp::lsp_types as lsp; /// Parse an arrow expression for any test steps and return them. -fn arrow_to_steps( - parent: &str, +fn visit_arrow( arrow_expr: &ast::ArrowExpr, -) -> Vec<TestDefinition> { + parent_id: &str, + text_info: &SourceTextInfo, + test_module: &mut TestModule, +) { if let Some((maybe_test_context, maybe_step_var)) = parse_test_context_param(arrow_expr.params.get(0)) { let mut collector = TestStepCollector::new( - parent.to_string(), maybe_test_context, maybe_step_var, + parent_id, + text_info, + test_module, ); arrow_expr.body.visit_with(&mut collector); - collector.take() - } else { - vec![] } } /// Parse a function for any test steps and return them. -fn fn_to_steps(parent: &str, function: &ast::Function) -> Vec<TestDefinition> { +fn visit_fn( + function: &ast::Function, + parent_id: &str, + text_info: &SourceTextInfo, + test_module: &mut TestModule, +) { if let Some((maybe_test_context, maybe_step_var)) = parse_test_context_param(function.params.get(0).map(|p| &p.pat)) { let mut collector = TestStepCollector::new( - parent.to_string(), maybe_test_context, maybe_step_var, + parent_id, + text_info, + test_module, ); function.body.visit_with(&mut collector); - collector.take() - } else { - vec![] } } @@ -120,188 +128,223 @@ fn parse_test_context_param( /// Check a call expression of a test or test step to determine the name of the /// test or test step as well as any sub steps. -fn check_call_expr( - parent: &str, +fn visit_call_expr( node: &ast::CallExpr, fns: Option<&HashMap<String, ast::Function>>, - text_info: Option<&SourceTextInfo>, -) -> Option<(String, Vec<TestDefinition>)> { + range: Range, + parent_id: Option<&str>, + text_info: &SourceTextInfo, + test_module: &mut TestModule, +) { if let Some(expr) = node.args.get(0).map(|es| es.expr.as_ref()) { match expr { ast::Expr::Object(obj_lit) => { let mut maybe_name = None; - let mut steps = vec![]; for prop in &obj_lit.props { - if let ast::PropOrSpread::Prop(prop) = prop { - match prop.as_ref() { - ast::Prop::KeyValue(key_value_prop) => { - if let ast::PropName::Ident(ast::Ident { sym, .. }) = - &key_value_prop.key - { - match sym.to_string().as_str() { - "name" => match key_value_prop.value.as_ref() { - // matches string literals (e.g. "test name" or - // 'test name') - ast::Expr::Lit(ast::Lit::Str(lit_str)) => { - maybe_name = Some(lit_str.value.to_string()); - } - // matches template literals with only a single quasis - // (e.g. `test name`) - ast::Expr::Tpl(tpl) => { - if tpl.quasis.len() == 1 { - maybe_name = Some(tpl.quasis[0].raw.to_string()); - } - } - _ => (), - }, - "fn" => match key_value_prop.value.as_ref() { - ast::Expr::Arrow(arrow_expr) => { - steps = arrow_to_steps(parent, arrow_expr); - } - ast::Expr::Fn(fn_expr) => { - steps = fn_to_steps(parent, &fn_expr.function); - } - _ => (), - }, - _ => (), + let ast::PropOrSpread::Prop(prop) = prop else { + continue; + }; + let ast::Prop::KeyValue(key_value_prop) = prop.as_ref() else { + continue; + }; + let ast::PropName::Ident(ast::Ident { sym, .. }) = + &key_value_prop.key + else { + continue; + }; + if sym == "name" { + match key_value_prop.value.as_ref() { + // matches string literals (e.g. "test name" or + // 'test name') + ast::Expr::Lit(ast::Lit::Str(lit_str)) => { + maybe_name = Some(lit_str.value.to_string()); + } + // matches template literals with only a single quasis + // (e.g. `test name`) + ast::Expr::Tpl(tpl) => { + if tpl.quasis.len() == 1 { + maybe_name = Some(tpl.quasis[0].raw.to_string()); + } + } + _ => {} + } + break; + } + } + let name = match maybe_name { + Some(n) => n, + None => return, + }; + let (id, _) = test_module.register( + name, + Some(range), + false, + parent_id.map(str::to_owned), + ); + for prop in &obj_lit.props { + let ast::PropOrSpread::Prop(prop) = prop else { + continue; + }; + match prop.as_ref() { + ast::Prop::KeyValue(key_value_prop) => { + let ast::PropName::Ident(ast::Ident { sym, .. }) = + &key_value_prop.key + else { + continue; + }; + if sym == "fn" { + match key_value_prop.value.as_ref() { + ast::Expr::Arrow(arrow_expr) => { + visit_arrow(arrow_expr, &id, text_info, test_module); } + ast::Expr::Fn(fn_expr) => { + visit_fn(&fn_expr.function, &id, text_info, test_module); + } + _ => {} } + break; } - ast::Prop::Method(method_prop) => { - steps = fn_to_steps(parent, &method_prop.function); + } + ast::Prop::Method(method_prop) => { + let ast::PropName::Ident(ast::Ident { sym, .. }) = + &method_prop.key + else { + continue; + }; + if sym == "fn" { + visit_fn(&method_prop.function, &id, text_info, test_module); + break; } - _ => (), } + _ => {} } } - maybe_name.map(|name| (name, steps)) } ast::Expr::Fn(fn_expr) => { if let Some(ast::Ident { sym, .. }) = fn_expr.ident.as_ref() { let name = sym.to_string(); - let steps = fn_to_steps(parent, &fn_expr.function); - Some((name, steps)) - } else { - None + let (id, _) = test_module.register( + name, + Some(range), + false, + parent_id.map(str::to_owned), + ); + visit_fn(&fn_expr.function, &id, text_info, test_module); } } ast::Expr::Lit(ast::Lit::Str(lit_str)) => { let name = lit_str.value.to_string(); - let mut steps = vec![]; + let (id, _) = test_module.register( + name, + Some(range), + false, + parent_id.map(str::to_owned), + ); match node.args.get(1).map(|es| es.expr.as_ref()) { Some(ast::Expr::Fn(fn_expr)) => { - steps = fn_to_steps(parent, &fn_expr.function); + visit_fn(&fn_expr.function, &id, text_info, test_module); } Some(ast::Expr::Arrow(arrow_expr)) => { - steps = arrow_to_steps(parent, arrow_expr); + visit_arrow(arrow_expr, &id, text_info, test_module); } - _ => (), + _ => {} } - Some((name, steps)) } ast::Expr::Tpl(tpl) => { if tpl.quasis.len() == 1 { - let mut steps = vec![]; + let name = tpl.quasis[0].raw.to_string(); + let (id, _) = test_module.register( + name, + Some(range), + false, + parent_id.map(str::to_owned), + ); match node.args.get(1).map(|es| es.expr.as_ref()) { Some(ast::Expr::Fn(fn_expr)) => { - steps = fn_to_steps(parent, &fn_expr.function); + visit_fn(&fn_expr.function, &id, text_info, test_module); } Some(ast::Expr::Arrow(arrow_expr)) => { - steps = arrow_to_steps(parent, arrow_expr); + visit_arrow(arrow_expr, &id, text_info, test_module); } - _ => (), + _ => {} } - - Some((tpl.quasis[0].raw.to_string(), steps)) - } else { - None } } ast::Expr::Ident(ident) => { let name = ident.sym.to_string(); - fns.and_then(|fns| { - fns - .get(&name) - .map(|fn_expr| (name, fn_to_steps(parent, fn_expr))) - }) + if let Some(fn_expr) = fns.and_then(|fns| fns.get(&name)) { + let (parent_id, _) = test_module.register( + name, + Some(range), + false, + parent_id.map(str::to_owned), + ); + visit_fn(fn_expr, &parent_id, text_info, test_module); + } } _ => { - if let Some(text_info) = text_info { - let range = node.range(); - let indexes = text_info.line_and_column_display(range.start); - Some(( + if parent_id.is_none() { + let node_range = node.range(); + let indexes = text_info.line_and_column_display(node_range.start); + test_module.register( format!("Test {}:{}", indexes.line_number, indexes.column_number), - vec![], - )) - } else { - None + Some(range), + false, + None, + ); } } } - } else { - None } } /// A structure which can be used to walk a branch of AST determining if the /// branch contains any testing steps. -struct TestStepCollector { - steps: Vec<TestDefinition>, - parent: String, +struct TestStepCollector<'a> { maybe_test_context: Option<String>, vars: HashSet<String>, + parent_id: &'a str, + text_info: &'a SourceTextInfo, + test_module: &'a mut TestModule, } -impl TestStepCollector { +impl<'a> TestStepCollector<'a> { fn new( - parent: String, maybe_test_context: Option<String>, maybe_step_var: Option<String>, + parent_id: &'a str, + text_info: &'a SourceTextInfo, + test_module: &'a mut TestModule, ) -> Self { let mut vars = HashSet::new(); if let Some(var) = maybe_step_var { vars.insert(var); } Self { - steps: Vec::default(), - parent, maybe_test_context, vars, + parent_id, + text_info, + test_module, } } - - fn add_step<N: AsRef<str>>( - &mut self, - name: N, - range: SourceRange, - steps: Vec<TestDefinition>, - ) { - let step = - TestDefinition::new_step(name.as_ref().to_string(), range, steps); - self.steps.push(step); - } - - fn check_call_expr(&mut self, node: &ast::CallExpr, range: SourceRange) { - if let Some((name, steps)) = check_call_expr(&self.parent, node, None, None) - { - self.add_step(name, range, steps); - } - } - - /// Move out the test definitions - pub fn take(self) -> Vec<TestDefinition> { - self.steps - } } -impl Visit for TestStepCollector { +impl Visit for TestStepCollector<'_> { fn visit_call_expr(&mut self, node: &ast::CallExpr) { if let ast::Callee::Expr(callee_expr) = &node.callee { match callee_expr.as_ref() { // Identify calls to identified variables ast::Expr::Ident(ident) => { if self.vars.contains(&ident.sym.to_string()) { - self.check_call_expr(node, ident.range()); + visit_call_expr( + node, + None, + source_range_to_lsp_range(&ident.range(), self.text_info), + Some(self.parent_id), + self.text_info, + self.test_module, + ); } } // Identify calls to `test.step()` @@ -311,7 +354,17 @@ impl Visit for TestStepCollector { if ns_prop_ident.sym.eq("step") { if let ast::Expr::Ident(ident) = member_expr.obj.as_ref() { if ident.sym == *test_context { - self.check_call_expr(node, ns_prop_ident.range()); + visit_call_expr( + node, + None, + source_range_to_lsp_range( + &ns_prop_ident.range(), + self.text_info, + ), + Some(self.parent_id), + self.text_info, + self.test_module, + ); } } } @@ -382,53 +435,29 @@ impl Visit for TestStepCollector { /// Walk an AST and determine if it contains any `Deno.test` tests. pub struct TestCollector { - definitions: Vec<TestDefinition>, - specifier: ModuleSpecifier, + test_module: TestModule, vars: HashSet<String>, fns: HashMap<String, ast::Function>, text_info: SourceTextInfo, } impl TestCollector { - pub fn new(specifier: ModuleSpecifier, text_info: SourceTextInfo) -> Self { + pub fn new( + specifier: ModuleSpecifier, + script_version: String, + text_info: SourceTextInfo, + ) -> Self { Self { - definitions: Vec::new(), - specifier, + test_module: TestModule::new(specifier, script_version), vars: HashSet::new(), fns: HashMap::new(), text_info, } } - fn add_definition<N: AsRef<str>>( - &mut self, - name: N, - range: SourceRange, - steps: Vec<TestDefinition>, - ) { - let definition = TestDefinition::new( - &self.specifier, - name.as_ref().to_string(), - range, - steps, - ); - self.definitions.push(definition); - } - - fn check_call_expr(&mut self, node: &ast::CallExpr, range: SourceRange) { - if let Some((name, steps)) = check_call_expr( - self.specifier.as_str(), - node, - Some(&self.fns), - Some(&self.text_info), - ) { - self.add_definition(name, range, steps); - } - } - /// Move out the test definitions - pub fn take(self) -> Vec<TestDefinition> { - self.definitions + pub fn take(self) -> TestModule { + self.test_module } } @@ -438,7 +467,14 @@ impl Visit for TestCollector { match callee_expr.as_ref() { ast::Expr::Ident(ident) => { if self.vars.contains(&ident.sym.to_string()) { - self.check_call_expr(node, ident.range()); + visit_call_expr( + node, + Some(&self.fns), + source_range_to_lsp_range(&ident.range(), &self.text_info), + None, + &self.text_info, + &mut self.test_module, + ); } } ast::Expr::Member(member_expr) => { @@ -446,7 +482,17 @@ impl Visit for TestCollector { if ns_prop_ident.sym.to_string() == "test" { if let ast::Expr::Ident(ident) = member_expr.obj.as_ref() { if ident.sym.to_string() == "Deno" { - self.check_call_expr(node, ns_prop_ident.range()); + visit_call_expr( + node, + Some(&self.fns), + source_range_to_lsp_range( + &ns_prop_ident.range(), + &self.text_info, + ), + None, + &self.text_info, + &mut self.test_module, + ); } } } @@ -519,18 +565,17 @@ impl Visit for TestCollector { #[cfg(test)] pub mod tests { + use crate::lsp::testing::definitions::TestDefinition; + use super::*; - use deno_ast::StartSourcePos; use deno_core::resolve_url; + use lsp::Position; - pub fn new_range(start: usize, end: usize) -> SourceRange { - SourceRange::new( - StartSourcePos::START_SOURCE_POS + start, - StartSourcePos::START_SOURCE_POS + end, - ) + pub fn new_range(l1: u32, c1: u32, l2: u32, c2: u32) -> Range { + Range::new(Position::new(l1, c1), Position::new(l2, c2)) } - fn collect(source: &str) -> Vec<TestDefinition> { + fn collect(source: &str) -> TestModule { let specifier = resolve_url("file:///a/example.ts").unwrap(); let parsed_module = deno_ast::parse_module(deno_ast::ParseParams { @@ -543,54 +588,81 @@ pub mod tests { }) .unwrap(); let text_info = parsed_module.text_info().clone(); - let mut collector = TestCollector::new(specifier, text_info); + let mut collector = + TestCollector::new(specifier, "1".to_string(), text_info); parsed_module.module().visit_with(&mut collector); collector.take() } #[test] fn test_test_collector_test() { - let res = collect( + let test_module = collect( r#" Deno.test("test", () => {}); "#, ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(12, 16), - steps: vec![], - },] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + TestDefinition { + id: + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + name: "test".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_test_tpl() { - let res = collect( + let test_module = collect( r#" Deno.test(`test`, () => {}); "#, ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(12, 16), - steps: vec![], - },] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + TestDefinition { + id: + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + name: "test".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_a() { - let res = collect( + let test_module = collect( r#" Deno.test({ name: "test", @@ -607,34 +679,52 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(12, 16), - steps: vec![TestDefinition { - id: - "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c" - .to_string(), - name: "step".to_string(), - range: new_range(81, 85), - steps: vec![TestDefinition { - id: - "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d" - .to_string(), - name: "sub step".to_string(), - range: new_range(128, 132), - steps: vec![], - }] - }], - },] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![ + ( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string(), + TestDefinition { + id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string(), + name: "test".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: vec!["704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string()].into_iter().collect(), + } + ), + ( + "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string(), + TestDefinition { + id: "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string(), + name: "step".to_string(), + range: Some(new_range(4, 18, 4, 22)), + is_dynamic: false, + parent_id: Some("4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string()), + step_ids: vec!["0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string()].into_iter().collect(), + } + ), + ( + "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string(), + TestDefinition { + id: "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string(), + name: "sub step".to_string(), + range: Some(new_range(5, 18, 5, 22)), + is_dynamic: false, + parent_id: Some("704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string()), + step_ids: Default::default(), + } + ), + ].into_iter().collect(), + } ); } #[test] fn test_test_collector_a_tpl() { - let res = collect( + let test_module = collect( r#" Deno.test({ name: `test`, @@ -651,34 +741,52 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(12, 16), - steps: vec![TestDefinition { - id: - "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c" - .to_string(), - name: "step".to_string(), - range: new_range(81, 85), - steps: vec![TestDefinition { - id: - "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d" - .to_string(), - name: "sub step".to_string(), - range: new_range(128, 132), - steps: vec![], - }] - }], - },] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![ + ( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string(), + TestDefinition { + id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string(), + name: "test".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: vec!["704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string()].into_iter().collect(), + } + ), + ( + "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string(), + TestDefinition { + id: "704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string(), + name: "step".to_string(), + range: Some(new_range(4, 18, 4, 22)), + is_dynamic: false, + parent_id: Some("4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9".to_string()), + step_ids: vec!["0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string()].into_iter().collect(), + } + ), + ( + "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string(), + TestDefinition { + id: "0d006a4ec0abaa9cc1d18256b1ccd2677a4c882ff5cb807123890f7528ab1e8d".to_string(), + name: "sub step".to_string(), + range: Some(new_range(5, 18, 5, 22)), + is_dynamic: false, + parent_id: Some("704d24083fd4a3e1bd204faa20827dc594334812245e5d45dda222b3edc60a0c".to_string()), + step_ids: Default::default(), + } + ), + ].into_iter().collect(), + } ); } #[test] fn test_test_collector_destructure() { - let res = collect( + let test_module = collect( r#" const { test } = Deno; test("test", () => {}); @@ -686,20 +794,33 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(36, 40), - steps: vec![], - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + TestDefinition { + id: + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + name: "test".to_string(), + range: Some(new_range(2, 6, 2, 10)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_destructure_rebind_step() { - let res = collect( + let test_module = collect( r#" Deno.test(async function useFnName({ step: s }) { await s("step", () => {}); @@ -708,27 +829,41 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "86b4c821900e38fc89f24bceb0e45193608ab3f9d2a6019c7b6a5aceff5d7df2" - .to_string(), - name: "useFnName".to_string(), - range: new_range(12, 16), - steps: vec![TestDefinition { - id: - "dac8a169b8f8c6babf11122557ea545de2733bfafed594d044b22bc6863a0856" - .to_string(), - name: "step".to_string(), - range: new_range(71, 72), - steps: vec![], - }], - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![ + ( + "86b4c821900e38fc89f24bceb0e45193608ab3f9d2a6019c7b6a5aceff5d7df2".to_string(), + TestDefinition { + id: "86b4c821900e38fc89f24bceb0e45193608ab3f9d2a6019c7b6a5aceff5d7df2".to_string(), + name: "useFnName".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: vec!["dac8a169b8f8c6babf11122557ea545de2733bfafed594d044b22bc6863a0856".to_string()].into_iter().collect(), + } + ), + ( + "dac8a169b8f8c6babf11122557ea545de2733bfafed594d044b22bc6863a0856".to_string(), + TestDefinition { + id: "dac8a169b8f8c6babf11122557ea545de2733bfafed594d044b22bc6863a0856".to_string(), + name: "step".to_string(), + range: Some(new_range(2, 14, 2, 15)), + is_dynamic: false, + parent_id: Some("86b4c821900e38fc89f24bceb0e45193608ab3f9d2a6019c7b6a5aceff5d7df2".to_string()), + step_ids: Default::default(), + } + ), + ].into_iter().collect(), + } ); } #[test] fn test_test_collector_rebind() { - let res = collect( + let test_module = collect( r#" const t = Deno.test; t("test", () => {}); @@ -736,20 +871,33 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(34, 35), - steps: vec![], - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + TestDefinition { + id: + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + name: "test".to_string(), + range: Some(new_range(2, 6, 2, 7)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_separate_test_function_with_string_name() { - let res = collect( + let test_module = collect( r#" function someFunction() {} Deno.test("test", someFunction); @@ -757,40 +905,66 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" - .to_string(), - name: "test".to_string(), - range: new_range(45, 49), - steps: vec![], - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + TestDefinition { + id: + "4ebb361c93f76a0f1bac300638675609f1cf481e6f3b9006c3c98604b3a184e9" + .to_string(), + name: "test".to_string(), + range: Some(new_range(2, 11, 2, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_function_only() { - let res = collect( + let test_module = collect( r#" Deno.test(async function someFunction() {}); "#, ); assert_eq!( - res, - vec![TestDefinition { - id: "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" - .to_string(), - name: "someFunction".to_string(), - range: new_range(12, 16), - steps: vec![] - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" + .to_string(), + TestDefinition { + id: + "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" + .to_string(), + name: "someFunction".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_separate_test_function() { - let res = collect( + let test_module = collect( r#" async function someFunction() {} Deno.test(someFunction); @@ -798,20 +972,33 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" - .to_string(), - name: "someFunction".to_string(), - range: new_range(51, 55), - steps: vec![] - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" + .to_string(), + TestDefinition { + id: + "e0f6a73647b763f82176c98a019e54200b799a32007f9859fb782aaa9e308568" + .to_string(), + name: "someFunction".to_string(), + range: Some(new_range(2, 11, 2, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } #[test] fn test_test_collector_unknown_test() { - let res = collect( + let test_module = collect( r#" const someFunction = () => ({ name: "test", fn: () => {} }); Deno.test(someFunction()); @@ -819,21 +1006,34 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "6d05d6dc35548b86a1e70acaf24a5bc2dd35db686b35b685ad5931d201b4a918" - .to_string(), - name: "Test 3:7".to_string(), - range: new_range(79, 83), - steps: vec![] - }] + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![( + "6d05d6dc35548b86a1e70acaf24a5bc2dd35db686b35b685ad5931d201b4a918" + .to_string(), + TestDefinition { + id: + "6d05d6dc35548b86a1e70acaf24a5bc2dd35db686b35b685ad5931d201b4a918" + .to_string(), + name: "Test 3:7".to_string(), + range: Some(new_range(2, 11, 2, 15)), + is_dynamic: false, + parent_id: None, + step_ids: Default::default(), + } + ),] + .into_iter() + .collect(), + } ); } // Regression test for https://github.com/denoland/vscode_deno/issues/656. #[test] fn test_test_collector_nested_steps_same_name_and_level() { - let res = collect( + let test_module = collect( r#" Deno.test("1", async (t) => { await t.step("step 1", async (t) => { @@ -847,36 +1047,71 @@ pub mod tests { ); assert_eq!( - res, - vec![TestDefinition { - id: "3799fc549a32532145ffc8532b0cd943e025bbc19a02e2cde9be94f87bceb829".to_string(), - name: "1".to_string(), - range: new_range(12, 16), - steps: vec![ - TestDefinition { - id: "e714fc695c0895327bf7148a934c3303ad515af029a14906be46f80340c6d7e3".to_string(), - name: "step 1".to_string(), - range: new_range(53, 57), - steps: vec![TestDefinition { + &test_module, + &TestModule { + specifier: test_module.specifier.clone(), + script_version: test_module.script_version.clone(), + defs: vec![ + ( + "3799fc549a32532145ffc8532b0cd943e025bbc19a02e2cde9be94f87bceb829".to_string(), + TestDefinition { + id: "3799fc549a32532145ffc8532b0cd943e025bbc19a02e2cde9be94f87bceb829".to_string(), + name: "1".to_string(), + range: Some(new_range(1, 11, 1, 15)), + is_dynamic: false, + parent_id: None, + step_ids: vec![ + "e714fc695c0895327bf7148a934c3303ad515af029a14906be46f80340c6d7e3".to_string(), + "ec6b03d3dd3dde78d2d11ed981d3386083aeca701510cc049189d74bd79f8587".to_string(), + ].into_iter().collect() + } + ), + ( + "e714fc695c0895327bf7148a934c3303ad515af029a14906be46f80340c6d7e3".to_string(), + TestDefinition { + id: "e714fc695c0895327bf7148a934c3303ad515af029a14906be46f80340c6d7e3".to_string(), + name: "step 1".to_string(), + range: Some(new_range(2, 16, 2, 20)), + is_dynamic: false, + parent_id: Some("3799fc549a32532145ffc8532b0cd943e025bbc19a02e2cde9be94f87bceb829".to_string()), + step_ids: vec!["d874949e18dfc297e15c52ff13f13b4e6ae911ec1818b2c761e3313bc018a3ab".to_string()].into_iter().collect() + } + ), + ( + "d874949e18dfc297e15c52ff13f13b4e6ae911ec1818b2c761e3313bc018a3ab".to_string(), + TestDefinition { id: "d874949e18dfc297e15c52ff13f13b4e6ae911ec1818b2c761e3313bc018a3ab".to_string(), name: "nested step".to_string(), - range: new_range(101, 105), - steps: vec![], - }], - }, - TestDefinition { - id: "ec6b03d3dd3dde78d2d11ed981d3386083aeca701510cc049189d74bd79f8587".to_string(), - name: "step 2".to_string(), - range: new_range(160, 164), - steps: vec![TestDefinition { + range: Some(new_range(3, 18, 3, 22)), + is_dynamic: false, + parent_id: Some("e714fc695c0895327bf7148a934c3303ad515af029a14906be46f80340c6d7e3".to_string()), + step_ids: Default::default(), + } + ), + ( + "ec6b03d3dd3dde78d2d11ed981d3386083aeca701510cc049189d74bd79f8587".to_string(), + TestDefinition { + id: "ec6b03d3dd3dde78d2d11ed981d3386083aeca701510cc049189d74bd79f8587".to_string(), + name: "step 2".to_string(), + range: Some(new_range(5, 16, 5, 20)), + is_dynamic: false, + parent_id: Some("3799fc549a32532145ffc8532b0cd943e025bbc19a02e2cde9be94f87bceb829".to_string()), + step_ids: vec!["96729f1f1608e50160b0bf11946719384b4021fd1d26b14eff7765034b3d2684".to_string()].into_iter().collect() + } + ), + ( + "96729f1f1608e50160b0bf11946719384b4021fd1d26b14eff7765034b3d2684".to_string(), + TestDefinition { id: "96729f1f1608e50160b0bf11946719384b4021fd1d26b14eff7765034b3d2684".to_string(), name: "nested step".to_string(), - range: new_range(208, 212), - steps: vec![], - }], - }, - ] - }] + range: Some(new_range(6, 18, 6, 22)), + is_dynamic: false, + parent_id: Some("ec6b03d3dd3dde78d2d11ed981d3386083aeca701510cc049189d74bd79f8587".to_string()), + step_ids: Default::default(), + } + ), + ].into_iter().collect(), + } ); } } |