Skip to content

Commit c63d154

Browse files
test: 13 tests for http_get/post/post_json/put/delete builtins (arg-validation + network-conditional schema)
1 parent 91a5cb4 commit c63d154

1 file changed

Lines changed: 176 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Tests for native HTTP builtins.
2+
#
3+
# http_get(url, headers?) → {status, body, ok}
4+
# http_post(url, body, headers?) → {status, body, ok}
5+
# http_post_json(url, data, hdrs?)→ {status, body, ok, json}
6+
# http_put(url, body, headers?) → {status, body, ok}
7+
# http_delete(url, headers?) → {status, body, ok}
8+
#
9+
# Network-dependent tests are wrapped in try/catch so they pass
10+
# gracefully when the test environment has no outbound HTTP access.
11+
# They do validate the response schema when the network IS available.
12+
13+
fn assert_eq(actual, expected, msg) {
14+
if actual != expected {
15+
test_record_failure(msg + ": expected " + to_string(expected) + " got " + to_string(actual));
16+
}
17+
}
18+
19+
fn assert_true(cond, msg) { if !cond { test_record_failure(msg); } }
20+
21+
# ── Argument-validation (no network) ─────────────────────────────────────────
22+
23+
fn test_http_get_requires_url() {
24+
h err = ""
25+
try { http_get() } catch e { err = e }
26+
assert_true(str_len(err) > 0, "http_get() with no args → error")
27+
}
28+
29+
fn test_http_post_requires_body() {
30+
h err = ""
31+
try { http_post("http://example.com") } catch e { err = e }
32+
assert_true(str_len(err) > 0, "http_post with only url → error")
33+
}
34+
35+
fn test_http_put_requires_body() {
36+
h err = ""
37+
try { http_put("http://example.com") } catch e { err = e }
38+
assert_true(str_len(err) > 0, "http_put with only url → error")
39+
}
40+
41+
fn test_http_delete_requires_url() {
42+
h err = ""
43+
try { http_delete() } catch e { err = e }
44+
assert_true(str_len(err) > 0, "http_delete with no args → error")
45+
}
46+
47+
fn test_http_post_json_requires_data() {
48+
h err = ""
49+
try { http_post_json("http://example.com") } catch e { err = e }
50+
assert_true(str_len(err) > 0, "http_post_json with only url → error")
51+
}
52+
53+
fn test_http_get_bad_header_type() {
54+
# Headers must be a dict or null — passing an int should error.
55+
h err = ""
56+
try { http_get("http://example.com", 42) } catch e { err = e }
57+
assert_true(str_len(err) > 0, "int headers → error")
58+
}
59+
60+
# ── Response schema (network-conditional) ─────────────────────────────────────
61+
# Uses httpbin.org — a public echo/testing HTTP service.
62+
# If the request fails (no network), the test is silently skipped.
63+
64+
fn test_http_get_response_schema() {
65+
h net_ok = 1
66+
h resp = null
67+
try {
68+
resp = http_get("https://httpbin.org/get")
69+
} catch e {
70+
net_ok = 0
71+
}
72+
if net_ok {
73+
assert_true(dict_has(resp, "status"), "response has status")
74+
assert_true(dict_has(resp, "body"), "response has body")
75+
assert_true(dict_has(resp, "ok"), "response has ok")
76+
assert_eq(resp["ok"], true, "httpbin GET returns 2xx")
77+
assert_true(resp["status"] >= 200 and resp["status"] < 300, "status 2xx")
78+
assert_true(str_len(resp["body"]) > 0, "body non-empty")
79+
}
80+
}
81+
82+
fn test_http_get_404_ok_false() {
83+
h net_ok = 1
84+
h resp = null
85+
try {
86+
resp = http_get("https://httpbin.org/status/404")
87+
} catch e {
88+
net_ok = 0
89+
}
90+
if net_ok {
91+
assert_eq(resp["status"], 404, "404 status code")
92+
assert_eq(resp["ok"], false, "404 → ok = false")
93+
}
94+
}
95+
96+
fn test_http_post_response_schema() {
97+
h net_ok = 1
98+
h resp = null
99+
try {
100+
resp = http_post("https://httpbin.org/post", "hello=world")
101+
} catch e {
102+
net_ok = 0
103+
}
104+
if net_ok {
105+
assert_true(dict_has(resp, "status"), "has status")
106+
assert_true(dict_has(resp, "body"), "has body")
107+
assert_true(dict_has(resp, "ok"), "has ok")
108+
assert_eq(resp["ok"], true, "POST httpbin → 2xx")
109+
}
110+
}
111+
112+
fn test_http_post_json_response_schema() {
113+
h net_ok = 1
114+
h resp = null
115+
try {
116+
resp = http_post_json("https://httpbin.org/post", {key: "value", num: 42})
117+
} catch e {
118+
net_ok = 0
119+
}
120+
if net_ok {
121+
assert_true(dict_has(resp, "status"), "has status")
122+
assert_true(dict_has(resp, "body"), "has body")
123+
assert_true(dict_has(resp, "ok"), "has ok")
124+
assert_true(dict_has(resp, "json"), "has json key")
125+
assert_eq(resp["ok"], true, "POST JSON httpbin → 2xx")
126+
# httpbin echoes the JSON we sent under resp.json.json
127+
h j = resp["json"]
128+
if j != null {
129+
assert_true(dict_has(j, "json"), "httpbin wraps payload under json")
130+
}
131+
}
132+
}
133+
134+
fn test_http_delete_response_schema() {
135+
h net_ok = 1
136+
h resp = null
137+
try {
138+
resp = http_delete("https://httpbin.org/delete")
139+
} catch e {
140+
net_ok = 0
141+
}
142+
if net_ok {
143+
assert_true(dict_has(resp, "status"), "has status")
144+
assert_true(dict_has(resp, "body"), "has body")
145+
assert_eq(resp["ok"], true, "DELETE httpbin → 2xx")
146+
}
147+
}
148+
149+
fn test_http_get_with_custom_headers() {
150+
h net_ok = 1
151+
h resp = null
152+
try {
153+
resp = http_get("https://httpbin.org/headers", {X-OMC-Test: "yes"})
154+
} catch e {
155+
net_ok = 0
156+
}
157+
if net_ok {
158+
assert_eq(resp["ok"], true, "headers GET → 2xx")
159+
# httpbin echoes headers in the body JSON — we just verify body is non-empty
160+
assert_true(str_len(resp["body"]) > 0, "body contains header echo")
161+
}
162+
}
163+
164+
fn test_http_get_null_headers_accepted() {
165+
# Passing null explicitly for headers must not error.
166+
h net_ok = 1
167+
h resp = null
168+
try {
169+
resp = http_get("https://httpbin.org/get", null)
170+
} catch e {
171+
net_ok = 0
172+
}
173+
if net_ok {
174+
assert_eq(resp["ok"], true, "null headers → 2xx")
175+
}
176+
}

0 commit comments

Comments
 (0)