Skip to content

Commit

Permalink
chore: generalize snapshot tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Aug 29, 2023
1 parent bc83684 commit c6d4558
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 242 deletions.
81 changes: 0 additions & 81 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,87 +391,6 @@ mod tests {
);
}

#[tokio::test]
async fn test_build_graph_dynamic_json_ignores_assert() {
let mut loader = setup(
vec![
(
"file:///a/test.js",
Source::Module {
specifier: "file:///a/test.js",
maybe_headers: None,
content: r#"
const a = await import("./a.json");
"#,
},
),
(
"file:///a/a.json",
Source::Module {
specifier: "file:///a/a.json",
maybe_headers: None,
content: r#"{"a":"b"}"#,
},
),
],
vec![],
);
let roots = vec![ModuleSpecifier::parse("file:///a/test.js").unwrap()];
let mut graph = ModuleGraph::new(GraphKind::All);
graph
.build(
roots.clone(),
&mut loader,
BuildOptions {
is_dynamic: true,
..Default::default()
},
)
.await;
assert_eq!(
json!(graph),
json!({
"roots": [
"file:///a/test.js",
],
"modules": [
{
"kind": "asserted",
"size": 9,
"mediaType": "Json",
"specifier": "file:///a/a.json"
},
{
"dependencies": [
{
"specifier": "./a.json",
"code": {
"specifier": "file:///a/a.json",
"span": {
"start": {
"line": 1,
"character": 31
},
"end": {
"line": 1,
"character": 41
}
}
},
"isDynamic": true
}
],
"kind": "esm",
"mediaType": "JavaScript",
"size": 53,
"specifier": "file:///a/test.js"
}
],
"redirects": {}
})
);
}

#[tokio::test]
async fn test_valid_type_missing() {
let mut loader = setup(
Expand Down
102 changes: 43 additions & 59 deletions tests/type_tracing/tests.rs → tests/helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,15 @@
use std::path::Path;
use std::path::PathBuf;

use pretty_assertions::assert_eq;
mod test_builder;

use super::test_builder::TestBuilder;
use deno_graph::type_tracer::TypeTraceDiagnostic;
pub use test_builder::*;
use url::Url;

#[tokio::test]
async fn test_type_tracing_specs() {
for (test_file_path, spec) in
get_specs_in_dir(&PathBuf::from("./tests/specs/type_tracing"))
{
eprintln!("Running {}", test_file_path.display());
let mut builder = TestBuilder::new();
builder.with_loader(|loader| {
for file in &spec.files {
loader.add_file(&file.specifier, &file.text);
}
});

let result = builder.trace().await.unwrap();
let update_var = std::env::var("UPDATE");
let spec = if update_var.as_ref().map(|v| v.as_str()) == Ok("1") {
let mut spec = spec;
spec.output_file.text = result.output.clone();
spec.diagnostics = result.diagnostics.clone();
std::fs::write(&test_file_path, spec.emit()).unwrap();
spec
} else {
spec
};
assert_eq!(
result.output,
spec.output_file.text,
"Should be same for {}",
test_file_path.display()
);
assert_eq!(
result.diagnostics,
spec.diagnostics,
"Should be same for {}",
test_file_path.display()
);
}
}

struct Spec {
files: Vec<File>,
output_file: File,
diagnostics: Vec<TypeTraceDiagnostic>,
pub struct Spec {
pub files: Vec<SpecFile>,
pub output_file: SpecFile,
pub diagnostics: Vec<serde_json::Value>,
}

impl Spec {
Expand All @@ -59,6 +20,9 @@ impl Spec {
text.push('\n');
}
text.push_str(&self.output_file.emit());
if !text.ends_with("\n") {
text.push('\n');
}
if !self.diagnostics.is_empty() {
text.push_str("\n# diagnostics\n");
text.push_str(&serde_json::to_string_pretty(&self.diagnostics).unwrap());
Expand All @@ -68,33 +32,45 @@ impl Spec {
}
}

struct File {
specifier: String,
text: String,
#[derive(Debug)]
pub struct SpecFile {
pub specifier: String,
pub text: String,
}

impl File {
impl SpecFile {
pub fn emit(&self) -> String {
format!("# {}\n{}", self.specifier, self.text)
}

pub fn url(&self) -> Url {
let specifier = &self.specifier;
if !specifier.starts_with("http") && !specifier.starts_with("file") {
Url::parse(&format!("file:///{}", specifier)).unwrap()
} else {
Url::parse(specifier).unwrap()
}
}
}

fn get_specs_in_dir(path: &Path) -> Vec<(PathBuf, Spec)> {
let files = get_files_in_dir_recursive(path);
pub fn get_specs_in_dir(path: &Path) -> Vec<(PathBuf, Spec)> {
let files = collect_files_in_dir_recursive(path);
let files = if files
.iter()
.any(|(s, _)| s.to_string_lossy().to_lowercase().contains("_only"))
.any(|file| file.path.to_string_lossy().to_lowercase().contains("_only"))
{
files
.into_iter()
.filter(|(s, _)| s.to_string_lossy().to_lowercase().contains("_only"))
.filter(|file| {
file.path.to_string_lossy().to_lowercase().contains("_only")
})
.collect()
} else {
files
};
files
.into_iter()
.map(|(file_path, text)| (file_path, parse_spec(text)))
.map(|file| (file.path, parse_spec(file.text)))
.collect()
}

Expand All @@ -106,7 +82,7 @@ fn parse_spec(text: String) -> Spec {
if let Some(file) = current_file.take() {
files.push(file);
}
current_file = Some(File {
current_file = Some(SpecFile {
specifier: specifier.to_string(),
text: String::new(),
});
Expand Down Expand Up @@ -136,16 +112,24 @@ fn parse_spec(text: String) -> Spec {
}
}

fn get_files_in_dir_recursive(path: &Path) -> Vec<(PathBuf, String)> {
struct CollectedFile {
pub path: PathBuf,
pub text: String,
}

fn collect_files_in_dir_recursive(path: &Path) -> Vec<CollectedFile> {
let mut result = Vec::new();

for entry in path.read_dir().unwrap().flatten() {
let entry_path = entry.path();
if entry_path.is_file() {
let text = std::fs::read_to_string(&entry_path).unwrap();
result.push((entry_path, text));
result.push(CollectedFile {
path: entry_path,
text,
});
} else {
result.extend(get_files_in_dir_recursive(&entry_path));
result.extend(collect_files_in_dir_recursive(&entry_path));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,63 +1,68 @@
use std::cell::RefCell;
use std::collections::BTreeMap;

use anyhow::Result;
use deno_ast::ModuleSpecifier;
use deno_ast::SourceRanged;
use deno_graph::type_tracer::trace_public_types;
use deno_graph::type_tracer::ModuleSymbol;
use deno_graph::type_tracer::RootSymbol;
use deno_graph::type_tracer::SymbolId;
use deno_graph::type_tracer::TypeTraceDiagnostic;
use deno_graph::type_tracer::TypeTraceHandler;
use deno_graph::source::MemoryLoader;
use deno_graph::CapturingModuleAnalyzer;
use deno_graph::DefaultModuleParser;
use deno_graph::GraphKind;
use deno_graph::ModuleGraph;

use super::in_memory_loader::InMemoryLoader;
#[cfg(feature = "type_tracing")]
pub mod tracing {
use std::cell::RefCell;

#[derive(Default)]
struct TestTypeTraceHandler {
diagnostics: RefCell<Vec<TypeTraceDiagnostic>>,
}
use deno_graph::type_tracer::RootSymbol;
use deno_graph::type_tracer::TypeTraceDiagnostic;
use deno_graph::type_tracer::TypeTraceHandler;
use deno_graph::ModuleGraph;

impl TestTypeTraceHandler {
pub fn diagnostics(self) -> Vec<TypeTraceDiagnostic> {
self.diagnostics.take()
#[derive(Default)]
pub struct TestTypeTraceHandler {
diagnostics: RefCell<Vec<TypeTraceDiagnostic>>,
}

impl TestTypeTraceHandler {
pub fn diagnostics(self) -> Vec<TypeTraceDiagnostic> {
self.diagnostics.take()
}
}
}

impl TypeTraceHandler for TestTypeTraceHandler {
fn diagnostic(&self, diagnostic: TypeTraceDiagnostic) {
self.diagnostics.borrow_mut().push(diagnostic);
impl TypeTraceHandler for TestTypeTraceHandler {
fn diagnostic(&self, diagnostic: TypeTraceDiagnostic) {
self.diagnostics.borrow_mut().push(diagnostic);
}
}

pub struct TypeTraceResult {
pub graph: ModuleGraph,
pub root_symbol: RootSymbol,
pub output: String,
pub diagnostics: Vec<TypeTraceDiagnostic>,
}
}

pub struct TypeTraceResult {
pub struct BuildResult {
pub graph: ModuleGraph,
pub root_symbol: RootSymbol,
pub output: String,
pub diagnostics: Vec<TypeTraceDiagnostic>,
}

pub struct TestBuilder {
loader: InMemoryLoader,
loader: MemoryLoader,
entry_point: String,
}

impl TestBuilder {
pub fn new() -> Self {
let loader = InMemoryLoader::default();
Self {
loader,
loader: Default::default(),
entry_point: "file:///mod.ts".to_string(),
}
}

pub fn with_loader(
&mut self,
mut action: impl FnMut(&mut InMemoryLoader),
mut action: impl FnMut(&mut MemoryLoader),
) -> &mut Self {
action(&mut self.loader);
self
Expand All @@ -69,8 +74,23 @@ impl TestBuilder {
self
}

pub async fn trace(&mut self) -> Result<TypeTraceResult> {
let handler = TestTypeTraceHandler::default();
pub async fn build(&mut self) -> BuildResult {
let mut graph = deno_graph::ModuleGraph::new(GraphKind::All);
let entry_point_url = ModuleSpecifier::parse(&self.entry_point).unwrap();
let roots = vec![entry_point_url.clone()];
graph
.build(
roots.clone(),
&mut self.loader,
deno_graph::BuildOptions::default(),
)
.await;
BuildResult { graph }
}

#[cfg(feature = "type_tracing")]
pub async fn trace(&mut self) -> Result<tracing::TypeTraceResult> {
let handler = tracing::TestTypeTraceHandler::default();
let mut graph = deno_graph::ModuleGraph::new(GraphKind::All);
let entry_point_url = ModuleSpecifier::parse(&self.entry_point).unwrap();
let roots = vec![entry_point_url.clone()];
Expand All @@ -84,13 +104,13 @@ impl TestBuilder {
let source_parser = DefaultModuleParser::new_for_analysis();
let capturing_analyzer =
CapturingModuleAnalyzer::new(Some(Box::new(source_parser)), None);
let root_symbol = trace_public_types(
let root_symbol = deno_graph::type_tracer::trace_public_types(
&graph,
&roots,
&capturing_analyzer.as_capturing_parser(),
&handler,
)?;
Ok(TypeTraceResult {
Ok(tracing::TypeTraceResult {
graph: graph.clone(),
root_symbol: root_symbol.clone(),
output: {
Expand All @@ -102,7 +122,8 @@ impl TestBuilder {
output_text.push_str(&format!("{}: {:#?}\n", k.as_str(), v));
}
let get_symbol_text =
|module_symbol: &ModuleSymbol, symbol_id: SymbolId| {
|module_symbol: &deno_graph::type_tracer::ModuleSymbol,
symbol_id: deno_graph::type_tracer::SymbolId| {
let symbol = module_symbol.symbol(symbol_id).unwrap();
let definitions =
root_symbol.go_to_definitions(&graph, module_symbol, symbol);
Expand Down
Loading

0 comments on commit c6d4558

Please sign in to comment.