185 lines
6.1 KiB
Rust
185 lines
6.1 KiB
Rust
use std::{
|
|
fs,
|
|
path::PathBuf,
|
|
process::{Command, Output},
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
};
|
|
|
|
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
#[test]
|
|
fn symbols_single_file_reports_editor_facing_source_metadata() {
|
|
let source = r#"(module docs (export main))
|
|
|
|
(type Count i32)
|
|
|
|
(struct Point
|
|
(x i32)
|
|
(y i32))
|
|
|
|
(enum Status Ready (Blocked i32))
|
|
|
|
(fn main () -> i32
|
|
0)
|
|
|
|
(test "main returns zero"
|
|
(= (main) 0))
|
|
"#;
|
|
let file = write_file("symbols-file", source);
|
|
|
|
let output = run_glagol(["symbols".as_ref(), file.as_os_str()]);
|
|
|
|
assert_success("symbols file", &output);
|
|
assert!(output.stderr.is_empty(), "symbols wrote stderr");
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.starts_with("(symbols\n"));
|
|
assert!(stdout.contains(" (schema slovo.symbols)\n"));
|
|
assert!(stdout.contains(" (version \"1.0.0-beta.10\")\n"));
|
|
assert!(stdout.contains(&format!(" (path \"{}\")\n", file.display())));
|
|
assert!(stdout.contains(" (name \"docs\")\n"));
|
|
assert!(stdout.contains(" (module_span (span "));
|
|
assert!(stdout.contains("(range (start (line 1) (column 1))"));
|
|
assert!(stdout.contains(" (name \"main\")\n"));
|
|
assert!(stdout.contains(" (name \"Count\")\n"));
|
|
assert!(stdout.contains(" (name \"Point\")\n"));
|
|
assert!(stdout.contains(" (name \"Status\")\n"));
|
|
assert!(stdout.contains(" (name \"Blocked\")\n"));
|
|
assert!(stdout.contains(" (name \"main returns zero\")\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn symbols_project_writes_output_and_manifest_without_stdout() {
|
|
let project = write_project(
|
|
"symbols-project",
|
|
&[(
|
|
"math",
|
|
"(module math (export one))\n\n(fn one () -> i32\n 1)\n",
|
|
)],
|
|
"(module main)\n\n(import math (one))\n\n(fn main () -> i32\n (one))\n",
|
|
);
|
|
let output_path = unique_path("symbols-project-out").with_extension("sexpr");
|
|
let manifest_path = unique_path("symbols-project-manifest").with_extension("slo");
|
|
|
|
let output = run_glagol([
|
|
"symbols".as_ref(),
|
|
project.as_os_str(),
|
|
"-o".as_ref(),
|
|
output_path.as_os_str(),
|
|
"--manifest".as_ref(),
|
|
manifest_path.as_os_str(),
|
|
]);
|
|
|
|
assert_success("symbols project", &output);
|
|
assert!(output.stdout.is_empty(), "symbols -o wrote stdout");
|
|
assert!(output.stderr.is_empty(), "symbols project wrote stderr");
|
|
|
|
let symbols = fs::read_to_string(&output_path).expect("read symbols output");
|
|
assert!(symbols.contains(" (name \"main\")\n"));
|
|
assert!(symbols.contains(" (name \"math\")\n"));
|
|
assert!(symbols.contains(" (module \"math\")\n"));
|
|
assert!(symbols.contains(" (name \"one\")\n"));
|
|
assert!(symbols.contains(" (imports\n"));
|
|
assert!(symbols.contains(" (functions\n"));
|
|
|
|
let manifest = fs::read_to_string(&manifest_path).expect("read symbols manifest");
|
|
assert!(manifest.contains(" (mode symbols)\n"));
|
|
assert!(manifest.contains(" (kind symbols)\n"));
|
|
assert!(manifest.contains(&format!(" (path \"{}\")\n", output_path.display())));
|
|
}
|
|
|
|
#[test]
|
|
fn symbols_workspace_includes_package_names_deterministically() {
|
|
let workspace = unique_path("symbols-workspace");
|
|
let scaffold = run_glagol([
|
|
"new".as_ref(),
|
|
workspace.as_os_str(),
|
|
"--template".as_ref(),
|
|
"workspace".as_ref(),
|
|
]);
|
|
assert_success("workspace scaffold", &scaffold);
|
|
|
|
let first = run_glagol(["symbols".as_ref(), workspace.as_os_str()]);
|
|
let second = run_glagol(["symbols".as_ref(), workspace.as_os_str()]);
|
|
|
|
assert_success("symbols workspace first", &first);
|
|
assert_success("symbols workspace second", &second);
|
|
assert_eq!(
|
|
first.stdout, second.stdout,
|
|
"workspace symbols output was not deterministic"
|
|
);
|
|
let stdout = String::from_utf8_lossy(&first.stdout);
|
|
assert!(stdout.contains(" (package \"app\")\n"));
|
|
assert!(stdout.contains(" (package \"libutil\")\n"));
|
|
assert!(stdout.contains(" (module \"libutil.libutil\")\n"));
|
|
}
|
|
|
|
#[test]
|
|
fn symbols_usage_is_part_of_the_public_cli_surface() {
|
|
let output = run_glagol([std::ffi::OsStr::new("--help")]);
|
|
|
|
assert_success("glagol help", &output);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("glagol symbols <file.slo|project|workspace>"));
|
|
}
|
|
|
|
fn write_project(name: &str, modules: &[(&str, &str)], main: &str) -> PathBuf {
|
|
let project = unique_path(name);
|
|
fs::create_dir_all(project.join("src")).expect("create project src");
|
|
fs::write(
|
|
project.join("slovo.toml"),
|
|
format!(
|
|
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
name
|
|
),
|
|
)
|
|
.expect("write manifest");
|
|
for (module, source) in modules {
|
|
fs::write(project.join("src").join(format!("{}.slo", module)), source)
|
|
.expect("write module");
|
|
}
|
|
fs::write(project.join("src/main.slo"), main).expect("write main");
|
|
project
|
|
}
|
|
|
|
fn write_file(name: &str, source: &str) -> PathBuf {
|
|
let path = unique_path(name).with_extension("slo");
|
|
fs::write(&path, source).expect("write fixture");
|
|
path
|
|
}
|
|
|
|
fn unique_path(name: &str) -> PathBuf {
|
|
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
|
|
let nanos = std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.expect("system clock before UNIX_EPOCH")
|
|
.as_nanos();
|
|
std::env::temp_dir().join(format!(
|
|
"glagol-symbols-beta10-{}-{}-{}-{}",
|
|
std::process::id(),
|
|
nanos,
|
|
id,
|
|
name
|
|
))
|
|
}
|
|
|
|
fn run_glagol<I, S>(args: I) -> Output
|
|
where
|
|
I: IntoIterator<Item = S>,
|
|
S: AsRef<std::ffi::OsStr>,
|
|
{
|
|
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
.args(args)
|
|
.output()
|
|
.expect("run glagol")
|
|
}
|
|
|
|
fn assert_success(context: &str, output: &Output) {
|
|
assert!(
|
|
output.status.success(),
|
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
context,
|
|
String::from_utf8_lossy(&output.stdout),
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|