nx_http_router_test.nx source
↩ module page · 118 lines · 4621 B
1// nx_http_router_test.nx -- route dispatch shape verification.
2
3import "nx_syscalls.nx"
4import "nx_tier.nx"
5import "nx_http_router.nx"
6
7const HANDLER_HEALTH: nx_int = 1
8const HANDLER_LIST_CHARS: nx_int = 2
9const HANDLER_GET_CHAR: nx_int = 3
10const HANDLER_BATCH_POST: nx_int = 4
11const HANDLER_OPTIONS: nx_int = 5
12
13func main() -> nx_int {
14 let r: *HttpRouter = nx_http_router_alloc(16)
15
16 // ===== Register routes =====================================
17 //
18 // Order matters: more specific first.
19
20 nx_http_router_add(r,
21 NX_HTTP_METHOD_GET, NX_HTTP_MATCH_EXACT,
22 "/health" as *u8, 7,
23 HANDLER_HEALTH)
24
25 nx_http_router_add(r,
26 NX_HTTP_METHOD_GET, NX_HTTP_MATCH_EXACT,
27 "/api/character" as *u8, 14,
28 HANDLER_LIST_CHARS)
29
30 nx_http_router_add(r,
31 NX_HTTP_METHOD_GET, NX_HTTP_MATCH_PREFIX,
32 "/api/character/" as *u8, 15,
33 HANDLER_GET_CHAR)
34
35 nx_http_router_add(r,
36 NX_HTTP_METHOD_POST, NX_HTTP_MATCH_PREFIX,
37 "/api/batch" as *u8, 10,
38 HANDLER_BATCH_POST)
39
40 nx_http_router_add(r,
41 NX_HTTP_METHOD_ANY, NX_HTTP_MATCH_EXACT,
42 "/cors" as *u8, 5,
43 HANDLER_OPTIONS)
44
45 if r.routes_count != 5 { return 1 }
46
47 // ===== Exact GET match =====================================
48 let h1: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
49 "/health" as *u8, 7)
50 if h1 != HANDLER_HEALTH { return 10 }
51
52 // ===== Exact match must not greedy-match prefix ============
53 //
54 // GET /api/character must hit LIST_CHARS (exact), not GET_CHAR
55 // (prefix would match too, but exact is registered first).
56 let h2: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
57 "/api/character" as *u8, 14)
58 if h2 != HANDLER_LIST_CHARS { return 11 }
59
60 // ===== Prefix match ========================================
61 //
62 // GET /api/character/42 -> prefix /api/character/ -> GET_CHAR
63 let h3: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
64 "/api/character/42" as *u8, 17)
65 if h3 != HANDLER_GET_CHAR { return 12 }
66
67 // ===== Method mismatch -> no match =========================
68 let h4: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_POST,
69 "/health" as *u8, 7)
70 if h4 != 0 - 1 { return 13 }
71
72 // ===== POST /api/batch -> BATCH_POST ======================
73 let h5: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_POST,
74 "/api/batch" as *u8, 10)
75 if h5 != HANDLER_BATCH_POST { return 14 }
76
77 // ===== Wildcard ANY matches any method on the path ========
78 let h6: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_OPTIONS,
79 "/cors" as *u8, 5)
80 if h6 != HANDLER_OPTIONS { return 15 }
81 let h7: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
82 "/cors" as *u8, 5)
83 if h7 != HANDLER_OPTIONS { return 16 }
84
85 // ===== Unknown path -> -1 ==================================
86 let h8: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
87 "/nothing" as *u8, 8)
88 if h8 != 0 - 1 { return 17 }
89
90 // ===== Path shorter than prefix -> no prefix match =========
91 //
92 // path "/api" is 4 bytes, but /api/character/ prefix is 15 -> no.
93 let h9: nx_int = nx_http_router_match(r, NX_HTTP_METHOD_GET,
94 "/api" as *u8, 4)
95 if h9 != 0 - 1 { return 18 }
96
97 // ===== Method enum validity ===============================
98 if nx_http_method_is_valid(NX_HTTP_METHOD_GET) != 1 { return 20 }
99 if nx_http_method_is_valid(NX_HTTP_METHOD_ANY) != 1 { return 21 }
100 if nx_http_method_is_valid(0 - 1) != 0 { return 22 }
101 if nx_http_method_is_valid(NX_HTTP_METHOD_N_KINDS) != 0 { return 23 }
102
103 // ===== Capacity exhaustion ================================
104 let small: *HttpRouter = nx_http_router_alloc(2)
105 nx_http_router_add(small, NX_HTTP_METHOD_GET, NX_HTTP_MATCH_EXACT,
106 "/a" as *u8, 2, 1)
107 nx_http_router_add(small, NX_HTTP_METHOD_GET, NX_HTTP_MATCH_EXACT,
108 "/b" as *u8, 2, 2)
109 let full: nx_int = nx_http_router_add(small,
110 NX_HTTP_METHOD_GET, NX_HTTP_MATCH_EXACT,
111 "/c" as *u8, 2, 3)
112 if full != 0 - 1 { return 30 }
113
114 // Suffix-offset helper sanity
115 if nx_http_router_suffix_offset(15) != 15 { return 40 }
116
117 return 0
118}