use koto_bytecode::{Chunk, CompilerSettings, ModuleLoader};
use koto_runtime::Ptr;
use koto_test_utils::OutputCapture;
mod vm {
use super::*;
fn check_logged_output(script: &str, expected_output: &str) {
let (mut vm, output) = OutputCapture::make_vm_with_output_capture();
let print_chunk = |script: &str, chunk: Ptr<Chunk>| {
println!("{script}\n");
let script_lines = script.lines().collect::<Vec<_>>();
println!("Constants\n---------\n{}\n", chunk.constants);
println!(
"Instructions\n------------\n{}",
Chunk::instructions_as_string(chunk, &script_lines)
);
};
let mut loader = ModuleLoader::default();
let chunk = match loader.compile_script(script, None, CompilerSettings::default()) {
Ok(chunk) => chunk,
Err(error) => {
print_chunk(script, vm.chunk());
panic!("Error while compiling script: {error}");
}
};
match vm.run(chunk) {
Ok(_) => {
assert_eq!(output.captured_output().as_str(), expected_output);
}
Err(e) => {
print_chunk(script, vm.chunk());
panic!("Error while running script: {e}");
}
}
}
#[test]
fn print_loop() {
let script = "
for i in 0..5
print 'foo {i}'
";
check_logged_output(
script,
"\
foo 0
foo 1
foo 2
foo 3
foo 4
",
);
}
#[test]
fn print_value_with_overridden_display() {
let script = "
foo =
@display: || 'Hello from @display'
@type: 'Foo'
print foo
";
check_logged_output(
script,
"\
Hello from @display
",
);
}
#[test]
fn debug() {
let script = "debug 2 + 2";
check_logged_output(script, "[1] 2 + 2: 4\n");
}
#[test]
fn debug_map_no_type() {
let script = "
foo = {}
debug foo
";
check_logged_output(script, "[3] foo: {}\n");
}
#[test]
fn debug_map_with_meta_no_type() {
let script = "
foo =
@meta bar: 'Foo'
debug foo
";
check_logged_output(script, "[4] foo: {}\n");
}
#[test]
fn debug_with_type() {
let script = "
foo =
@type: 'Foo'
debug foo
";
check_logged_output(script, "[4] foo: Foo {}\n");
}
#[test]
fn debug_with_overridden_display() {
let script = "
foo =
@type: 'Foo'
@display: || 'Display Foo'
debug foo
";
check_logged_output(script, "[5] foo: Display Foo\n");
}
#[test]
fn debug_with_overridden_debug() {
let script = "
foo =
@type: 'Foo'
@debug: || 'Debug Foo'
debug foo
";
check_logged_output(script, "[5] foo: Debug Foo\n");
}
#[test]
fn write_via_stdout() {
let script = "
stdout = io.stdout()
stdout.write 'abc'
stdout.write 'def'
stdout.write_line 'ghi'
";
check_logged_output(script, "abcdefghi\n");
}
#[test]
fn write_via_stderr() {
let script = "
stderr = io.stderr()
stderr.write '123'
stderr.write '456'
stderr.write_line '789'
";
check_logged_output(script, "123456789\n");
}
}