#![allow(clippy::approx_constant)]
use fusevm::{Op, Value};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
fn h(v: &Value) -> u64 {
let mut s = DefaultHasher::new();
v.hash(&mut s);
s.finish()
}
#[test]
fn int_and_float_with_same_numeric_value_hash_differently() {
assert_ne!(h(&Value::int(1)), h(&Value::float(1.0)));
}
#[test]
fn int_zero_and_bool_false_hash_differently() {
assert_ne!(h(&Value::int(0)), h(&Value::bool(false)));
}
#[test]
fn equal_ints_hash_equally() {
assert_eq!(h(&Value::int(42)), h(&Value::int(42)));
}
#[test]
fn equal_strings_hash_equally() {
assert_eq!(h(&Value::str("hello")), h(&Value::str("hello")));
}
#[test]
fn unequal_strings_hash_differently() {
assert_ne!(h(&Value::str("a")), h(&Value::str("b")));
}
#[test]
fn equal_floats_hash_equally_via_bit_pattern() {
assert_eq!(h(&Value::float(3.14)), h(&Value::float(3.14)));
}
#[test]
fn nan_floats_with_same_bit_pattern_hash_equally() {
let n1 = f64::from_bits(0x7ff8000000000001);
let n2 = f64::from_bits(0x7ff8000000000001);
assert_eq!(h(&Value::float(n1)), h(&Value::float(n2)));
}
#[test]
fn pos_zero_and_neg_zero_hash_differently() {
assert_ne!(h(&Value::float(0.0)), h(&Value::float(-0.0)));
}
#[test]
fn undef_and_empty_string_hash_differently() {
assert_ne!(h(&Value::Undef), h(&Value::str("")));
}
#[test]
fn array_hash_depends_on_element_order() {
let a = Value::array(vec![Value::int(1), Value::int(2)]);
let b = Value::array(vec![Value::int(2), Value::int(1)]);
assert_ne!(h(&a), h(&b));
}
#[test]
fn array_of_same_elements_hashes_equally() {
let a = Value::array(vec![Value::int(1), Value::int(2), Value::int(3)]);
let b = Value::array(vec![Value::int(1), Value::int(2), Value::int(3)]);
assert_eq!(h(&a), h(&b));
}
#[test]
fn status_and_int_with_same_numeric_hash_differently() {
assert_ne!(h(&Value::status(7)), h(&Value::int(7)));
}
#[test]
fn native_fn_with_distinct_ids_hash_differently() {
assert_ne!(h(&Value::NativeFn(1)), h(&Value::NativeFn(2)));
}
#[test]
fn empty_arrays_hash_equally() {
assert_eq!(h(&Value::array(vec![])), h(&Value::array(vec![])));
}
#[test]
fn clone_int_str_array_bool_preserves_equality() {
let v1 = Value::int(42);
let v2 = v1.clone();
assert_eq!(v1, v2);
let s1 = Value::str("hello");
let s2 = s1.clone();
assert_eq!(s1, s2);
let a1 = Value::array(vec![Value::int(1), Value::str("x")]);
let a2 = a1.clone();
assert_eq!(a1, a2);
let b1 = Value::bool(true);
let b2 = b1.clone();
assert_eq!(b1, b2);
}
#[test]
fn clone_hash_preserves_entries() {
let mut m = HashMap::new();
m.insert("k1".into(), Value::int(1));
m.insert("k2".into(), Value::str("v"));
let h1 = Value::hash(m);
let h2 = h1.clone();
assert_eq!(h1, h2);
}
#[test]
fn op_partial_eq_self_for_all_simple_variants() {
let ops = vec![
Op::Nop,
Op::Pop,
Op::Dup,
Op::Swap,
Op::Rot,
Op::Add,
Op::Sub,
Op::Mul,
Op::Div,
Op::Mod,
Op::Pow,
Op::Negate,
Op::Inc,
Op::Dec,
Op::Concat,
Op::StringLen,
Op::Return,
Op::ReturnValue,
Op::PushFrame,
Op::PopFrame,
Op::SetStatus,
Op::GetStatus,
Op::BitNot,
Op::LogNot,
];
for op in &ops {
assert_eq!(op, op);
}
}
#[test]
fn op_partial_eq_distinguishes_indices() {
assert_ne!(Op::GetVar(1), Op::GetVar(2));
assert_ne!(Op::SetVar(1), Op::GetVar(1));
assert_ne!(Op::LoadInt(1), Op::LoadInt(2));
assert_ne!(Op::LoadFloat(1.0), Op::LoadFloat(2.0));
assert_ne!(Op::Jump(1), Op::Jump(2));
assert_ne!(Op::Call(1, 2), Op::Call(1, 3));
assert_ne!(Op::Call(1, 2), Op::Call(2, 2));
assert_ne!(Op::Extended(1, 0), Op::Extended(2, 0));
assert_ne!(Op::ExtendedWide(1, 0), Op::ExtendedWide(1, 1));
}
#[test]
fn op_clone_equals_original_for_all_payloaded_variants() {
let ops = vec![
Op::LoadInt(99),
Op::LoadFloat(1.5),
Op::LoadConst(3),
Op::GetVar(4),
Op::SetVar(4),
Op::Jump(10),
Op::JumpIfTrue(11),
Op::JumpIfFalse(12),
Op::Call(5, 2),
Op::CallBuiltin(2, 1),
Op::CallFunction(6, 0),
Op::Extended(7, 8),
Op::ExtendedWide(9, 0xdeadbeef),
Op::AccumSumLoop(1, 2, 100),
Op::ConcatConstLoop(0, 1, 2, 5),
Op::PushIntRangeLoop(3, 4, 10),
Op::SlotLtIntJumpIfFalse(0, 5, 99),
Op::SlotIncLtIntJumpBack(0, 5, 1),
Op::AddAssignSlotVoid(1, 2),
Op::Redirect(1, 0),
];
for op in &ops {
assert_eq!(*op, op.clone());
}
}
#[test]
fn float_load_op_compares_via_bit_pattern_not_value() {
let nan1 = f64::from_bits(0x7ff8000000000001);
let nan2 = f64::from_bits(0x7ff8000000000001);
let a = Op::LoadFloat(nan1);
let b = Op::LoadFloat(nan2);
let _ = a == b; }
#[test]
fn nested_arrays_compare_structurally() {
let inner1 = Value::array(vec![Value::int(1), Value::int(2)]);
let inner2 = Value::array(vec![Value::int(1), Value::int(2)]);
let outer1 = Value::array(vec![inner1.clone()]);
let outer2 = Value::array(vec![inner2.clone()]);
assert_eq!(outer1, outer2);
}
#[test]
fn nested_array_differs_at_inner_element() {
let outer1 = Value::array(vec![Value::array(vec![Value::int(1)])]);
let outer2 = Value::array(vec![Value::array(vec![Value::int(2)])]);
assert_ne!(outer1, outer2);
}