summaryrefslogtreecommitdiff
path: root/cli/lsp/testing/definitions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/lsp/testing/definitions.rs')
-rw-r--r--cli/lsp/testing/definitions.rs251
1 files changed, 130 insertions, 121 deletions
diff --git a/cli/lsp/testing/definitions.rs b/cli/lsp/testing/definitions.rs
index 6992c995d..30b0d3bb0 100644
--- a/cli/lsp/testing/definitions.rs
+++ b/cli/lsp/testing/definitions.rs
@@ -1,172 +1,181 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use super::lsp_custom;
+use super::lsp_custom::TestData;
-use crate::lsp::analysis::source_range_to_lsp_range;
use crate::lsp::client::TestingNotification;
+use crate::lsp::logging::lsp_warn;
+use crate::tools::test::TestDescription;
+use crate::tools::test::TestStepDescription;
use crate::util::checksum;
-use deno_ast::SourceRange;
-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;
#[derive(Debug, Clone, PartialEq)]
pub struct TestDefinition {
pub id: String,
pub name: String,
- pub range: SourceRange,
- pub steps: Vec<TestDefinition>,
+ pub range: Option<Range>,
+ pub is_dynamic: bool,
+ pub parent_id: Option<String>,
+ pub step_ids: HashSet<String>,
}
-impl TestDefinition {
- pub fn new(
- specifier: &ModuleSpecifier,
+#[derive(Debug, Clone, PartialEq)]
+pub struct TestModule {
+ pub specifier: ModuleSpecifier,
+ /// The version of the document that the discovered tests relate to.
+ pub script_version: String,
+ pub defs: HashMap<String, TestDefinition>,
+}
+
+impl TestModule {
+ pub fn new(specifier: ModuleSpecifier, script_version: String) -> Self {
+ Self {
+ specifier,
+ script_version,
+ defs: Default::default(),
+ }
+ }
+
+ /// Returns `(id, is_newly_registered)`.
+ pub fn register(
+ &mut self,
name: String,
- range: SourceRange,
- mut steps: Vec<TestDefinition>,
- ) -> Self {
+ range: Option<Range>,
+ is_dynamic: bool,
+ parent_id: Option<String>,
+ ) -> (String, bool) {
let mut id_components = Vec::with_capacity(7);
- id_components.push(specifier.as_str().as_bytes());
id_components.push(name.as_bytes());
+ let mut current_parent_id = &parent_id;
+ while let Some(parent_id) = current_parent_id {
+ let parent = match self.defs.get(parent_id) {
+ Some(d) => d,
+ None => {
+ lsp_warn!("Internal Error: parent_id \"{}\" of test \"{}\" was not registered.", parent_id, &name);
+ id_components.push("<unknown>".as_bytes());
+ break;
+ }
+ };
+ id_components.push(parent.name.as_bytes());
+ current_parent_id = &parent.parent_id;
+ }
+ id_components.push(self.specifier.as_str().as_bytes());
+ id_components.reverse();
let id = checksum::gen(&id_components);
- Self::fix_ids(&mut steps, &mut id_components);
- Self {
- id,
- name,
- range,
- steps,
+ if self.defs.contains_key(&id) {
+ return (id, false);
}
- }
-
- fn fix_ids<'a>(
- steps: &'a mut Vec<TestDefinition>,
- id_components: &mut Vec<&'a [u8]>,
- ) {
- for step in steps {
- id_components.push(step.name.as_bytes());
- step.id = checksum::gen(id_components);
- Self::fix_ids(&mut step.steps, id_components);
- id_components.pop();
+ if let Some(parent_id) = &parent_id {
+ let parent = self.defs.get_mut(parent_id).unwrap();
+ parent.step_ids.insert(id.clone());
}
+ self.defs.insert(
+ id.clone(),
+ TestDefinition {
+ id: id.clone(),
+ name,
+ range,
+ is_dynamic,
+ parent_id,
+ step_ids: Default::default(),
+ },
+ );
+ (id, true)
}
- pub fn new_step(
- name: String,
- range: SourceRange,
- steps: Vec<TestDefinition>,
- ) -> Self {
- Self {
- // ID will be fixed later when the entire ancestry is available.
- id: "".to_string(),
- name,
- range,
- steps,
- }
+ /// Returns `(id, was_newly_registered)`.
+ pub fn register_dynamic(&mut self, desc: &TestDescription) -> (String, bool) {
+ self.register(desc.name.clone(), None, true, None)
}
- fn as_test_data(
- &self,
- source_text_info: &SourceTextInfo,
- ) -> lsp_custom::TestData {
- lsp_custom::TestData {
- id: self.id.clone(),
- label: self.name.clone(),
- steps: self
- .steps
- .iter()
- .map(|step| step.as_test_data(source_text_info))
- .collect(),
- range: Some(source_range_to_lsp_range(&self.range, source_text_info)),
- }
+ /// Returns `(id, was_newly_registered)`.
+ pub fn register_step_dynamic(
+ &mut self,
+ desc: &TestStepDescription,
+ parent_static_id: &str,
+ ) -> (String, bool) {
+ self.register(
+ desc.name.clone(),
+ None,
+ true,
+ Some(parent_static_id.to_string()),
+ )
}
- fn contains_id<S: AsRef<str>>(&self, id: S) -> bool {
- let id = id.as_ref();
- self.id == id || self.steps.iter().any(|td| td.contains_id(id))
+ pub fn get(&self, id: &str) -> Option<&TestDefinition> {
+ self.defs.get(id)
}
-}
-
-#[derive(Debug, Clone)]
-pub struct TestDefinitions {
- /// definitions of tests and their steps which were statically discovered from
- /// the source document.
- pub discovered: Vec<TestDefinition>,
- /// Tests and steps which the test runner notified us of, which were
- /// dynamically added
- pub injected: Vec<lsp_custom::TestData>,
- /// The version of the document that the discovered tests relate to.
- pub script_version: String,
-}
-impl Default for TestDefinitions {
- fn default() -> Self {
- TestDefinitions {
- script_version: "1".to_string(),
- discovered: vec![],
- injected: vec![],
+ pub fn get_test_data(&self, id: &str) -> TestData {
+ fn get_test_data_inner(tm: &TestModule, id: &str) -> TestData {
+ let def = tm.defs.get(id).unwrap();
+ TestData {
+ id: def.id.clone(),
+ label: def.name.clone(),
+ steps: def
+ .step_ids
+ .iter()
+ .map(|id| get_test_data_inner(tm, id))
+ .collect(),
+ range: def.range,
+ }
+ }
+ let def = self.defs.get(id).unwrap();
+ let mut current_data = get_test_data_inner(self, &def.id);
+ let mut current_parent_id = &def.parent_id;
+ while let Some(parent_id) = current_parent_id {
+ let parent = self.defs.get(parent_id).unwrap();
+ current_data = TestData {
+ id: parent.id.clone(),
+ label: parent.name.clone(),
+ steps: vec![current_data],
+ range: None,
+ };
+ current_parent_id = &parent.parent_id;
}
+ current_data
}
-}
-impl TestDefinitions {
/// Return the test definitions as a testing module notification.
- pub fn as_notification(
+ pub fn as_replace_notification(
&self,
- specifier: &ModuleSpecifier,
- maybe_root: Option<&ModuleSpecifier>,
- source_text_info: &SourceTextInfo,
+ maybe_root_uri: Option<&ModuleSpecifier>,
) -> TestingNotification {
- let label = if let Some(root) = maybe_root {
- specifier.as_str().replace(root.as_str(), "")
- } else {
- specifier
- .path_segments()
- .and_then(|s| s.last().map(|s| s.to_string()))
- .unwrap_or_else(|| "<unknown>".to_string())
- };
- let mut tests_map: HashMap<String, lsp_custom::TestData> = self
- .injected
- .iter()
- .map(|td| (td.id.clone(), td.clone()))
- .collect();
- tests_map.extend(self.discovered.iter().map(|td| {
- let test_data = td.as_test_data(source_text_info);
- (test_data.id.clone(), test_data)
- }));
+ let label = self.label(maybe_root_uri);
TestingNotification::Module(lsp_custom::TestModuleNotificationParams {
text_document: lsp::TextDocumentIdentifier {
- uri: specifier.clone(),
+ uri: self.specifier.clone(),
},
kind: lsp_custom::TestModuleNotificationKind::Replace,
label,
- tests: tests_map.into_values().collect(),
+ tests: self
+ .defs
+ .iter()
+ .filter(|(_, def)| def.parent_id.is_none())
+ .map(|(id, _)| self.get_test_data(id))
+ .collect(),
})
}
- /// Register a dynamically-detected test. Returns false if a test with the
- /// same static id was already registered statically or dynamically. Otherwise
- /// returns true.
- pub fn inject(&mut self, data: lsp_custom::TestData) -> bool {
- if self.discovered.iter().any(|td| td.contains_id(&data.id))
- || self.injected.iter().any(|td| td.id == data.id)
- {
- return false;
+ pub fn label(&self, maybe_root_uri: Option<&ModuleSpecifier>) -> String {
+ if let Some(root) = maybe_root_uri {
+ self.specifier.as_str().replace(root.as_str(), "")
+ } else {
+ self
+ .specifier
+ .path_segments()
+ .and_then(|s| s.last().map(|s| s.to_string()))
+ .unwrap_or_else(|| "<unknown>".to_string())
}
- self.injected.push(data);
- true
- }
-
- /// Return a test definition identified by the test ID.
- pub fn get_by_id<S: AsRef<str>>(&self, id: S) -> Option<&TestDefinition> {
- self
- .discovered
- .iter()
- .find(|td| td.id.as_str() == id.as_ref())
}
pub fn is_empty(&self) -> bool {
- self.discovered.is_empty() && self.injected.is_empty()
+ self.defs.is_empty()
}
}