447 lines
23 KiB
Rust
447 lines
23 KiB
Rust
mod support;
|
|
|
|
use support::{checked, run, sources, stdout};
|
|
|
|
#[test]
|
|
fn typed_core_compiles_to_native_values_with_named_outputs() {
|
|
let output = stdout(include_str!(
|
|
"../../../examples/old/dever/core/module/main.dever"
|
|
));
|
|
assert_eq!(
|
|
output,
|
|
concat!(
|
|
"original = 1\nchanged = 99\nchoice = 7\ncategory = large\nexact = true\n",
|
|
"quotient = 2.5\nthird = 0.3333333333333333333333333333333333\nrounded = 2.34\n",
|
|
"integer_division = -2\nremainder = -1\nselected = [3, 6]\nfound = 3\ntotal = 18\n",
|
|
"empty_total = 0\nnames = ABCabc\nordered_keys = [second, first]\nmaps_equal = false\n",
|
|
"nan_equal = false\nfinite = true\noptionals = [null, 1, null]\nkey_value = 2\nidentity = true\n",
|
|
)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn source_field_order_actions_and_short_circuiting_are_preserved() {
|
|
let output = stdout(
|
|
r#"type Pair {
|
|
first: Int
|
|
second: Int
|
|
}
|
|
mark(label: Text, value: Int) (answer: Int) {
|
|
dever.io.println(label)
|
|
answer = value
|
|
}
|
|
probe(value: Int) (answer: Bool) {
|
|
dever.io.println("probe")
|
|
answer = value == 2
|
|
}
|
|
show(value: Int) () {
|
|
dever.io.println("each")
|
|
}
|
|
public main() (answer: Int?, first_value: Int?, short: Bool, pair_value: Int) {
|
|
pair = Pair {
|
|
second = mark("second", 2)
|
|
first = mark("first", 1)
|
|
}
|
|
pair_value = pair.first + pair.second
|
|
each(show, [1, 2])
|
|
answer = find(probe, [1, 2, 3])
|
|
short = false and probe(10) or true
|
|
first_value = first([])
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"second\nfirst\neach\neach\nprobe\nprobe\nanswer = 2\nfirst_value = null\nshort = true\npair_value = 3\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn nullable_variants_bind_payloads_and_optional_results_flatten() {
|
|
let output = stdout(
|
|
r#"type Result {
|
|
Found(value: Int)
|
|
Missing
|
|
}
|
|
choose(value: Result.Found(payload)) (answer: Int) { answer = payload }
|
|
choose(value: Result.Missing) (answer: Int) { answer = -1 }
|
|
choose(value: null) (answer: Int) { answer = -2 }
|
|
present(value: Int) (answer: Bool) { answer = true }
|
|
present(value: null) (answer: Bool) { answer = false }
|
|
select(values: List<Int?>) (answer: Int?) { answer = first(values) }
|
|
public main() (payload: Int, missing: Int, absent: Int, first_value: Int?, found: Int?, label: Int?) {
|
|
payload = choose(Result.Found(7))
|
|
missing = choose(Result.Missing)
|
|
absent = choose(null)
|
|
first_value = select([null, 1])
|
|
found = find(present, [null, 1, 2])
|
|
labels = { "first" = optional(4) }
|
|
label = get(labels, "first")
|
|
}
|
|
optional(value: Int) (answer: Int?) { answer = value }
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"payload = 7\nmissing = -1\nabsent = -2\nfirst_value = null\nfound = 1\nlabel = 4\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn dynamic_numeric_faults_retain_the_original_source_location() {
|
|
for (function, arguments, message) in [
|
|
(
|
|
"divide(left: Int, right: Int) (answer: Int) { answer = left // right }",
|
|
"1, 0",
|
|
"Int division by zero",
|
|
),
|
|
(
|
|
"divide(left: Decimal, right: Decimal) (answer: Decimal) { answer = left / right }",
|
|
"1.0, 0.0",
|
|
"Decimal division by zero",
|
|
),
|
|
(
|
|
"divide(left: Int, right: Int) (answer: Int) { answer = left + right }",
|
|
"9223372036854775807, 1",
|
|
"Int overflow",
|
|
),
|
|
] {
|
|
let output = run(&format!(
|
|
"{function}\npublic main() () {{ answer = divide({arguments}) }}"
|
|
));
|
|
assert!(!output.status.success());
|
|
let error = String::from_utf8(output.stderr).unwrap();
|
|
assert!(error.contains("main.dever:2:"), "{error}");
|
|
assert!(error.contains(message), "{error}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn standard_bytes_are_normal_choice_results_and_not_dynamic_values() {
|
|
let output = stdout(
|
|
r#"decode(result: dever.bytes.DecodeResult.Decoded(text)) (answer: Text) recover("test observes decode failures in its assertions") { answer = text }
|
|
decode(result: dever.bytes.DecodeResult.Failed(message)) (answer: Text) recover("test observes decode failures in its assertions") { answer = "invalid" }
|
|
buffer(result: dever.bytes.BufferResult.Ready(bytes)) (answer: Bytes) recover("test observes buffer failures in its assertions") { answer = bytes }
|
|
buffer(result: dever.bytes.BufferResult.Failed(message)) (answer: Bytes) recover("test observes buffer failures in its assertions") { answer = dever.bytes.from_text(message) }
|
|
public main() (decoded: Text, invalid: Text, count: Int, byte: Int?, outside: Int?) {
|
|
original = dever.bytes.from_text("abc")
|
|
combined = dever.bytes.concat(original, dever.bytes.from_text("def"))
|
|
sliced = buffer(result(dever.bytes.slice(combined, 1, 4)))
|
|
decoded = decode(result(dever.bytes.to_text(sliced)))
|
|
invalid = decode(result(dever.bytes.to_text(buffer(result(dever.bytes.from_ints([255]))))))
|
|
count = dever.bytes.length(original)
|
|
byte = dever.bytes.at(original, 1)
|
|
outside = dever.bytes.at(original, -1)
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"decoded = bcd\ninvalid = invalid\ncount = 3\nbyte = 98\noutside = null\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn official_file_source_compiles_with_explicit_resource_results() {
|
|
let directory = support::temp::TemporaryDirectory::new();
|
|
let path = directory.path().join("native.txt");
|
|
let functions = r#"
|
|
created(result: dever.io.OpenResult.Opened(file), path: Text) (answer: Bool) recover("test observes created failures in its assertions") {
|
|
alias = file
|
|
written = write_ok(result(dever.io.write(file, dever.bytes.from_text("hello"))))
|
|
closed = close_ok(result(dever.io.close(file)))
|
|
rejected = write_failed(result(dever.io.write(alias, dever.bytes.from_text("bad"))))
|
|
content = opened(result(dever.io.open(path)))
|
|
answer = written and closed and rejected and content
|
|
}
|
|
created(result: dever.io.OpenResult.Failed(message), path: Text) (answer: Bool) recover("test observes created failures in its assertions") { answer = false }
|
|
opened(result: dever.io.OpenResult.Opened(file)) (answer: Bool) recover("test observes opened failures in its assertions") {
|
|
read = read_ok(result(dever.io.read(file, 64)))
|
|
closed = close_ok(result(dever.io.close(file)))
|
|
answer = read and closed
|
|
}
|
|
opened(result: dever.io.OpenResult.Failed(message)) (answer: Bool) recover("test observes opened failures in its assertions") { answer = false }
|
|
read_ok(result: dever.io.ReadResult.Done(state)) (answer: Bool) recover("test observes read_ok failures in its assertions") { answer = read_state_ok(state) }
|
|
read_ok(result: other) (answer: Bool) recover("test observes read_ok failures in its assertions") { answer = false }
|
|
read_state_ok(state: dever.io.ReadState.Read(bytes)) (answer: Bool) { answer = decode_ok(result(dever.bytes.to_text(bytes))) }
|
|
read_state_ok(state: other) (answer: Bool) { answer = false }
|
|
decode_ok(result: dever.bytes.DecodeResult.Decoded(text)) (answer: Bool) recover("test observes decode_ok failures in its assertions") { answer = text == "hello" }
|
|
decode_ok(result: other) (answer: Bool) recover("test observes decode_ok failures in its assertions") { answer = false }
|
|
write_ok(result: dever.io.WriteResult.Done) (answer: Bool) recover("test observes write_ok failures in its assertions") { answer = true }
|
|
write_ok(result: other) (answer: Bool) recover("test observes write_ok failures in its assertions") { answer = false }
|
|
write_failed(result: dever.io.WriteResult.Failed(message)) (answer: Bool) recover("test observes write_failed failures in its assertions") { answer = true }
|
|
write_failed(result: other) (answer: Bool) recover("test observes write_failed failures in its assertions") { answer = false }
|
|
close_ok(result: dever.io.CloseResult.Closed) (answer: Bool) recover("test observes close_ok failures in its assertions") { answer = true }
|
|
close_ok(result: other) (answer: Bool) recover("test observes close_ok failures in its assertions") { answer = false }
|
|
"#;
|
|
let source = format!(
|
|
"public main() (result: Bool) {{ result = created(result(dever.io.create({path:?})), {path:?}) }}\n{functions}",
|
|
path = path.to_str().unwrap()
|
|
);
|
|
assert_eq!(stdout(&source), "result = true\n");
|
|
assert_eq!(std::fs::read_to_string(path).unwrap(), "hello");
|
|
}
|
|
|
|
#[test]
|
|
fn official_tcp_source_runs_a_single_local_connection_and_closes_it() {
|
|
let output = stdout(
|
|
r#"public main() (result: Bool) { result = listening(result(dever.net.listen("127.0.0.1", 0))) }
|
|
listening(result: dever.net.ListenResult.Listening(listener)) (answer: Bool) recover("test observes listening failures in its assertions") {
|
|
answer = bound(result(dever.net.port(listener)), listener)
|
|
}
|
|
listening(result: other) (answer: Bool) recover("test observes listening failures in its assertions") { answer = false }
|
|
bound(result: dever.net.PortResult.Bound(port), listener: dever.system.Listener) (answer: Bool) recover("test observes bound failures in its assertions") {
|
|
answer = connected(result(dever.net.connect("127.0.0.1", port)), listener)
|
|
}
|
|
bound(result: other, listener: dever.system.Listener) (answer: Bool) recover("test observes bound failures in its assertions") { answer = false }
|
|
connected(result: dever.net.ConnectResult.Connected(client), listener: dever.system.Listener) (answer: Bool) recover("test observes connected failures in its assertions") {
|
|
answer = accepted(result(dever.net.accept(listener)), client, listener)
|
|
}
|
|
connected(result: other, listener: dever.system.Listener) (answer: Bool) recover("test observes connected failures in its assertions") { answer = false }
|
|
accepted(result: dever.net.ConnectResult.Connected(server), client: dever.system.Socket, listener: dever.system.Listener) (answer: Bool) recover("test observes accepted failures in its assertions") {
|
|
client_timeout = write_ok(result(dever.net.timeout(client, 1000)))
|
|
server_timeout = write_ok(result(dever.net.timeout(server, 1000)))
|
|
written = write_ok(result(dever.net.write(client, dever.bytes.from_text("x"))))
|
|
received = read_ok(result(dever.net.read(server, 1)))
|
|
client_closed = close_ok(result(dever.net.close(client)))
|
|
server_closed = close_ok(result(dever.net.close(server)))
|
|
listener_closed = close_ok(result(dever.net.close_listener(listener)))
|
|
answer = client_timeout and server_timeout and written and received and client_closed and server_closed and listener_closed
|
|
}
|
|
accepted(result: other, client: dever.system.Socket, listener: dever.system.Listener) (answer: Bool) recover("test observes accepted failures in its assertions") { answer = false }
|
|
write_ok(result: dever.io.WriteResult.Done) (answer: Bool) recover("test observes write_ok failures in its assertions") { answer = true }
|
|
write_ok(result: other) (answer: Bool) recover("test observes write_ok failures in its assertions") { answer = false }
|
|
close_ok(result: dever.io.CloseResult.Closed) (answer: Bool) recover("test observes close_ok failures in its assertions") { answer = true }
|
|
close_ok(result: other) (answer: Bool) recover("test observes close_ok failures in its assertions") { answer = false }
|
|
read_ok(result: dever.io.ReadResult.Done(state)) (answer: Bool) recover("test observes read_ok failures in its assertions") { answer = read_state_ok(state) }
|
|
read_ok(result: other) (answer: Bool) recover("test observes read_ok failures in its assertions") { answer = false }
|
|
read_state_ok(state: dever.io.ReadState.Read(bytes)) (answer: Bool) { answer = bytes == dever.bytes.from_text("x") }
|
|
read_state_ok(state: other) (answer: Bool) { answer = false }
|
|
"#,
|
|
);
|
|
assert_eq!(output, "result = true\n");
|
|
}
|
|
|
|
#[test]
|
|
fn grouping_and_null_only_collections_do_not_change_semantics() {
|
|
let output = stdout(
|
|
r#"same(value: Int?) (answer: Bool) { answer = (null) == value and value == ((null)) }
|
|
public main() (size: Int, equal: Bool, first_value: Int?, mapped: List<Text>, appended: List<Int>, found: Int?) {
|
|
values = [(null), 1]
|
|
size = length(values)
|
|
equal = same(null)
|
|
first_value = first([null])
|
|
mapped = each((text.trim), [" a ", " b "])
|
|
appended = append(([]), 1)
|
|
labels = put(({}), "a", 2)
|
|
found = get(labels, "a")
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"size = 2\nequal = true\nfirst_value = null\nmapped = [a, b]\nappended = [1]\nfound = 2\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn float_patterns_preserve_signed_zero_and_literal_context_is_symmetric() {
|
|
let output = stdout(
|
|
r#"sign(value: 0.0e0) (answer: Float) { answer = 1.0e0 / value }
|
|
sign(value: other) (answer: Float) { answer = 0.0e0 }
|
|
compare(value: Float) (answer: Bool) { answer = value < 0.0 and 0.0 > value and value == (-1.0) }
|
|
public main() (negative: Bool, comparison: Bool, ordered_sum: Float) {
|
|
negative = sign(-0.0e0) < 0.0
|
|
comparison = compare(-1.0e0)
|
|
ordered_sum = sum([1.0e16, 1.0e0, -1.0e16])
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"negative = true\ncomparison = true\nordered_sum = 0\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn reduce_bytes_and_forwarded_handlers_are_direct_native_operations() {
|
|
let output = stdout(
|
|
r#"add(value: Int, total: Int) (next: Int) { next = total + value }
|
|
until(value: Int, total: Int) (next: Int, stop: Bool) { next = total + value
|
|
stop = value == 2 }
|
|
increment(value: Int) (answer: Int) { answer = value + 1 }
|
|
apply(route: handler(value: Int) (answer: Int), value: Int) (answer: Int) { answer = route(value) }
|
|
forward(route: handler(value: Int) (answer: Int), value: Int) (answer: Int) { answer = apply(route, value) }
|
|
public main() (list_total: Int, empty_total: Int, stopped: Int, bytes_total: Int, mapped: List<Int>, forwarded: Int) {
|
|
list_total = reduce(add, [1, 2, 3], 0)
|
|
empty_total = reduce(add, [], 7)
|
|
stopped = reduce_until(until, [1, 2, 100], 0)
|
|
bytes = dever.bytes.from_text("ABC")
|
|
bytes_total = reduce(add, bytes, 0)
|
|
mapped = each(increment, bytes)
|
|
forwarded = forward(increment, 4)
|
|
}
|
|
"#,
|
|
);
|
|
assert_eq!(
|
|
output,
|
|
"list_total = 6\nempty_total = 7\nstopped = 3\nbytes_total = 198\nmapped = [66, 67, 68]\nforwarded = 5\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn handler_codegen_emits_concrete_specializations_without_function_values() {
|
|
let sources = sources(
|
|
r#"increment(value: Int) (answer: Int) { answer = value + 1 }
|
|
decrement(value: Int) (answer: Int) { answer = value - 1 }
|
|
apply(route: handler(value: Int) (answer: Int), value: Int) (answer: Int) { answer = route(value) }
|
|
public main() (up: Int, down: Int) { up = apply(increment, 1)
|
|
down = apply(decrement, 1) }
|
|
"#,
|
|
);
|
|
let generated = dever_core::native::emit(&checked(&sources), &sources, "main.main").unwrap();
|
|
assert_eq!(
|
|
generated
|
|
.lines()
|
|
.filter(|line| line.starts_with("fn f") && line.contains('h'))
|
|
.count(),
|
|
2
|
|
);
|
|
assert!(!generated.contains("dyn Fn"));
|
|
assert!(!generated.contains("fn("));
|
|
}
|
|
|
|
#[test]
|
|
fn bytes_reduce_codegen_iterates_bytes_without_materializing_a_list() {
|
|
let sources = sources(
|
|
r#"add(value: Int, total: Int) (next: Int) { next = total + value }
|
|
public main() (answer: Int) {
|
|
bytes = dever.bytes.from_text("ABC")
|
|
answer = reduce(add, bytes, 0)
|
|
}
|
|
"#,
|
|
);
|
|
let generated = dever_core::native::emit(&checked(&sources), &sources, "main.main").unwrap();
|
|
assert!(generated.contains("for element in a0.values()"));
|
|
assert!(generated.contains("i64::from(*element)"));
|
|
assert!(!generated.contains("List::<i64>::new"));
|
|
}
|
|
|
|
#[test]
|
|
fn official_file_chunks_stop_and_resume_the_same_stream_alias() {
|
|
let directory = support::temp::TemporaryDirectory::new();
|
|
let path = directory.path().join("chunks.txt");
|
|
std::fs::write(&path, "abcdef").unwrap();
|
|
let source = format!(
|
|
r#"decode(result: dever.bytes.DecodeResult.Decoded(text), state: Text) (next: Text) recover("test observes decode failures in its assertions") {{ next = state + text }}
|
|
decode(result: dever.bytes.DecodeResult.Failed(message), state: Text) (next: Text) recover("test observes decode failures in its assertions") {{ next = state }}
|
|
collect(event: dever.io.ReadEvent.Chunk(bytes), state: Text) (next: Text) recover("test observes collect failures in its assertions") {{ next = decode(result(dever.bytes.to_text(bytes)), state) }}
|
|
collect(event: dever.io.ReadEvent.Failed(message), state: Text) (next: Text) recover("test observes collect failures in its assertions") {{ next = state }}
|
|
first(event: dever.io.ReadEvent.Chunk(bytes), state: Text) (next: Text, stop: Bool) recover("test observes first failures in its assertions") {{ next = decode(result(dever.bytes.to_text(bytes)), state)
|
|
stop = true }}
|
|
first(event: dever.io.ReadEvent.Failed(message), state: Text) (next: Text, stop: Bool) recover("test observes first failures in its assertions") {{ next = state
|
|
stop = true }}
|
|
streaming(result: dever.io.ReadStreamResult.Streaming(stream)) (answer: Text) recover("test observes streaming failures in its assertions") {{ alias = stream
|
|
prefix = reduce_until(first, stream, "")
|
|
answer = reduce(collect, alias, prefix)
|
|
close(stream) }}
|
|
streaming(result: dever.io.ReadStreamResult.Failed(message)) (answer: Text) recover("test observes streaming failures in its assertions") {{ answer = message }}
|
|
opened(result: dever.io.OpenResult.Opened(file)) (answer: Text) recover("test observes opened failures in its assertions") {{ answer = streaming(result(dever.io.chunks(file, 2))) }}
|
|
opened(result: dever.io.OpenResult.Failed(message)) (answer: Text) recover("test observes opened failures in its assertions") {{ answer = message }}
|
|
public main() (answer: Text) {{ answer = opened(result(dever.io.open({path:?}))) }}
|
|
"#,
|
|
path = path.to_str().unwrap()
|
|
);
|
|
assert_eq!(stdout(&source), "answer = abcdef\n");
|
|
}
|
|
|
|
#[test]
|
|
fn official_file_chunks_report_creation_failures_without_a_stream() {
|
|
let directory = support::temp::TemporaryDirectory::new();
|
|
let path = directory.path().join("creation-failure.txt");
|
|
std::fs::write(&path, "x").unwrap();
|
|
let source = format!(
|
|
r#"failed(result: dever.io.ReadStreamResult.Streaming(stream)) (answer: Bool) recover("test observes failed failures in its assertions") {{ close(stream)
|
|
answer = false }}
|
|
failed(result: dever.io.ReadStreamResult.Failed(message)) (answer: Bool) recover("test observes failed failures in its assertions") {{ answer = true }}
|
|
opened(result: dever.io.OpenResult.Opened(file)) (invalid: Bool, closed: Bool) recover("test observes opened failures in its assertions") {{
|
|
invalid = failed(result(dever.io.chunks(file, 0)))
|
|
dever.io.close(file)
|
|
closed = failed(result(dever.io.chunks(file, 1)))
|
|
}}
|
|
opened(result: dever.io.OpenResult.Failed(message)) (invalid: Bool, closed: Bool) recover("test observes opened failures in its assertions") {{ invalid = false
|
|
closed = false }}
|
|
public main() (invalid: Bool, closed: Bool) {{ result = opened(result(dever.io.open({path:?})))
|
|
invalid = result.invalid
|
|
closed = result.closed }}
|
|
"#,
|
|
path = path.to_str().unwrap()
|
|
);
|
|
assert_eq!(stdout(&source), "invalid = true\nclosed = true\n");
|
|
}
|
|
|
|
#[test]
|
|
fn official_loopback_connections_and_socket_chunks_are_streamed() {
|
|
let output = stdout(
|
|
r#"type State {
|
|
client: dever.system.Socket
|
|
text: Text
|
|
}
|
|
decode(result: dever.bytes.DecodeResult.Decoded(text), state: State) (next: State) recover("test observes decode failures in its assertions") { next = State { client = state.client
|
|
text = state.text + text } }
|
|
decode(result: dever.bytes.DecodeResult.Failed(message), state: State) (next: State) recover("test observes decode failures in its assertions") { next = state }
|
|
collect(event: dever.io.ReadEvent.Chunk(bytes), state: State) (next: State) recover("test observes collect failures in its assertions") { next = decode(result(dever.bytes.to_text(bytes)), state) }
|
|
collect(event: dever.io.ReadEvent.Failed(message), state: State) (next: State) recover("test observes collect failures in its assertions") { next = state }
|
|
reading(result: dever.net.ReadStreamResult.Streaming(stream), state: State) (next: State) recover("test observes reading failures in its assertions") { next = reduce(collect, stream, state) }
|
|
reading(result: dever.net.ReadStreamResult.Failed(message), state: State) (next: State) recover("test observes reading failures in its assertions") { next = state }
|
|
accepted(result: dever.net.ConnectResult.Connected(server), state: State) (next: State, stop: Bool) recover("test observes accepted failures in its assertions") {
|
|
dever.net.timeout(state.client, 1000)
|
|
dever.net.timeout(server, 1000)
|
|
dever.net.write(state.client, dever.bytes.from_text("xyz"))
|
|
dever.net.close(state.client)
|
|
next = reading(result(dever.net.chunks(server, 2)), state)
|
|
stop = true
|
|
}
|
|
accepted(result: dever.net.ConnectResult.Failed(message), state: State) (next: State, stop: Bool) recover("test observes accepted failures in its assertions") { next = state
|
|
stop = true }
|
|
connected(result: dever.net.ConnectResult.Connected(client), listener: dever.system.Listener) (answer: Text) recover("test observes connected failures in its assertions") {
|
|
stream = dever.net.connections(listener)
|
|
state = State { client = client
|
|
text = "" }
|
|
finished = reduce_until(accepted, stream, state)
|
|
close(stream)
|
|
answer = finished.text
|
|
}
|
|
connected(result: dever.net.ConnectResult.Failed(message), listener: dever.system.Listener) (answer: Text) recover("test observes connected failures in its assertions") { answer = message }
|
|
bound(result: dever.net.PortResult.Bound(port), listener: dever.system.Listener) (answer: Text) recover("test observes bound failures in its assertions") { answer = connected(result(dever.net.connect("127.0.0.1", port)), listener) }
|
|
bound(result: dever.net.PortResult.Failed(message), listener: dever.system.Listener) (answer: Text) recover("test observes bound failures in its assertions") { answer = message }
|
|
listening(result: dever.net.ListenResult.Listening(listener)) (answer: Text) recover("test observes listening failures in its assertions") { answer = bound(result(dever.net.port(listener)), listener) }
|
|
listening(result: dever.net.ListenResult.Failed(message)) (answer: Text) recover("test observes listening failures in its assertions") { answer = message }
|
|
public main() (answer: Text) { answer = listening(result(dever.net.listen("127.0.0.1", 0))) }
|
|
"#,
|
|
);
|
|
assert_eq!(output, "answer = xyz\n");
|
|
}
|
|
|
|
#[test]
|
|
fn each_consumes_a_stream_only_for_zero_output_actions() {
|
|
let directory = support::temp::TemporaryDirectory::new();
|
|
let path = directory.path().join("each.txt");
|
|
std::fs::write(&path, "abcd").unwrap();
|
|
let source = format!(
|
|
r#"print(result: dever.bytes.DecodeResult.Decoded(text)) () recover("test observes print failures in its assertions") {{ dever.io.println(text) }}
|
|
print(result: dever.bytes.DecodeResult.Failed(message)) () recover("test observes print failures in its assertions") {{ dever.io.println("failed") }}
|
|
show(event: dever.io.ReadEvent.Chunk(bytes)) () recover("test observes show failures in its assertions") {{ print(result(dever.bytes.to_text(bytes))) }}
|
|
show(event: dever.io.ReadEvent.Failed(message)) () recover("test observes show failures in its assertions") {{ dever.io.println("failed") }}
|
|
streaming(result: dever.io.ReadStreamResult.Streaming(stream)) (answer: Bool) recover("test observes streaming failures in its assertions") {{ each(show, stream)
|
|
answer = true }}
|
|
streaming(result: dever.io.ReadStreamResult.Failed(message)) (answer: Bool) recover("test observes streaming failures in its assertions") {{ answer = false }}
|
|
opened(result: dever.io.OpenResult.Opened(file)) (answer: Bool) recover("test observes opened failures in its assertions") {{ answer = streaming(result(dever.io.chunks(file, 2))) }}
|
|
opened(result: dever.io.OpenResult.Failed(message)) (answer: Bool) recover("test observes opened failures in its assertions") {{ answer = false }}
|
|
public main() (answer: Bool) {{ answer = opened(result(dever.io.open({path:?}))) }}
|
|
"#,
|
|
path = path.to_str().unwrap()
|
|
);
|
|
assert_eq!(stdout(&source), "ab\ncd\nanswer = true\n");
|
|
}
|