1
use super::*;
2

            
3
#[tokio::test]
4
1
async fn false_bool_in_an_anyref_slot_is_nil() {
5
7
    for form in [
6
1
        "(null? (car (cdr (if (> (rpc-protocol-version) 0) (list t nil) (list 1 2)))))",
7
1
        "(null? (car (cdr (handler-case (list (> (rpc-protocol-version) 0) nil) \
8
1
         (t (e) (list 1/2 (index->scalar (rpc-protocol-version))))))))",
9
1
        "(null? (car (if (> (rpc-protocol-version) 0) \
10
1
         (list nil (> (rpc-protocol-version) 0)) (list \"a\" (rpc-protocol-version)))))",
11
1
        "(null? (car (cons (> (rpc-protocol-version) 5) (list \"a\"))))",
12
1
        "(null? (car (fold (lambda (acc x) (cons x acc)) '(\"a\") \
13
1
         (list (> (rpc-protocol-version) 5)))))",
14
1
        "(null? (if (> (rpc-protocol-version) 0) (> (rpc-protocol-version) 5) \"s\"))",
15
1
        "(null? (car (cdr (append (list (> (rpc-protocol-version) 0) nil) \
16
1
         (list (rpc-protocol-version))))))",
17
1
    ] {
18
7
        assert_values(&[(form, "t")]).await;
19
1
    }
20
1
    assert_values(&[(
21
1
        "(null? (car (cons (> (rpc-protocol-version) 0) (list \"a\"))))",
22
1
        "nil",
23
1
    )])
24
1
    .await;
25
1
}
26

            
27
#[tokio::test]
28
1
async fn index_result_beyond_i31_crosses_the_eval_boundary_exactly() {
29
1
    assert_values(&[
30
1
        (
31
1
            "(handler-case (* 1073741824 (rpc-protocol-version)) (index-overflow (e) -1))",
32
1
            "1073741824",
33
1
        ),
34
1
        ("2000000000", "2000000000"),
35
1
        (
36
1
            "(if (> (rpc-protocol-version) 0) 2000000000 0)",
37
1
            "2000000000",
38
1
        ),
39
1
        ("(- -2147483647 (rpc-protocol-version))", "-2147483648"),
40
1
    ])
41
1
    .await;
42
1
}
43

            
44
#[tokio::test]
45
1
async fn car_and_cdr_of_a_runtime_null_pair_never_trap() {
46
1
    assert_values(&[
47
1
        (
48
1
            "(car (if (< (rpc-protocol-version) 0) (list \"a\") nil))",
49
1
            "nil",
50
1
        ),
51
1
        (
52
1
            "(car (if (< (rpc-protocol-version) 0) (list t) nil))",
53
1
            "nil",
54
1
        ),
55
1
        (
56
1
            "(car (if (> (rpc-protocol-version) 0) \
57
1
             (if (> (rpc-protocol-version) 1) (list \"a\") nil) (list \"b\" \"c\")))",
58
1
            "nil",
59
1
        ),
60
1
        (
61
1
            "(cdr (if (< (rpc-protocol-version) 0) (list 1) nil))",
62
1
            "nil",
63
1
        ),
64
1
        (
65
1
            "(handler-case (car (cdr (list (rpc-protocol-version)))) (car-of-nil (e) -1))",
66
1
            "-1",
67
1
        ),
68
1
    ])
69
1
    .await;
70
1
    assert_error_code("(car (cdr (list (rpc-protocol-version))))", "CAR-OF-NIL").await;
71
1
    assert_error_code(
72
1
        "(car (if (< (rpc-protocol-version) 0) (list 1) nil))",
73
1
        "CAR-OF-NIL",
74
1
    )
75
1
    .await;
76
    // A scalar or money value is never nil either, so an empty numeric list
77
    // has no car. The untaken branch never calls the DB-backed host fn.
78
1
    assert_error_code(
79
1
        "(+ (car (if (< (rpc-protocol-version) 0) (list 1/2) nil)) 1)",
80
1
        "CAR-OF-NIL",
81
1
    )
82
1
    .await;
83
1
    assert_error_code(
84
1
        "(car (if (< (rpc-protocol-version) 0) (list (account-balance \"cash\")) nil))",
85
1
        "CAR-OF-NIL",
86
1
    )
87
1
    .await;
88
1
    assert_values(&[(
89
1
        "(handler-case (car (if (< (rpc-protocol-version) 0) (list 1/2) nil)) \
90
1
         (car-of-nil (e) 7))",
91
1
        "7",
92
1
    )])
93
1
    .await;
94
1
}
95

            
96
#[tokio::test]
97
1
async fn filter_and_do_treat_a_runtime_index_as_true() {
98
1
    assert_values(&[
99
1
        ("(filter (lambda (x) (* 0 x)) (list 1 2))", "\"(1 2)\""),
100
1
        (
101
1
            "(filter (lambda (x) (* 0 x)) (list 1 (rpc-protocol-version)))",
102
1
            "\"(1 1)\"",
103
1
        ),
104
1
        (
105
1
            "(let ((n 0)) (do ((i (* 0 (rpc-protocol-version)) (+ i 1))) (i n) \
106
1
             (setf n (+ n (rpc-protocol-version)))))",
107
1
            "0",
108
1
        ),
109
1
    ])
110
1
    .await;
111
1
}
112

            
113
#[tokio::test]
114
1
async fn handler_case_reconciles_an_anyref_body_with_literal_and_nil_arms() {
115
1
    assert_values(&[(
116
1
        "(handler-case (if (> (rpc-protocol-version) 0) (rpc-protocol-version)) (t (e) 0))",
117
1
        "\"<anyref>\"",
118
1
    )])
119
1
    .await;
120
1
    let response = eval_value_of("(handler-case (rpc-protocol-version) (t (e) nil))").await;
121
1
    assert!(
122
1
        response.contains("HANDLER-CASE: a nil arm cannot join a i32 result"),
123
1
        "got: {response}"
124
1
    );
125
1
}
126

            
127
#[tokio::test]
128
1
async fn fractional_literal_never_crosses_into_an_index_arm() {
129
1
    assert_values(&[
130
1
        (
131
1
            "(if (> (rpc-protocol-version) 0) (rpc-protocol-version) 1/2)",
132
1
            "\"<anyref>\"",
133
1
        ),
134
1
        (
135
1
            "(if (> (rpc-protocol-version) 0) (if (> (rpc-protocol-version) 1) 1 2) 1/2)",
136
1
            "\"<anyref>\"",
137
1
        ),
138
1
        (
139
1
            "(if (> (rpc-protocol-version) 0) (index->scalar (rpc-protocol-version)) 1/2)",
140
1
            "1",
141
1
        ),
142
1
    ])
143
1
    .await;
144
1
    let response = eval_value_of("(handler-case (rpc-protocol-version) (t (e) 1/2))").await;
145
1
    assert!(
146
1
        response.contains("conflicting result types i32 and ratio"),
147
1
        "got: {response}"
148
1
    );
149
1
}
150

            
151
#[tokio::test]
152
1
async fn a_runtime_index_is_never_nil() {
153
1
    assert_values(&[
154
1
        ("(null? (* 0 (rpc-protocol-version)))", "nil"),
155
1
        ("(not (* 0 (rpc-protocol-version)))", "nil"),
156
1
        ("(if (* 0 (rpc-protocol-version)) 1 2)", "1"),
157
1
        ("(if (< (rpc-protocol-version) 0) 5)", "nil"),
158
1
        ("(null? (if (> (rpc-protocol-version) 0) 5))", "nil"),
159
1
        ("(null? (> (rpc-protocol-version) 5))", "t"),
160
1
        (
161
1
            "(and (* 0 (rpc-protocol-version)) (> (rpc-protocol-version) 0))",
162
1
            "t",
163
1
        ),
164
1
        (
165
1
            "(or (* 0 (rpc-protocol-version)) (> (rpc-protocol-version) 5))",
166
1
            "t",
167
1
        ),
168
1
    ])
169
1
    .await;
170
1
}
171

            
172
#[tokio::test]
173
1
async fn constant_list_arms_materialize_as_chains() {
174
1
    assert_values(&[
175
1
        (
176
1
            "(if (> (rpc-protocol-version) 0) '(1 2) '(\"a\"))",
177
1
            "\"(<anyref> <anyref>)\"",
178
1
        ),
179
1
        (
180
1
            "(let ((xs (list 1 2))) (if (> (rpc-protocol-version) 0) xs nil))",
181
1
            "\"(1 2)\"",
182
1
        ),
183
1
        (
184
1
            "(let ((xs '(1 2))) (handler-case xs (t (e) nil)))",
185
1
            "\"(1 2)\"",
186
1
        ),
187
1
        (
188
1
            "(let ((xs '(1 2))) (car (if (> (rpc-protocol-version) 0) xs \
189
1
             (list (rpc-protocol-version)))))",
190
1
            "1",
191
1
        ),
192
1
    ])
193
1
    .await;
194
1
}
195

            
196
#[tokio::test]
197
1
async fn nil_arm_after_runtime_effects_reconciles() {
198
1
    assert_values(&[(
199
1
        "(let ((n 0)) (handler-case (begin (setf n (rpc-protocol-version)) nil) \
200
1
         (t (e) (list 1))) n)",
201
1
        "1",
202
1
    )])
203
1
    .await;
204
1
}
205

            
206
#[tokio::test]
207
1
async fn map_applies_a_quoted_defun_over_a_runtime_list() {
208
2
    for head in ["map", "mapcar"] {
209
2
        assert_values(&[(
210
2
            &format!("(begin (defun g2 (x) (+ x 1)) ({head} 'g2 (list (rpc-protocol-version))))"),
211
2
            "\"(2)\"",
212
2
        )])
213
2
        .await;
214
1
    }
215
1
}