mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
add stdin support for cli tests (currently unused)
This commit is contained in:
parent
999f3cfce6
commit
4bd9d417d1
7 changed files with 120 additions and 20 deletions
|
@ -23,6 +23,24 @@ mod cli_run {
|
||||||
flags: &[&str],
|
flags: &[&str],
|
||||||
expected_ending: &str,
|
expected_ending: &str,
|
||||||
use_valgrind: bool,
|
use_valgrind: bool,
|
||||||
|
) {
|
||||||
|
check_output_with_stdin(
|
||||||
|
file,
|
||||||
|
"",
|
||||||
|
executable_filename,
|
||||||
|
flags,
|
||||||
|
expected_ending,
|
||||||
|
use_valgrind,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_output_with_stdin(
|
||||||
|
file: &Path,
|
||||||
|
stdin_str: &str,
|
||||||
|
executable_filename: &str,
|
||||||
|
flags: &[&str],
|
||||||
|
expected_ending: &str,
|
||||||
|
use_valgrind: bool,
|
||||||
) {
|
) {
|
||||||
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat());
|
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat());
|
||||||
if !compile_out.stderr.is_empty() {
|
if !compile_out.stderr.is_empty() {
|
||||||
|
@ -31,8 +49,10 @@ mod cli_run {
|
||||||
assert!(compile_out.status.success());
|
assert!(compile_out.status.success());
|
||||||
|
|
||||||
let out = if use_valgrind {
|
let out = if use_valgrind {
|
||||||
let (valgrind_out, raw_xml) =
|
let (valgrind_out, raw_xml) = run_with_valgrind(
|
||||||
run_with_valgrind(&[file.with_file_name(executable_filename).to_str().unwrap()]);
|
stdin_str,
|
||||||
|
&[file.with_file_name(executable_filename).to_str().unwrap()],
|
||||||
|
);
|
||||||
|
|
||||||
if valgrind_out.status.success() {
|
if valgrind_out.status.success() {
|
||||||
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
|
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
|
||||||
|
@ -55,6 +75,7 @@ mod cli_run {
|
||||||
} else {
|
} else {
|
||||||
run_cmd(
|
run_cmd(
|
||||||
file.with_file_name(executable_filename).to_str().unwrap(),
|
file.with_file_name(executable_filename).to_str().unwrap(),
|
||||||
|
stdin_str,
|
||||||
&[],
|
&[],
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -174,8 +195,9 @@ mod cli_run {
|
||||||
#[test]
|
#[test]
|
||||||
#[serial(nqueens)]
|
#[serial(nqueens)]
|
||||||
fn run_nqueens_not_optimized() {
|
fn run_nqueens_not_optimized() {
|
||||||
check_output(
|
check_output_with_stdin(
|
||||||
&example_file("benchmarks", "NQueens.roc"),
|
&example_file("benchmarks", "NQueens.roc"),
|
||||||
|
"",
|
||||||
"nqueens",
|
"nqueens",
|
||||||
&[],
|
&[],
|
||||||
"4\n",
|
"4\n",
|
||||||
|
|
|
@ -61,15 +61,29 @@ pub fn run_roc(args: &[&str]) -> Out {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn run_cmd(cmd_name: &str, args: &[&str]) -> Out {
|
pub fn run_cmd(cmd_name: &str, stdin_str: &str, args: &[&str]) -> Out {
|
||||||
let mut cmd = Command::new(cmd_name);
|
let mut cmd = Command::new(cmd_name);
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
cmd.arg(arg);
|
cmd.arg(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = cmd
|
let mut child = cmd
|
||||||
.output()
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap_or_else(|_| panic!("failed to execute cmd `{}` in CLI test", cmd_name));
|
||||||
|
|
||||||
|
{
|
||||||
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
|
stdin
|
||||||
|
.write_all(stdin_str.as_bytes())
|
||||||
|
.expect("Failed to write to stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = child
|
||||||
|
.wait_with_output()
|
||||||
.unwrap_or_else(|_| panic!("failed to execute cmd `{}` in CLI test", cmd_name));
|
.unwrap_or_else(|_| panic!("failed to execute cmd `{}` in CLI test", cmd_name));
|
||||||
|
|
||||||
Out {
|
Out {
|
||||||
|
@ -80,7 +94,7 @@ pub fn run_cmd(cmd_name: &str, args: &[&str]) -> Out {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn run_with_valgrind(args: &[&str]) -> (Out, String) {
|
pub fn run_with_valgrind(stdin_str: &str, args: &[&str]) -> (Out, String) {
|
||||||
//TODO: figure out if there is a better way to get the valgrind executable.
|
//TODO: figure out if there is a better way to get the valgrind executable.
|
||||||
let mut cmd = Command::new("valgrind");
|
let mut cmd = Command::new("valgrind");
|
||||||
let named_tempfile =
|
let named_tempfile =
|
||||||
|
@ -114,8 +128,23 @@ pub fn run_with_valgrind(args: &[&str]) -> (Out, String) {
|
||||||
cmd.arg(arg);
|
cmd.arg(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = cmd
|
cmd.stdin(Stdio::piped());
|
||||||
.output()
|
cmd.stdout(Stdio::piped());
|
||||||
|
cmd.stderr(Stdio::piped());
|
||||||
|
|
||||||
|
let mut child = cmd
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to execute compiled `valgrind` binary in CLI test");
|
||||||
|
|
||||||
|
{
|
||||||
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
|
stdin
|
||||||
|
.write_all(stdin_str.as_bytes())
|
||||||
|
.expect("Failed to write to stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = child
|
||||||
|
.wait_with_output()
|
||||||
.expect("failed to execute compiled `valgrind` binary in CLI test");
|
.expect("failed to execute compiled `valgrind` binary in CLI test");
|
||||||
|
|
||||||
let mut file = named_tempfile.into_file();
|
let mut file = named_tempfile.into_file();
|
||||||
|
|
|
@ -1791,14 +1791,12 @@ fn update<'a>(
|
||||||
|
|
||||||
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
||||||
|
|
||||||
if false {
|
Proc::optimize_refcount_operations(
|
||||||
Proc::optimize_refcount_operations(
|
arena,
|
||||||
arena,
|
module_id,
|
||||||
module_id,
|
&mut ident_ids,
|
||||||
&mut ident_ids,
|
&mut state.procedures,
|
||||||
&mut state.procedures,
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.constrained_ident_ids.insert(module_id, ident_ids);
|
state.constrained_ident_ids.insert(module_id, ident_ids);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ app "nqueens"
|
||||||
|
|
||||||
main : Task.Task {} []
|
main : Task.Task {} []
|
||||||
main =
|
main =
|
||||||
|
# Task.after Task.getInt \n ->
|
||||||
queens 6
|
queens 6
|
||||||
|> Str.fromInt
|
|> Str.fromInt
|
||||||
|> Task.putLine
|
|> Task.putLine
|
||||||
|
|
|
@ -6,7 +6,8 @@ platform folkertdev/foo
|
||||||
provides [ mainForHost ]
|
provides [ mainForHost ]
|
||||||
effects Effect
|
effects Effect
|
||||||
{
|
{
|
||||||
putLine : Str -> Effect {}
|
putLine : Str -> Effect {},
|
||||||
|
getInt : Effect { value: I64, errorCode: [ A, B ], isError: Bool }
|
||||||
}
|
}
|
||||||
|
|
||||||
mainForHost : Task.Task {} [] as Fx
|
mainForHost : Task.Task {} [] as Fx
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
interface Task
|
interface Task
|
||||||
exposes [ Task, succeed, fail, after, map, putLine ]
|
exposes [ Task, succeed, fail, after, map, putLine, getInt ]
|
||||||
imports [ Effect ]
|
imports [ Effect ]
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ fail : err -> Task * err
|
||||||
fail = \val ->
|
fail = \val ->
|
||||||
Effect.always (Err val)
|
Effect.always (Err val)
|
||||||
|
|
||||||
|
|
||||||
after : Task a err, (a -> Task b err) -> Task b err
|
after : Task a err, (a -> Task b err) -> Task b err
|
||||||
after = \effect, transform ->
|
after = \effect, transform ->
|
||||||
Effect.after effect \result ->
|
Effect.after effect \result ->
|
||||||
|
@ -32,3 +31,16 @@ map = \effect, transform ->
|
||||||
|
|
||||||
putLine : Str -> Task {} *
|
putLine : Str -> Task {} *
|
||||||
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||||
|
|
||||||
|
getInt : Task I64 []
|
||||||
|
getInt =
|
||||||
|
Effect.after Effect.getInt \{ isError, value, errorCode } ->
|
||||||
|
when isError is
|
||||||
|
True ->
|
||||||
|
when errorCode is
|
||||||
|
# A -> Task.fail InvalidCharacter
|
||||||
|
# B -> Task.fail IOError
|
||||||
|
_ -> Task.succeed -1
|
||||||
|
|
||||||
|
False ->
|
||||||
|
Task.succeed value
|
||||||
|
|
|
@ -4,6 +4,7 @@ const RocStr = str.RocStr;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const expectEqual = testing.expectEqual;
|
const expectEqual = testing.expectEqual;
|
||||||
const expect = testing.expect;
|
const expect = testing.expect;
|
||||||
|
const maxInt = std.math.maxInt;
|
||||||
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
@ -96,3 +97,39 @@ pub export fn roc_fx_putLine(rocPath: str.RocStr) i64 {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetInt = extern struct {
|
||||||
|
value: i64,
|
||||||
|
error_code: u8,
|
||||||
|
is_error: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub export fn roc_fx_getInt() GetInt {
|
||||||
|
if (roc_fx_getInt_help()) |value| {
|
||||||
|
const get_int = GetInt{ .is_error = false, .value = value, .error_code = 0 };
|
||||||
|
return get_int;
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.InvalidCharacter => {
|
||||||
|
return GetInt{ .is_error = true, .value = 0, .error_code = 0 };
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
return GetInt{ .is_error = true, .value = 0, .error_code = 1 };
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roc_fx_getInt_help() !i64 {
|
||||||
|
const stdin = std.io.getStdIn().inStream();
|
||||||
|
var buf: [40]u8 = undefined;
|
||||||
|
|
||||||
|
const line: []u8 = (try stdin.readUntilDelimiterOrEof(&buf, '\n')) orelse "";
|
||||||
|
|
||||||
|
return std.fmt.parseInt(i64, line, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readLine() []u8 {
|
||||||
|
const stdin = std.io.getStdIn().reader();
|
||||||
|
return (stdin.readUntilDelimiterOrEof(&line_buf, '\n') catch unreachable) orelse "";
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue