import { test, expect } from "bun:test" import { isValue, toValue } from "#reef" test("isValue - recognizes valid Value objects", () => { expect(isValue({ type: 'number', value: 42 })).toBe(true) expect(isValue({ type: 'number', value: 0 })).toBe(true) expect(isValue({ type: 'string', value: 'hello' })).toBe(true) expect(isValue({ type: 'string', value: '' })).toBe(true) expect(isValue({ type: 'boolean', value: true })).toBe(true) expect(isValue({ type: 'boolean', value: false })).toBe(true) expect(isValue({ type: 'null', value: null })).toBe(true) expect(isValue({ type: 'array', value: [] })).toBe(true) expect(isValue({ type: 'array', value: [toValue(1), toValue(2)] })).toBe(true) expect(isValue({ type: 'dict', value: new Map() })).toBe(true) expect(isValue({ type: 'regex', value: /test/ })).toBe(true) expect(isValue({ type: 'function', value: '', params: [], defaults: {}, body: 0, variadic: false, named: false, parentScope: null as any })).toBe(true) expect(isValue({ type: 'native', value: '', fn: (() => { }) as any })).toBe(true) }) test("isValue - rejects primitives", () => { expect(isValue(42)).toBe(false) expect(isValue(0)).toBe(false) expect(isValue('hello')).toBe(false) expect(isValue('')).toBe(false) expect(isValue(true)).toBe(false) expect(isValue(false)).toBe(false) expect(isValue(null)).toBe(false) expect(isValue(undefined)).toBe(false) }) test("isValue - rejects plain objects", () => { expect(isValue({})).toBe(false) expect(isValue({ foo: 'bar' })).toBe(false) expect(isValue({ type: 'number' })).toBe(false) expect(isValue({ value: 42 })).toBe(false) }) test("isValue - rejects arrays and functions", () => { expect(isValue([])).toBe(false) expect(isValue([1, 2, 3])).toBe(false) expect(isValue(() => { })).toBe(false) expect(isValue(function () { })).toBe(false) }) test("isValue - rejects other object types", () => { expect(isValue(new Date())).toBe(false) expect(isValue(/regex/)).toBe(false) expect(isValue(new Map())).toBe(false) expect(isValue(new Set())).toBe(false) }) test("isValue - used by toValue to detect already-converted values", () => { const value = toValue(42) expect(isValue(value)).toBe(true) const result = toValue(value) expect(result).toBe(value) }) test("isValue - edge cases with type and value properties", () => { // extra properties expect(isValue({ type: 'number', value: 42, extra: 'data' })).toBe(true) expect(isValue({ type: null, value: 42 })).toBe(false) expect(isValue({ type: 'number', value: undefined })).toBe(true) expect(isValue({ type: 'number', val: 42 })).toBe(false) expect(isValue({ typ: 'number', value: 42 })).toBe(false) }) test("toValue - converts wrapped Reef functions back to original Value", async () => { const { VM, toBytecode, fnFromValue } = await import("#reef") // Create a Reef function const bytecode = toBytecode([ ["MAKE_FUNCTION", ["x"], ".body"], ["STORE", "add1"], ["JUMP", ".end"], [".body:"], ["LOAD", "x"], ["PUSH", 1], ["ADD"], ["RETURN"], [".end:"], ["HALT"] ]) const vm = new VM(bytecode) await vm.run() const reefFunction = vm.scope.get("add1")! expect(reefFunction.type).toBe("function") // Convert to JS function const jsFunction = fnFromValue(reefFunction, vm) expect(typeof jsFunction).toBe("function") // Convert back to Value - should return the original Reef function const backToValue = toValue(jsFunction) expect(backToValue).toBe(reefFunction) // Same reference expect(backToValue.type).toBe("function") })