1
use super::entry::{Symbol, SymbolKind};
2
use super::table::SymbolTable;
3
use crate::ast::Expr;
4

            
5
#[test]
6
1
fn test_symbol_creation() {
7
1
    let sym = Symbol::new("foo", SymbolKind::Variable);
8
1
    assert_eq!(sym.name(), "foo");
9
1
    assert_eq!(sym.kind(), SymbolKind::Variable);
10
1
    assert!(sym.value().is_none());
11
1
}
12

            
13
#[test]
14
1
fn test_symbol_with_value() {
15
1
    let sym = Symbol::new("x", SymbolKind::Variable).with_value(Expr::Bool(true));
16
1
    assert!(sym.value().is_some());
17
1
    assert_eq!(sym.value(), Some(&Expr::Bool(true)));
18
1
}
19

            
20
#[test]
21
1
fn test_symbol_properties() {
22
1
    let mut sym = Symbol::new("test", SymbolKind::Function);
23
1
    sym.set_property("doc", Expr::String("A test function".into()));
24
1
    sym.set_property("pure", Expr::Bool(true));
25

            
26
1
    assert_eq!(
27
1
        sym.get_property("doc"),
28
1
        Some(&Expr::String("A test function".into()))
29
    );
30
1
    assert_eq!(sym.get_property("pure"), Some(&Expr::Bool(true)));
31
1
    assert!(sym.get_property("nonexistent").is_none());
32
1
}
33

            
34
#[test]
35
1
fn test_symbol_table_builtins() {
36
1
    let table = SymbolTable::with_builtins();
37

            
38
1
    assert!(table.contains("+"));
39
1
    assert_eq!(table.lookup("+").unwrap().kind(), SymbolKind::Operator);
40

            
41
1
    assert!(table.contains("IF"));
42
1
    assert_eq!(table.lookup("IF").unwrap().kind(), SymbolKind::SpecialForm);
43

            
44
1
    assert!(table.contains("CAR"));
45
1
    assert_eq!(table.lookup("CAR").unwrap().kind(), SymbolKind::Native);
46

            
47
1
    assert!(table.contains("EVAL"));
48
1
    assert_eq!(
49
1
        table.lookup("EVAL").unwrap().kind(),
50
        SymbolKind::SpecialForm
51
    );
52

            
53
1
    assert!(table.contains("DEBUG"));
54
1
    assert_eq!(table.lookup("DEBUG").unwrap().kind(), SymbolKind::Native);
55
1
}
56

            
57
#[test]
58
1
fn test_symbol_table_define_lookup() {
59
1
    let mut table = SymbolTable::new();
60
1
    table.define(Symbol::new("my-func", SymbolKind::Function));
61

            
62
1
    assert!(table.contains("my-func"));
63
1
    assert!(!table.contains("undefined"));
64

            
65
1
    let sym = table.lookup("my-func").unwrap();
66
1
    assert_eq!(sym.kind(), SymbolKind::Function);
67
1
}
68

            
69
// ADR-0029 strict resolution: a namespaced symbol keys by its canonical
70
// `NS:NAME` string and does NOT alias the bare `NAME`. There is no ambient
71
// current namespace and no cross-namespace fallback.
72

            
73
#[test]
74
1
fn qualified_symbol_keys_separately_from_bare() {
75
1
    let mut table = SymbolTable::new();
76
1
    table.define(Symbol::new("FOO:BAR", SymbolKind::Function));
77

            
78
1
    assert!(table.contains("FOO:BAR"));
79
    // Strict: the qualified key does not create a bare alias.
80
1
    assert!(!table.contains("BAR"));
81
1
    assert!(table.lookup("FOO:BAR").is_some());
82
1
    assert!(table.lookup("BAR").is_none());
83
1
}
84

            
85
#[test]
86
1
fn lookup_qualified_builds_canonical_key() {
87
1
    let mut table = SymbolTable::new();
88
1
    table.define(Symbol::new("FINANCE:ADD-MONEY", SymbolKind::Function));
89

            
90
1
    assert!(
91
1
        table
92
1
            .lookup_qualified(Some("FINANCE"), "ADD-MONEY")
93
1
            .is_some()
94
    );
95
    // An unqualified lookup of the same base name does not reach the namespaced entry.
96
1
    assert!(table.lookup_qualified(None, "ADD-MONEY").is_none());
97
1
}
98

            
99
#[test]
100
1
fn builtins_remain_global_unqualified() {
101
1
    let table = SymbolTable::with_builtins();
102
    // Global builtins keep bare keys; a namespaced lookup of the same base misses.
103
1
    assert!(table.contains("+"));
104
1
    assert!(!table.contains("MATH:+"));
105
1
    assert!(table.lookup_qualified(Some("MATH"), "+").is_none());
106
1
}
107

            
108
#[test]
109
1
fn universal_prelude_loaded_but_not_host_layer() {
110
    // ADR-0029 two-layer prelude: the universal math:* / list:* helpers are
111
    // present in every table; the host-fn-dependent split:* helpers are NOT
112
    // (they load only on the rpc Session path, after host fns are registered).
113
1
    let table = SymbolTable::with_builtins();
114
1
    assert!(table.contains("MATH:SQUARE"));
115
1
    assert!(table.contains("LIST:SECOND"));
116
1
    assert!(!table.contains("SPLIT:LIST-FOR-TRANSACTION"));
117

            
118
    // The pure-wasm table loads the same universal layer.
119
1
    let wasm_table = SymbolTable::with_builtins_for_wasm();
120
1
    assert!(wasm_table.contains("MATH:SQUARE"));
121
1
    assert!(!wasm_table.contains("SPLIT:LIST-FOR-TRANSACTION"));
122
1
}