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:
61f08d5a71/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.
This commit is contained in:
Nayeem Rahman 2023-08-30 16:31:31 +01:00 committed by GitHub
parent 329698cf73
commit d28384c3de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 836 additions and 662 deletions

View file

@ -1,7 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use super::collectors::TestCollector;
use super::definitions::TestDefinitions;
use super::definitions::TestModule;
use super::execution::TestRun;
use super::lsp_custom;
@ -47,7 +47,7 @@ pub struct TestServer {
/// A map of run ids to test runs
runs: Arc<Mutex<HashMap<u32, TestRun>>>,
/// Tests that are discovered from a versioned document
tests: Arc<Mutex<HashMap<ModuleSpecifier, TestDefinitions>>>,
tests: Arc<Mutex<HashMap<ModuleSpecifier, TestModule>>>,
/// A channel for requesting that changes to documents be statically analyzed
/// for tests
update_channel: mpsc::UnboundedSender<Arc<StateSnapshot>>,
@ -59,7 +59,7 @@ impl TestServer {
performance: Arc<Performance>,
maybe_root_uri: Option<ModuleSpecifier>,
) -> Self {
let tests: Arc<Mutex<HashMap<ModuleSpecifier, TestDefinitions>>> =
let tests: Arc<Mutex<HashMap<ModuleSpecifier, TestModule>>> =
Arc::new(Mutex::new(HashMap::new()));
let (update_channel, mut update_rx) =
@ -109,31 +109,27 @@ impl TestServer {
if let Some(Ok(parsed_source)) =
document.maybe_parsed_source()
{
let old_tds = tests.remove(specifier).unwrap_or_default();
let was_empty = tests
.remove(specifier)
.map(|tm| tm.is_empty())
.unwrap_or(true);
let mut collector = TestCollector::new(
specifier.clone(),
script_version,
parsed_source.text_info().clone(),
);
parsed_source.module().visit_with(&mut collector);
let test_definitions = TestDefinitions {
discovered: collector.take(),
injected: Default::default(),
script_version,
};
if !test_definitions.discovered.is_empty() {
let test_module = collector.take();
if !test_module.is_empty() {
client.send_test_notification(
test_definitions.as_notification(
specifier,
mru.as_ref(),
parsed_source.text_info(),
),
test_module.as_replace_notification(mru.as_ref()),
);
} else if !old_tds.is_empty() {
} else if !was_empty {
client.send_test_notification(as_delete_notification(
specifier.clone(),
));
}
tests.insert(specifier.clone(), test_definitions);
tests.insert(specifier.clone(), test_module);
}
}
}