use aegis_vm::{execute, build_config::opcodes::{stack, string, exec}};
#[test]
fn test_str_new_and_len() {
let bytecode = [
stack::PUSH_IMM8, 100,
string::STR_NEW,
string::STR_LEN,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0, "New string should have length 0");
}
#[test]
fn test_str_push() {
let bytecode = [
stack::PUSH_IMM8, 100,
string::STR_NEW,
stack::DUP,
stack::PUSH_IMM8, 0x48,
string::STR_PUSH,
stack::DUP,
stack::PUSH_IMM8, 0x69,
string::STR_PUSH,
string::STR_LEN,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 2, "String 'Hi' should have length 2");
}
#[test]
fn test_str_get() {
let bytecode = [
stack::PUSH_IMM8, 100,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH, stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH, stack::DUP, stack::PUSH_IMM8, 0x63, string::STR_PUSH,
stack::DUP,
stack::PUSH_IMM8, 1,
string::STR_GET,
stack::SWAP,
stack::DROP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0x62, "str[1] should be 'b' (0x62)");
}
#[test]
fn test_str_set() {
let bytecode = [
stack::PUSH_IMM8, 100,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x63, string::STR_PUSH,
stack::DUP,
stack::PUSH_IMM8, 1,
stack::PUSH_IMM8, 0x58,
string::STR_SET,
stack::DUP,
stack::PUSH_IMM8, 1,
string::STR_GET,
stack::SWAP,
stack::DROP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0x58, "str[1] should be 'X' (0x58) after set");
}
#[test]
fn test_str_eq_equal() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
string::STR_EQ,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 1, "Equal strings should return 1");
}
#[test]
fn test_str_eq_not_equal() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x63, string::STR_PUSH,
string::STR_EQ,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0, "Different strings should return 0");
}
#[test]
fn test_str_eq_different_lengths() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x63, string::STR_PUSH,
string::STR_EQ,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0, "Different length strings should return 0");
}
#[test]
fn test_str_cmp_less() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
string::STR_CMP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, u64::MAX, "\"aa\" < \"ab\" should return -1 (u64::MAX)");
}
#[test]
fn test_str_cmp_greater() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x62, string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, 0x61, string::STR_PUSH,
string::STR_CMP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 1, "\"b\" > \"a\" should return 1");
}
#[test]
fn test_str_cmp_equal() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'e', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b's', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'e', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b's', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
string::STR_CMP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 0, "Equal strings should return 0");
}
#[test]
fn test_str_hash() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'e', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b's', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b't', string::STR_PUSH,
string::STR_HASH,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_ne!(result, 0, "Hash should not be 0");
}
#[test]
fn test_str_hash_consistency() {
let bytecode1 = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'a', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'b', string::STR_PUSH,
string::STR_HASH,
exec::HALT,
];
let bytecode2 = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'a', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'b', string::STR_PUSH,
string::STR_HASH,
exec::HALT,
];
let hash1 = execute(&bytecode1, &[]).unwrap();
let hash2 = execute(&bytecode2, &[]).unwrap();
assert_eq!(hash1, hash2, "Same string should produce same hash");
}
#[test]
fn test_str_concat() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'H', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'e', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'l', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'l', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'o', string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'W', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'o', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'r', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'l', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'd', string::STR_PUSH,
string::STR_CONCAT,
string::STR_LEN,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 10, "\"HelloWorld\" should have length 10");
}
#[test]
fn test_str_concat_content() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'A', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'B', string::STR_PUSH,
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'C', string::STR_PUSH,
stack::DUP, stack::PUSH_IMM8, b'D', string::STR_PUSH,
string::STR_CONCAT,
stack::DUP,
stack::PUSH_IMM8, 2,
string::STR_GET,
stack::SWAP,
stack::DROP,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, b'C' as u64, "\"ABCD\"[2] should be 'C'");
}
#[test]
fn test_empty_string() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::PUSH_IMM8, 10,
string::STR_NEW,
string::STR_EQ,
exec::HALT,
];
let result = execute(&bytecode, &[]).unwrap();
assert_eq!(result, 1, "Empty strings should be equal");
}
#[test]
fn test_str_bounds_check() {
let bytecode = [
stack::PUSH_IMM8, 10,
string::STR_NEW,
stack::DUP, stack::PUSH_IMM8, b'a', string::STR_PUSH,
stack::PUSH_IMM8, 5,
string::STR_GET,
exec::HALT,
];
let result = execute(&bytecode, &[]);
assert!(result.is_err(), "Accessing out of bounds should error");
}