Skip to content

Commit 426f790

Browse files
committed
fix(fspy): correctly report access mode from node:fs on Windows
# Conflicts: # crates/fspy/tests/node_fs.rs
1 parent 3e53955 commit 426f790

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ dist
44
.claude/settings.local.json
55
*.tsbuildinfo
66
.DS_Store
7+
/.vscode/settings.json

crates/fspy/tests/node_fs.rs

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
mod test_utils;
22

3-
use std::env::{current_dir, vars_os};
3+
use std::{
4+
env::{current_dir, vars_os},
5+
ffi::OsStr,
6+
};
47

58
use fspy::{AccessMode, PathAccessIterable};
69
use test_log::test;
710
use test_utils::assert_contains;
811

9-
async fn track_node_script(script: &str) -> anyhow::Result<PathAccessIterable> {
12+
async fn track_node_script(script: &str, args: &[&OsStr]) -> anyhow::Result<PathAccessIterable> {
1013
let mut command = fspy::Command::new("node");
1114
command
1215
.arg("-e")
1316
.envs(vars_os()) // https://github.com/jdx/mise/discussions/5968
14-
.arg(script);
17+
.arg(script)
18+
.args(args);
1519
let child = command.spawn().await?;
1620
let termination = child.wait_handle.await?;
1721
assert!(termination.status.success());
@@ -20,14 +24,65 @@ async fn track_node_script(script: &str) -> anyhow::Result<PathAccessIterable> {
2024

2125
#[test(tokio::test)]
2226
async fn read_sync() -> anyhow::Result<()> {
23-
let accesses = track_node_script("try { fs.readFileSync('hello') } catch {}").await?;
27+
let accesses = track_node_script("try { fs.readFileSync('hello') } catch {}", &[]).await?;
2428
assert_contains(&accesses, current_dir().unwrap().join("hello").as_path(), AccessMode::Read);
2529
Ok(())
2630
}
2731

32+
#[test(tokio::test)]
33+
async fn exist_sync() -> anyhow::Result<()> {
34+
let accesses = track_node_script("try { fs.existsSync('hello') } catch {}", &[]).await?;
35+
assert_contains(&accesses, current_dir().unwrap().join("hello").as_path(), AccessMode::Read);
36+
Ok(())
37+
}
38+
39+
#[test(tokio::test)]
40+
async fn stat_sync() -> anyhow::Result<()> {
41+
let accesses = track_node_script("try { fs.statSync('hello') } catch {}", &[]).await?;
42+
assert_contains(&accesses, current_dir().unwrap().join("hello").as_path(), AccessMode::Read);
43+
Ok(())
44+
}
45+
46+
#[test(tokio::test)]
47+
async fn create_read_stream() -> anyhow::Result<()> {
48+
let accesses = track_node_script(
49+
"try { fs.createReadStream('hello').on('error', () => {}) } catch {}",
50+
&[],
51+
)
52+
.await?;
53+
assert_contains(&accesses, current_dir().unwrap().join("hello").as_path(), AccessMode::Read);
54+
Ok(())
55+
}
56+
57+
#[test(tokio::test)]
58+
async fn create_write_stream() -> anyhow::Result<()> {
59+
let tmpdir = tempfile::tempdir()?;
60+
let file_path = tmpdir.path().join("hello");
61+
let accesses = track_node_script(
62+
"try { fs.createWriteStream(process.argv[1]).on('error', () => {}) } catch {}",
63+
&[file_path.as_os_str()],
64+
)
65+
.await?;
66+
assert_contains(&accesses, file_path.as_path(), AccessMode::Write);
67+
Ok(())
68+
}
69+
70+
#[test(tokio::test)]
71+
async fn write_sync() -> anyhow::Result<()> {
72+
let tmpdir = tempfile::tempdir()?;
73+
let file_path = tmpdir.path().join("hello");
74+
let accesses = track_node_script(
75+
"try { fs.writeFileSync(process.argv[1], '') } catch {}",
76+
&[file_path.as_os_str()],
77+
)
78+
.await?;
79+
assert_contains(&accesses, &file_path, AccessMode::Write);
80+
Ok(())
81+
}
82+
2883
#[test(tokio::test)]
2984
async fn read_dir_sync() -> anyhow::Result<()> {
30-
let accesses = track_node_script("try { fs.readdirSync('.') } catch {}").await?;
85+
let accesses = track_node_script("try { fs.readdirSync('.') } catch {}", &[]).await?;
3186
assert_contains(&accesses, &current_dir().unwrap(), AccessMode::ReadDir);
3287
Ok(())
3388
}
@@ -39,9 +94,10 @@ async fn subprocess() -> anyhow::Result<()> {
3994
} else {
4095
r"'/bin/sh', ['-c', 'cat hello']"
4196
};
42-
let accesses = track_node_script(&format!(
43-
"try {{ child_process.spawnSync({cmd}, {{ stdio: 'ignore' }}) }} catch {{}}"
44-
))
97+
let accesses = track_node_script(
98+
&format!("try {{ child_process.spawnSync({cmd}, {{ stdio: 'ignore' }}) }} catch {{}}"),
99+
&[],
100+
)
45101
.await?;
46102
assert_contains(&accesses, current_dir().unwrap().join("hello").as_path(), AccessMode::Read);
47103
Ok(())

crates/fspy_preload_windows/src/windows/winapi_utils.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use winapi::{
1212
},
1313
um::{
1414
fileapi::GetFinalPathNameByHandleW,
15-
winnt::{ACCESS_MASK, GENERIC_READ, GENERIC_WRITE},
15+
winnt::{ACCESS_MASK, FILE_APPEND_DATA, FILE_READ_DATA, FILE_WRITE_DATA},
1616
},
1717
};
1818
use winsafe::{GetLastError, co};
@@ -72,8 +72,8 @@ pub unsafe fn get_path_name(handle: HANDLE) -> winsafe::SysResult<SmallVec<u16,
7272
}
7373

7474
pub fn access_mask_to_mode(desired_access: ACCESS_MASK) -> AccessMode {
75-
let has_write = (desired_access & GENERIC_WRITE) != 0;
76-
let has_read = (desired_access & GENERIC_READ) != 0;
75+
let has_write = (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
76+
let has_read = (desired_access & FILE_READ_DATA) != 0;
7777
if has_write {
7878
if has_read { AccessMode::ReadWrite } else { AccessMode::Write }
7979
} else {

0 commit comments

Comments
 (0)