Skip to content

host-core tests compare against std Path::canonicalize and fail on Windows (11 tests) #208

Description

@dajiaohuang

Summary

cargo test -p host-core --locked is red on Windows because 11 test expectations spell the expected path with std Path::canonicalize() while the code under test spells its results with the crate's own simple_canonicalize(). On Windows the two disagree, so the assertions fail there and nowhere else.

Root cause

crates/host-core/src/workspace.rs defines:

/// Canonicalize a path, stripping the Windows extended-length prefix (`\?\`)
/// when the result is a simple drive-letter path (e.g. `C:\...`).
fn simple_canonicalize(path: &Path) -> std::io::Result<PathBuf> {
    let canonical = path.canonicalize()?;
    #[cfg(windows)]
    { /* strip `\?\X:\...` -> `X:\...` */ }
    Ok(canonical)
}

The stripping is deliberate — the doc comment explains that shell APIs such as ShellExecuteW reject \?\. Every path the resolver returns (resolve_in_workspace, resolve_tool_path, resolve_external_path, via resolve_with_existing_ancestor) carries that spelling.

The tests, however, build their expected value with Path::canonicalize() / .canonicalize() directly, which keeps \?\ on Windows. Path equality and strip_prefix compare components, and VerbatimDisk('C') != Disk('C'), so the two never match on Windows. On Linux/macOS both spellings are identical, which is why CI — ubuntu-latest only — has never caught this.

Failing tests (Windows, cargo 1.98.1, after #207 which fixes the unrelated relative_display case)

workspace::tests::allows_new_nested_path                              (workspace.rs:326)
workspace::tests::tool_path_relative_resolves_to_workspace            (workspace.rs:394)
workspace::tests::tool_path_absolute_scratch_resolves_to_scratch      (workspace.rs:405)
workspace::tests::approved_external_path_resolves_and_keeps_absolute_identity (workspace.rs:450)
workspace::tests::relative_escape_can_be_resolved_only_after_external_approval (workspace.rs:468)
rpc::tests::project_create_returns_an_id_without_switching_workspace  (rpc/mod.rs:3778)
rpc::tests::builtin_delegate_without_permission_scope_inherits_auto_for_external_glob (rpc/mod.rs:6049)
sessions::tests::create_session_returns_canonical_project_path        (sessions.rs:3228)
tools::tests::approved_external_paths_work_for_read_and_search_tools  (tools/mod.rs:3297)
mcp_servers::tests::project_server_is_copied_and_state_is_pruned_after_removal (mcp_servers.rs:624)
user_skills::tests::imports_one_file_into_the_selected_agents_directory (user_skills.rs:543)

Representative assertion output:

thread 'workspace::tests::tool_path_relative_resolves_to_workspace' panicked at workspace.rs:394:
assertion failed: p.starts_with(ws.path().canonicalize().unwrap())

Why the production code is right and the tests are wrong

workspace::path_is_within already handles Windows explicitly (case-insensitive component comparison), and db.rs / sessions.rs normalize separators for protocol paths. So simple_canonicalize is the intended canonical spelling, and the expectations are the side that is out of step.

Note some of these tests are not simply "expected == std canonicalize":
mcp_servers.rs:624 and user_skills.rs:543 compare against a raw dir.path().join(...) that was never canonicalized at all, so they also fail whenever the temp root's raw spelling (e.g. an 8.3 short name such as DAJIAO~1) differs from its canonical spelling.

Proposed fix

Have the expectations canonicalize with the same helper the code uses — simple_canonicalize — rather than Path::canonicalize(). That makes the assertion compare like with like on every platform and keeps the Windows-specific behavior covered instead of skipped.

If the maintainers would rather not widen the helper's visibility for tests, the alternative is to #[cfg(unix)]-gate the affected assertions, but that drops Windows coverage of a containment boundary, so the first option seems preferable.

Environment

PI-Desktop 6e6d710e (main), Windows 10 Pro N 19045, rustc 1.98.1, cargo 1.98.1. CI (ci.yml) runs cargo test -p host-core --locked on ubuntu-latest only.

I am happy to send a PR for this if the direction is agreed — it is a test-expectation change with no production behavior change.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: platformOperating-system and environment-specific behaviorbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions