This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_vm/tests/template_tests.rs
T
2026-06-14 12:58:09 +08:00

109 lines
3.3 KiB
Rust

use oxide_compiler::compiler::Compiler;
use oxide_parser::Allocator;
use oxide_types::value::JsValue;
use oxide_vm::vm::Vm;
fn eval(source: &str) -> String {
let allocator = Allocator::default();
let program = match oxide_parser::parse(&allocator, source) {
Ok(p) => p,
Err(e) => return format!("parse error: {}", e[0].message),
};
let module = match Compiler::new().compile(&program) {
Ok(m) => m,
Err(e) => return format!("compile error: {}", e),
};
let mut vm = Vm::new();
match vm.run(&module) {
Ok(result) => format!("{}", result),
Err(e) => format!("vm error: {}", e),
}
}
fn eval_val(source: &str) -> (Vm, Result<JsValue, String>) {
let allocator = Allocator::default();
let program = match oxide_parser::parse(&allocator, source) {
Ok(p) => p,
Err(e) => return (Vm::new(), Err(format!("parse error: {}", e[0].message))),
};
let module = match Compiler::new().compile(&program) {
Ok(m) => m,
Err(e) => return (Vm::new(), Err(format!("compile error: {}", e))),
};
let mut vm = Vm::new();
let result = vm.run(&module);
(vm, result)
}
fn to_str(vm: &Vm, val: JsValue) -> String {
if val.is_string() {
vm.kernel_core().string_forge().lookup(val.as_string_index()).unwrap_or_default()
} else {
format!("{}", val)
}
}
// -- Template literal tests --
#[test]
fn template_no_expressions() {
let (vm, result) = eval_val("`hello`");
assert_eq!(to_str(&vm, result.unwrap()), "hello");
}
#[test]
fn template_single_expression() {
let (vm, result) = eval_val("const name = 'world'; `hello ${name}`");
assert_eq!(to_str(&vm, result.unwrap()), "hello world");
}
#[test]
fn template_multiple_expressions() {
let (vm, result) = eval_val("`a${1}b${2}c`");
assert_eq!(to_str(&vm, result.unwrap()), "a1b2c");
}
#[test]
fn template_expression_only() {
let (vm, result) = eval_val("const x = 'foo', y = 'bar'; `${x}${y}`");
assert_eq!(to_str(&vm, result.unwrap()), "foobar");
}
#[test]
fn template_empty() {
let (vm, result) = eval_val("``");
assert_eq!(to_str(&vm, result.unwrap()), "");
}
#[test]
fn template_with_numbers() {
let (vm, result) = eval_val("`value is ${42}`");
assert_eq!(to_str(&vm, result.unwrap()), "value is 42");
}
#[test]
fn template_numeric_expression() {
let (vm, result) = eval_val("`${1 + 1}`");
assert_eq!(to_str(&vm, result.unwrap()), "2");
}
// -- Template tagging tests (basic) --
#[test]
fn tagged_template_basic() {
// Use Math.max as a simple native tag function to verify the CALL dispatch works.
// Math.max(cooked_array, raw_array, 42) should return 42 (the max of the args).
// This avoids bytecode function call complexity.
let result = eval("Math.max`hello ${42} world`");
// Math.max on the args should work - just verify it doesn't crash
assert!(!result.starts_with("vm error:"), "Tagged template should not crash, got: {}", result);
}
#[test]
fn tagged_template_compiles_no_error() {
// Verify that tagged templates compile without error (even if the tag
// function behavior isn't fully tested)
let result = eval("function t(s,v){ return s[0]+v; } t`x${1}`");
assert!(!result.starts_with("compile error:"), "Tagged template should compile");
}