hara-native 0.1.13

HAL-free native host runtime and package launcher for Hara
Documentation
use super::*;
use crate::vm::{compile_source, disassemble, execute_program};

#[test]
fn programs_round_trip_and_execute() {
    let source = "(do (defn add-one [x] (+ x 1)) (add-one 41))";
    let mut program = compile_source(source).unwrap();
    program.namespace = Some("demo".into());
    program.schema_types.insert(
        "demo/Customer".into(),
        SchemaType::Map(vec![SchemaField {
            name: crate::kernel::parse(":id").unwrap(),
            properties: None,
            value_type: SchemaType::Primitive("int".into()),
        }]),
    );
    program.schema_types.insert(
        "demo/Labels".into(),
        SchemaType::Set(Box::new(SchemaType::Primitive("keyword".into()))),
    );
    program.schema_types.insert(
        "demo/Handle".into(),
        SchemaType::WithProperties {
            schema: Box::new(SchemaType::Primitive("str".into())),
            properties: crate::kernel::parse("{:title \"Display handle\" :version 2 :owner :accounts :min-count 1 :max-count 32}").unwrap(),
        },
    );
    program.schema_types.insert(
        "demo/Profile".into(),
        SchemaType::WithProperties {
            schema: Box::new(SchemaType::Map(vec![SchemaField {
                name: crate::kernel::parse(":nickname").unwrap(),
                properties: Some(
                    crate::kernel::parse(
                        "{:required true :description \"Display nickname\" :default \"Anonymous\"}",
                    )
                    .unwrap(),
                ),
                value_type: SchemaType::Primitive("str".into()),
            }])),
            properties: crate::kernel::parse(
                "{:title \"User profile\" :version 2 :owner :accounts :closed true}",
            )
            .unwrap(),
        },
    );
    program.function_types.insert(
        "demo/add-one".into(),
        SchemaType::Function(vec![FunctionSchema {
            fixed: vec![SchemaType::Primitive("int".into())],
            rest: None,
            output: Box::new(SchemaType::Primitive("int".into())),
        }]),
    );
    program.inferred_function_types.insert(
        "demo/inferred".into(),
        SchemaType::Function(vec![FunctionSchema {
            fixed: vec![],
            rest: None,
            output: Box::new(SchemaType::Primitive("int".into())),
        }]),
    );
    let encoded = encode_program(&program).unwrap();
    assert!(encoded.starts_with(b"HBC0"));
    let decoded = decode_program(&encoded).unwrap();
    assert_eq!(encode_program(&decoded).unwrap(), encoded);
    assert_eq!(disassemble(&decoded), disassemble(&program));
    assert_eq!(decoded.schema_types, program.schema_types);
    assert_eq!(decoded.function_types, program.function_types);
    assert_eq!(
        decoded.inferred_function_types,
        program.inferred_function_types
    );
    assert_eq!(decoded.namespace, program.namespace);
    assert_eq!(
        execute_program(Rc::new(decoded)).unwrap(),
        Value::Number(42)
    );
}

#[test]
fn corruption_is_rejected_before_decode() {
    let program = compile_source("(+ 19 23)").unwrap();
    let mut encoded = encode_program(&program).unwrap();
    encoded[12] ^= 1;
    assert_eq!(
        decode_program(&encoded).unwrap_err(),
        "bytecode artifact checksum mismatch"
    );
}

#[test]
fn metadata_integer_widths_are_canonicalized() {
    let mut program = compile_source("(+ 1 2)").unwrap();
    program.var_metadata = vec![Metadata::new(vec![
        (
            MetadataValue::Keyword(Keyword::from("small")),
            MetadataValue::BigInteger(BigInt::from(42)),
        ),
        (
            MetadataValue::Keyword(Keyword::from("large")),
            MetadataValue::BigInteger(BigInt::from(1_u8) << 63),
        ),
    ])];

    let encoded = encode_program(&program).unwrap();
    let decoded = decode_program(&encoded).unwrap();
    assert_eq!(
        decoded.var_metadata[0].get_keyword("small"),
        Some(&MetadataValue::Number(42))
    );
    assert_eq!(
        decoded.var_metadata[0].get_keyword("large"),
        Some(&MetadataValue::BigInteger(BigInt::from(1_u8) << 63))
    );
    assert_eq!(encode_program(&decoded).unwrap(), encoded);
}

#[test]
fn integer_constants_use_canonical_hta_widths() {
    let mut program = compile_source("42").unwrap();
    assert_eq!(program.constants.len(), 1);
    program.constants[0] = Value::BigInteger(BigInt::from(42));

    let encoded = encode_program(&program).unwrap();
    let decoded = decode_program(&encoded).unwrap();
    assert_eq!(decoded.constants, vec![Value::Number(42)]);
    assert_eq!(encode_program(&decoded).unwrap(), encoded);
}