An ATProto Lexicon validator for Gleam.
1import gleam/json
2import gleeunit
3import gleeunit/should
4import honk/validation/context
5import honk/validation/primary/query
6
7pub fn main() {
8 gleeunit.main()
9}
10
11// Test valid query parameters
12pub fn valid_query_parameters_test() {
13 let schema =
14 json.object([
15 #("type", json.string("query")),
16 #(
17 "parameters",
18 json.object([
19 #("type", json.string("params")),
20 #(
21 "properties",
22 json.object([
23 #(
24 "limit",
25 json.object([
26 #("type", json.string("integer")),
27 #("minimum", json.int(1)),
28 #("maximum", json.int(100)),
29 ]),
30 ),
31 #("cursor", json.object([#("type", json.string("string"))])),
32 ]),
33 ),
34 ]),
35 ),
36 ])
37
38 let data =
39 json.object([#("limit", json.int(50)), #("cursor", json.string("abc123"))])
40
41 let assert Ok(ctx) = context.builder() |> context.build()
42 query.validate_data(data, schema, ctx) |> should.be_ok
43}
44
45// Test query with required parameter
46pub fn valid_query_with_required_test() {
47 let schema =
48 json.object([
49 #("type", json.string("query")),
50 #(
51 "parameters",
52 json.object([
53 #("type", json.string("params")),
54 #(
55 "properties",
56 json.object([
57 #("repo", json.object([#("type", json.string("string"))])),
58 ]),
59 ),
60 #("required", json.array([json.string("repo")], fn(x) { x })),
61 ]),
62 ),
63 ])
64
65 let data = json.object([#("repo", json.string("did:plc:abc123"))])
66
67 let assert Ok(ctx) = context.builder() |> context.build()
68 query.validate_data(data, schema, ctx) |> should.be_ok
69}
70
71// Test invalid: missing required parameter
72pub fn invalid_query_missing_required_test() {
73 let schema =
74 json.object([
75 #("type", json.string("query")),
76 #(
77 "parameters",
78 json.object([
79 #("type", json.string("params")),
80 #(
81 "properties",
82 json.object([
83 #("repo", json.object([#("type", json.string("string"))])),
84 #("collection", json.object([#("type", json.string("string"))])),
85 ]),
86 ),
87 #("required", json.array([json.string("repo")], fn(x) { x })),
88 ]),
89 ),
90 ])
91
92 let data = json.object([#("collection", json.string("app.bsky.feed.post"))])
93
94 let assert Ok(ctx) = context.builder() |> context.build()
95 query.validate_data(data, schema, ctx) |> should.be_error
96}
97
98// Test invalid: wrong parameter type
99pub fn invalid_query_wrong_type_test() {
100 let schema =
101 json.object([
102 #("type", json.string("query")),
103 #(
104 "parameters",
105 json.object([
106 #("type", json.string("params")),
107 #(
108 "properties",
109 json.object([
110 #(
111 "limit",
112 json.object([
113 #("type", json.string("integer")),
114 #("minimum", json.int(1)),
115 ]),
116 ),
117 ]),
118 ),
119 ]),
120 ),
121 ])
122
123 let data = json.object([#("limit", json.string("not-a-number"))])
124
125 let assert Ok(ctx) = context.builder() |> context.build()
126 query.validate_data(data, schema, ctx) |> should.be_error
127}
128
129// Test invalid: data not an object
130pub fn invalid_query_not_object_test() {
131 let schema =
132 json.object([
133 #("type", json.string("query")),
134 #(
135 "parameters",
136 json.object([
137 #("type", json.string("params")),
138 #("properties", json.object([])),
139 ]),
140 ),
141 ])
142
143 let data = json.array([], fn(x) { x })
144
145 let assert Ok(ctx) = context.builder() |> context.build()
146 query.validate_data(data, schema, ctx) |> should.be_error
147}
148
149// Test parameter constraint violation
150pub fn invalid_query_constraint_violation_test() {
151 let schema =
152 json.object([
153 #("type", json.string("query")),
154 #(
155 "parameters",
156 json.object([
157 #("type", json.string("params")),
158 #(
159 "properties",
160 json.object([
161 #(
162 "limit",
163 json.object([
164 #("type", json.string("integer")),
165 #("maximum", json.int(100)),
166 ]),
167 ),
168 ]),
169 ),
170 ]),
171 ),
172 ])
173
174 let data = json.object([#("limit", json.int(200))])
175
176 let assert Ok(ctx) = context.builder() |> context.build()
177 query.validate_data(data, schema, ctx) |> should.be_error
178}
179
180// Test array parameter
181pub fn valid_query_array_parameter_test() {
182 let schema =
183 json.object([
184 #("type", json.string("query")),
185 #(
186 "parameters",
187 json.object([
188 #("type", json.string("params")),
189 #(
190 "properties",
191 json.object([
192 #(
193 "tags",
194 json.object([
195 #("type", json.string("array")),
196 #(
197 "items",
198 json.object([
199 #("type", json.string("string")),
200 #("maxLength", json.int(50)),
201 ]),
202 ),
203 ]),
204 ),
205 ]),
206 ),
207 ]),
208 ),
209 ])
210
211 let data =
212 json.object([
213 #(
214 "tags",
215 json.array([json.string("tag1"), json.string("tag2")], fn(x) { x }),
216 ),
217 ])
218
219 let assert Ok(ctx) = context.builder() |> context.build()
220 query.validate_data(data, schema, ctx) |> should.be_ok
221}
222
223// Test query with no parameters
224pub fn valid_query_no_parameters_test() {
225 let schema = json.object([#("type", json.string("query"))])
226
227 let data = json.object([])
228
229 let assert Ok(ctx) = context.builder() |> context.build()
230 query.validate_data(data, schema, ctx) |> should.be_ok
231}