121 lines
4.0 KiB
Rust
121 lines
4.0 KiB
Rust
use aster_core::{Value, Vm, VmError};
|
|
|
|
#[test]
|
|
fn bootstrap_is_unique_and_root_has_no_parent() {
|
|
let mut vm = Vm::new().unwrap();
|
|
let root = vm.root_class();
|
|
assert_eq!(vm.bootstrap(), root);
|
|
assert_eq!(vm.bootstrap(), root);
|
|
assert_eq!(vm.object_count(), 1);
|
|
assert_eq!(vm.class(root).unwrap().name(), "Object");
|
|
assert_eq!(vm.class(root).unwrap().parent(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn factories_preserve_class_links_and_distinct_identity() {
|
|
let mut vm = Vm::new().unwrap();
|
|
let root = vm.root_class();
|
|
let class = vm.create_class("Point", root).unwrap();
|
|
let child = vm.create_class("ColoredPoint", class).unwrap();
|
|
let first = vm.create_instance(class).unwrap();
|
|
let second = vm.create_instance(class).unwrap();
|
|
let plain = vm.create_instance(root).unwrap();
|
|
assert_ne!(first, second);
|
|
assert_eq!(vm.class(child).unwrap().parent(), Some(class));
|
|
assert_eq!(vm.instance(first).unwrap().class(), class);
|
|
assert_eq!(vm.instance(plain).unwrap().class(), root);
|
|
vm.set_field(first, "x", Value::Integer(1)).unwrap();
|
|
vm.set_field(first, "next", Value::Object(second.into()))
|
|
.unwrap();
|
|
assert_eq!(
|
|
vm.instance(first).unwrap().field("x"),
|
|
Some(&Value::Integer(1))
|
|
);
|
|
assert_eq!(vm.instance(second).unwrap().field("x"), None);
|
|
assert_eq!(vm.as_class(class.into()).unwrap(), class);
|
|
assert_eq!(vm.as_instance(first.into()).unwrap(), first);
|
|
assert_eq!(vm.as_instance(class.into()), Err(VmError::ExpectedInstance));
|
|
assert_eq!(vm.as_class(first.into()), Err(VmError::ExpectedClass));
|
|
}
|
|
|
|
#[test]
|
|
fn foreign_handles_are_rejected_without_mutation() {
|
|
let mut vm = Vm::new().unwrap();
|
|
let mut other = Vm::new().unwrap();
|
|
let local = vm.create_instance(vm.root_class()).unwrap();
|
|
let foreign = other.create_instance(other.root_class()).unwrap();
|
|
let count = vm.object_count();
|
|
assert_eq!(
|
|
vm.create_class("Alien", other.root_class()),
|
|
Err(VmError::ForeignHandle)
|
|
);
|
|
assert_eq!(
|
|
vm.create_instance(other.root_class()),
|
|
Err(VmError::ForeignHandle)
|
|
);
|
|
assert!(matches!(
|
|
vm.object(foreign.into()),
|
|
Err(VmError::ForeignHandle)
|
|
));
|
|
assert!(matches!(vm.instance(foreign), Err(VmError::ForeignHandle)));
|
|
assert_eq!(
|
|
vm.set_field(foreign, "x", Value::Nil),
|
|
Err(VmError::ForeignHandle)
|
|
);
|
|
vm.set_field(local, "x", Value::Integer(7)).unwrap();
|
|
assert_eq!(
|
|
vm.set_field(local, "x", Value::Object(foreign.into())),
|
|
Err(VmError::ForeignHandle)
|
|
);
|
|
assert_eq!(
|
|
vm.instance(local).unwrap().field("x"),
|
|
Some(&Value::Integer(7))
|
|
);
|
|
assert_eq!(vm.object_count(), count);
|
|
}
|
|
|
|
#[test]
|
|
fn handles_outliving_a_vm_cannot_alias_a_new_vm() {
|
|
let old = {
|
|
let vm = Vm::new().unwrap();
|
|
vm.root_class()
|
|
};
|
|
let vm = Vm::new().unwrap();
|
|
assert_ne!(old, vm.root_class());
|
|
assert!(matches!(vm.class(old), Err(VmError::ForeignHandle)));
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_names_do_not_allocate_and_names_are_not_a_namespace() {
|
|
let mut vm = Vm::new().unwrap();
|
|
assert_eq!(
|
|
vm.create_class(" ", vm.root_class()),
|
|
Err(VmError::EmptyClassName)
|
|
);
|
|
assert_eq!(
|
|
vm.create_class("Object", vm.root_class()),
|
|
Err(VmError::ReservedClassName)
|
|
);
|
|
assert_eq!(vm.object_count(), 1);
|
|
let a = vm.create_class("Label", vm.root_class()).unwrap();
|
|
let b = vm.create_class("Label", vm.root_class()).unwrap();
|
|
assert_ne!(a, b);
|
|
}
|
|
|
|
#[test]
|
|
fn handles_remain_valid_when_the_arena_grows() {
|
|
let mut vm = Vm::new().unwrap();
|
|
let root = vm.root_class();
|
|
let first = vm.create_instance(root).unwrap();
|
|
vm.set_field(first, "stable", Value::Bool(true)).unwrap();
|
|
for _ in 0..4096 {
|
|
vm.create_instance(root).unwrap();
|
|
}
|
|
assert_eq!(vm.instance(first).unwrap().class(), root);
|
|
assert_eq!(
|
|
vm.instance(first).unwrap().field("stable"),
|
|
Some(&Value::Bool(true))
|
|
);
|
|
assert_eq!(vm.class(root).unwrap().name(), "Object");
|
|
}
|