use ide_run::{
detect,
dotnet::{parse_profiles, parse_project, resolve, solution_projects},
};
use std::fs;
use std::path::PathBuf;
const CONSOLE: &str = r#"Exenet10.0; net9.0"#;
const PROFILES: &str = r#"{
// Only Project profiles can be run with dotnet.
"profiles": {
"http": {"commandName":"Project", "applicationUrl":"http://localhost:5165", "commandLineArgs":"--message \"hello world\"", "workingDirectory":"work", "environmentVariables":{"DEMO":"profile"}},
"https": {"commandName":"Project", "environmentVariables":{"DEMO":"https"}},
"IIS Express": {"commandName":"IISExpress"},
"external": {"commandName":"Executable"},
"broken": {"commandName":"Project", "environmentVariables":7}
}
}"#;
fn write(root: &std::path::Path, file: &str, src: &str) {
let path = root.join(file);
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, src).unwrap();
}
#[test]
fn project_properties_and_sdk_defaults() {
let p = parse_project(CONSOLE).unwrap();
assert!(p.executable && !p.test);
assert_eq!(p.frameworks, ["net10.0", "net9.0"]);
for (sdk, output, executable) in [
("Microsoft.NET.Sdk", "", false),
("Microsoft.NET.Sdk", "WinExe", true),
("Microsoft.NET.Sdk.Web", "", true),
("Microsoft.NET.Sdk.Web", "Library", false),
] {
let xml = format!(
r#"{output}net10.0"#
);
let p = parse_project(&xml).unwrap();
assert_eq!(p.executable, executable, "{xml}");
assert_eq!(p.frameworks, ["net10.0"]);
}
let p = parse_project(r#"net10.0Library"#).unwrap();
assert!(p.executable && p.test);
assert!(parse_project("").is_none());
assert!(parse_project("garbage").is_none());
assert!(
parse_project(
r#""#
)
.unwrap()
.test
);
assert!(
!parse_project(r#""#)
.unwrap()
.test
);
}
#[test]
fn profiles_filter_and_preserve_launch_properties() {
let p = parse_profiles(PROFILES);
assert_eq!(p.keys().map(String::as_str).collect::>(), ["http", "https"]);
assert_eq!(p["http"].application_url, "http://localhost:5165");
assert_eq!(p["http"].environment_variables["DEMO"], "profile");
assert_eq!(p["http"].command_line_args, "--message \"hello world\"");
assert_eq!(p["http"].working_directory, "work");
assert!(parse_profiles("invalid").is_empty());
}
#[test]
fn solution_paths_support_windows_separators_folders_and_entities() {
let sln = "Project(\"{guid}\") = \"App\", \"src\\App\\App.csproj\", \"{guid}\"\nEndProject\nProject(\"{folder}\") = \"Folder\", \"Folder\", \"{guid}\"\nProject(\"{guid}\") = \"External\", \"..\\other\\Other.csproj\", \"{guid}\"";
assert_eq!(
solution_projects(sln, false),
[PathBuf::from("src/App/App.csproj"), PathBuf::from("../other/Other.csproj")]
);
let slnx = r#""#;
assert_eq!(solution_projects(slnx, true), [PathBuf::from("src/A&B/App.csproj")]);
assert!(solution_projects(""#,
);
write(
root,
"src/Test/Test.csproj",
r#"net10.0"#,
);
write(root, "bin/Ignored.csproj", CONSOLE);
write(root, "obj/Ignored.csproj", CONSOLE);
write(root, "node_modules/Ignored.csproj", CONSOLE);
write(root, "Lib.csproj", "");
let configs = detect(root);
assert_eq!(configs.len(), 4);
let app = configs.iter().find(|c| c.extras.params.get("launchProfile").is_some_and(|p| p == "http")).unwrap();
assert_eq!(
app.args,
["run", "--project", "src/App/App.csproj", "--framework", "net10.0", "--launch-profile", "http"]
);
assert_eq!(app.debug_adapter.as_deref(), Some("netcoredbg"));
assert_eq!(app.extras.before_launch[0].kind, "dotnetBuild");
let test = configs.iter().find(|c| c.is_test).unwrap();
assert_eq!(test.kind, "dotnet-test");
assert_eq!(test.args, ["test", "src/Test/Test.csproj", "--framework", "net10.0"]);
assert!(test.debug_adapter.is_none());
let mut edited = app.clone();
edited.env.insert("DEMO".into(), "override".into());
let resolved = resolve(root, edited.clone()).unwrap();
assert_eq!(resolved.env["DEMO"], "override");
assert_eq!(resolved.env["ASPNETCORE_URLS"], "http://localhost:5165");
assert!(resolved.cwd.unwrap().ends_with("src/App/work"));
edited.extras.params.insert("launchProfile".into(), "https".into());
let resolved = resolve(root, edited).unwrap();
assert!(!resolved.env.contains_key("ASPNETCORE_URLS"));
assert!(resolved.cwd.unwrap().ends_with("src/App"));
}
#[test]
fn solution_references_can_reach_projects_outside_the_open_directory() {
let temp = tempfile::tempdir().unwrap();
write(temp.path(), "external/App.csproj", CONSOLE);
write(temp.path(), "open/demo.sln", "Project(\"{guid}\") = \"App\", \"..\\external\\App.csproj\", \"{guid}\"");
let configs = detect(&temp.path().join("open"));
assert_eq!(configs.len(), 1);
assert!(configs[0].args[2].ends_with("external/App.csproj"));
}