Skip to content

Commit 3c5aa03

Browse files
committed
finish Cmd refactor, ressurect tests
1 parent a4f6ede commit 3c5aa03

4 files changed

Lines changed: 125 additions & 76 deletions

File tree

examples/command.roc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ main! = |_args| {
3434

3535
Stdout.line!("Exit code: ${exit_code.to_str()}")?
3636
37-
# TODO add exec_output_bytes
38-
3937
# To execute and capture the output (stdout and stderr) in the original form as bytes without inheriting your terminal.
4038
# Prefer using `exec_output!`.
4139
cmd_output_bytes =

platform/Cmd.roc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ Cmd :: {
117117
##
118118
## Stdout.line!("${Str.inspect(cmd_output_bytes)}")? # {stderr_bytes: [], stdout_bytes: [72, 105, 10]}
119119
## ```
120-
#exec_output_bytes! : Cmd => Try(
121-
# { stderr_bytes : List(U8), stdout_bytes : List(U8) },
122-
# [
123-
# FailedToGetExitCodeB(IOErr), # TODO: perhaps no need for B?
124-
# NonZeroExitCode({ exit_code : I32, stderr_bytes : List(U8), stdout_bytes : List(U8) }),
125-
# ..
126-
# ]
127-
#)
120+
exec_output_bytes! : Cmd => Try(
121+
{ stderr_bytes : List(U8), stdout_bytes : List(U8) },
122+
[
123+
NonZeroExitCodeB({ exit_code : I32, stdout_bytes : List(U8), stderr_bytes : List(U8) }),
124+
FailedToGetExitCodeB(IOErr),
125+
..
126+
]
127+
)
128128
exec_output_bytes! = |cmd| {
129129
exec_try = host_exec_output!(cmd)
130130

src/lib.rs

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -192,72 +192,6 @@ extern "C" fn roc_crashed_fn(roc_crashed: *const RocCrashed, _env: *mut c_void)
192192
}
193193
}
194194

195-
// ============================================================================
196-
// Cmd Module Types and Functions
197-
// ============================================================================
198-
199-
/// Output record: { stderr_utf8_lossy : Str, stdout_utf8 : Str }
200-
/// Memory layout: Both RocLists are 24 bytes, alphabetical: stderr_utf8_lossy, stdout_utf8
201-
// #[repr(C)]
202-
// pub struct OutputFromHostSuccess {
203-
// pub stderr_utf8_lossy: RocList<u8>, // offset 0 (24 bytes)
204-
// pub stdout_utf8: RocList<u8>, // offset 24 (24 bytes)
205-
// }
206-
207-
// /// Output record: { exit_code : I32, stderr_utf8_lossy : List(U8), stdout_utf8_lossy : List(U8) }
208-
// /// Memory layout: RocList (24 bytes) > I32 (4 bytes), so: stderr_utf8_lossy, stdout_utf8_lossy, exit_code
209-
// #[repr(C)]
210-
// pub struct OutputFromHostFailure {
211-
// pub stderr_utf8_lossy: RocList<u8>, // offset 0 (24 bytes)
212-
// pub stdout_utf8_lossy: RocList<u8>, // offset 24 (24 bytes)
213-
// pub exit_code: i32, // offset 48 (4 bytes + padding)
214-
// }
215-
216-
// /// Error type for command_exec_output!: [CmdErr(IOErr), NonZeroExit({ exit_code, stderr, stdout })]
217-
// /// Alphabetically: CmdErr=0, NonZeroExit=1
218-
// #[repr(C)]
219-
// pub union CmdOutputErrPayload {
220-
// cmd_err: core::mem::ManuallyDrop<roc_io_error::IOErr>,
221-
// non_zero_exit: core::mem::ManuallyDrop<NonZeroExitPayload>,
222-
// }
223-
224-
// #[repr(C)]
225-
// pub struct CmdOutputErr {
226-
// payload: CmdOutputErrPayload,
227-
// discriminant: u8, // CmdErr=0, NonZeroExit=1
228-
// }
229-
230-
// impl CmdOutputErr {
231-
// pub fn cmd_err(io_err: roc_io_error::IOErr) -> Self {
232-
// Self {
233-
// payload: CmdOutputErrPayload {
234-
// cmd_err: core::mem::ManuallyDrop::new(io_err),
235-
// },
236-
// discriminant: 0,
237-
// }
238-
// }
239-
240-
// pub fn non_zero_exit(
241-
// stderr_utf8_lossy: RocStr,
242-
// stdout_utf8_lossy: RocStr,
243-
// exit_code: i32,
244-
// ) -> Self {
245-
// Self {
246-
// payload: CmdOutputErrPayload {
247-
// non_zero_exit: core::mem::ManuallyDrop::new(NonZeroExitPayload {
248-
// stderr_utf8_lossy,
249-
// stdout_utf8_lossy,
250-
// exit_code,
251-
// }),
252-
// },
253-
// discriminant: 1,
254-
// }
255-
// }
256-
// }
257-
258-
/// Type alias for Try({ stderr, stdout }, [CmdErr(IOErr), NonZeroExit(...)]) - using official RocTry
259-
//type TryCmdOutputResult = RocTry<CmdOutputSuccess, CmdOutputErr>;
260-
261195
// ============================================================================
262196
// Hosted Functions (sorted alphabetically by fully-qualified name)
263197
// ============================================================================

tests/cmd-test.roc

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
app [main!] { pf: platform "../platform/main.roc" }
2+
3+
import pf.Stdout
4+
import pf.Cmd
5+
6+
# Tests all error cases in Cmd functions.
7+
8+
main! = |_args| {
9+
10+
# exec!
11+
expect_err(
12+
Cmd.exec!("blablaXYZ", []),
13+
"Try.Err(FailedToGetExitCode({ command: \"{ cmd: blablaXYZ, args: }\", err: NotFound }))"
14+
)?
15+
16+
# expect_err(
17+
# Cmd.exec!("cat", ["non_existent.txt"]),
18+
# "(Err (ExecFailed {command: \"cat non_existent.txt\", exit_code: 1}))"
19+
# )?
20+
21+
# # exec_cmd!
22+
# expect_err(
23+
# Cmd.new("blablaXYZ")
24+
# |> Cmd.exec_cmd!,
25+
# "(Err (FailedToGetExitCode {command: \"{ cmd: blablaXYZ, args: }\", err: NotFound}))"
26+
# )?
27+
28+
# expect_err(
29+
# Cmd.new("cat")
30+
# |> Cmd.arg("non_existent.txt")
31+
# |> Cmd.exec_cmd!,
32+
# "(Err (ExecCmdFailed {command: \"{ cmd: cat, args: non_existent.txt }\", exit_code: 1}))"
33+
# )?
34+
35+
# # exec_output!
36+
# expect_err(
37+
# Cmd.new("blablaXYZ")
38+
# |> Cmd.exec_output!,
39+
# "(Err (FailedToGetExitCode {command: \"{ cmd: blablaXYZ, args: }\", err: NotFound}))"
40+
# )?
41+
42+
# expect_err(
43+
# Cmd.new("cat")
44+
# |> Cmd.arg("non_existent.txt")
45+
# |> Cmd.exec_output!,
46+
# "(Err (NonZeroExitCode {command: \"{ cmd: cat, args: non_existent.txt }\", exit_code: 1, stderr_utf8_lossy: \"cat: non_existent.txt: No such file or directory\n\", stdout_utf8_lossy: \"\"}))"
47+
# )?
48+
49+
# # Test StdoutContainsInvalidUtf8 - using printf to output invalid UTF-8 bytes
50+
# expect_err(
51+
# Cmd.new("printf")
52+
# |> Cmd.args(["\\377\\376"]) # Invalid UTF-8 sequence
53+
# |> Cmd.exec_output!,
54+
# "(Err (StdoutContainsInvalidUtf8 {cmd_str: \"{ cmd: printf, args: \\377\\376 }\", err: (BadUtf8 {index: 0, problem: InvalidStartByte})}))"
55+
# )?
56+
57+
# # exec_output_bytes!
58+
# expect_err(
59+
# Cmd.new("blablaXYZ")
60+
# |> Cmd.exec_output_bytes!,
61+
# "(Err (FailedToGetExitCodeB NotFound))"
62+
# )?
63+
64+
# expect_err(
65+
# Cmd.new("cat")
66+
# |> Cmd.arg("non_existent.txt")
67+
# |> Cmd.exec_output_bytes!,
68+
# "(Err (NonZeroExitCodeB {exit_code: 1, stderr_bytes: [99, 97, 116, 58, 32, 110, 111, 110, 95, 101, 120, 105, 115, 116, 101, 110, 116, 46, 116, 120, 116, 58, 32, 78, 111, 32, 115, 117, 99, 104, 32, 102, 105, 108, 101, 32, 111, 114, 32, 100, 105, 114, 101, 99, 116, 111, 114, 121, 10], stdout_bytes: []}))"
69+
# )?
70+
71+
# # exec_exit_code!
72+
# expect_err(
73+
# Cmd.new("blablaXYZ")
74+
# |> Cmd.exec_exit_code!,
75+
# "(Err (FailedToGetExitCode {command: \"{ cmd: blablaXYZ, args: }\", err: NotFound}))"
76+
# )?
77+
78+
# # exec_exit_code! with non-zero exit code is not an error - it returns the exit code
79+
# exit_code =
80+
# Cmd.new("cat")
81+
# |> Cmd.arg("non_existent.txt")
82+
# |> Cmd.exec_exit_code!()?
83+
#
84+
# if exit_code == 1 {
85+
# Ok({})?
86+
# } else {
87+
# Err(FailedExpectation(
88+
# """
89+
#
90+
# - Expected:
91+
# 1
92+
#
93+
# - Got:
94+
# ${Inspect.to_str(exit_code)}
95+
#
96+
# """
97+
# ))?
98+
# }
99+
100+
Stdout.line!("All tests passed.")?
101+
102+
Ok({})
103+
}
104+
105+
expect_err = |err, expected_str| {
106+
if Str.inspect(err) == expected_str {
107+
Ok({})
108+
} else {
109+
Err(FailedExpectation(
110+
\\- Expected:
111+
\\${expected_str}
112+
113+
\\- Got:
114+
\\${Str.inspect(err)}
115+
))
116+
}
117+
}

0 commit comments

Comments
 (0)