173 lines
6.0 KiB
Rust
173 lines
6.0 KiB
Rust
use aster_core::{ObjectData, 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(), 2);
|
|
assert_eq!(vm.class(root).unwrap().name(), "Object");
|
|
assert_eq!(vm.class(root).unwrap().parent(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn bootstrap_types_have_headers_and_distinct_inheritance_links() {
|
|
let vm = Vm::new().unwrap();
|
|
let root = vm.root_class();
|
|
let type_class = vm.type_class();
|
|
assert_ne!(root, type_class);
|
|
assert_eq!(vm.class(type_class).unwrap().name(), "Type");
|
|
assert_eq!(vm.class(type_class).unwrap().parent(), Some(root));
|
|
assert_eq!(vm.type_of(root.into()).unwrap(), type_class);
|
|
assert_eq!(vm.type_of(type_class.into()).unwrap(), type_class);
|
|
for class in [root, type_class] {
|
|
let object = vm.object(class.into()).unwrap();
|
|
assert_eq!(object.header().class(), type_class);
|
|
assert!(matches!(object.data(), ObjectData::Class(_)));
|
|
assert_eq!(vm.as_class(class.into()).unwrap(), class);
|
|
assert_eq!(vm.as_instance(class.into()), Err(VmError::ExpectedInstance));
|
|
}
|
|
}
|
|
|
|
#[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.type_of(class.into()).unwrap(), vm.type_class());
|
|
assert_eq!(vm.type_of(child.into()).unwrap(), vm.type_class());
|
|
assert_eq!(vm.type_of(first.into()).unwrap(), class);
|
|
assert_eq!(vm.type_of(plain.into()).unwrap(), root);
|
|
let object = vm.object(first.into()).unwrap();
|
|
assert_eq!(object.header().class(), class);
|
|
assert!(matches!(object.data(), ObjectData::Instance(_)));
|
|
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)));
|
|
for reference in [
|
|
foreign.into(),
|
|
other.root_class().into(),
|
|
other.type_class().into(),
|
|
] {
|
|
assert_eq!(vm.type_of(reference), 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)
|
|
);
|
|
for name in ["Object", "Type"] {
|
|
assert_eq!(
|
|
vm.create_class(name, vm.root_class()),
|
|
Err(VmError::ReservedClassName)
|
|
);
|
|
}
|
|
assert_eq!(vm.object_count(), 2);
|
|
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 type_cannot_be_used_to_bypass_the_class_factory() {
|
|
let mut vm = Vm::new().unwrap();
|
|
let type_class = vm.type_class();
|
|
let count = vm.object_count();
|
|
assert_eq!(
|
|
vm.create_instance(type_class),
|
|
Err(VmError::UnsupportedMetaclass)
|
|
);
|
|
assert_eq!(
|
|
vm.create_class("CustomType", type_class),
|
|
Err(VmError::UnsupportedMetaclass)
|
|
);
|
|
assert_eq!(vm.object_count(), count);
|
|
assert_eq!(vm.type_of(type_class.into()).unwrap(), type_class);
|
|
}
|
|
|
|
#[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.type_of(first.into()).unwrap(), root);
|
|
assert_eq!(vm.type_of(root.into()).unwrap(), vm.type_class());
|
|
assert_eq!(vm.type_of(vm.type_class().into()).unwrap(), vm.type_class());
|
|
assert_eq!(
|
|
vm.instance(first).unwrap().field("stable"),
|
|
Some(&Value::Bool(true))
|
|
);
|
|
assert_eq!(vm.class(root).unwrap().name(), "Object");
|
|
}
|