authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2024-06-26 23:37:11+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-03 15:34:59-04:00
log8f7b50e2c4ad0c08015bce02a3ba8a7a9a058e11
treef0b56e1d62c04164cefdc8a47b98e561f50248a4
parentfe66a12a23eda90b89b06dc28957f3baac01ee89

json: respect duplicate_field_behavior in std.json.Value.jsonParse


3 files changed, 44 insertions(+), 2 deletions(-)

lib/std/json/dynamic.zig+13-1
......@@ -147,7 +147,19 @@ fn handleCompleteValue(stack: *Array, allocator: Allocator, source: anytype, val
147147
148148 // stack: [..., .object]
149149 var object = &stack.items[stack.items.len - 1].object;
150 try object.put(key, value);
150
151 const gop = try object.getOrPut(key);
152 if (gop.found_existing) {
153 switch (options.duplicate_field_behavior) {
154 .use_first => {},
155 .@"error" => return error.DuplicateField,
156 .use_last => {
157 gop.value_ptr.* = value;
158 },
159 }
160 } else {
161 gop.value_ptr.* = value;
162 }
151163
152164 // This is an invalid state to leave the stack in,
153165 // so we have to process the next token before we return.
lib/std/json/dynamic_test.zig+28
......@@ -181,6 +181,34 @@ test "escaped characters" {
181181 try testing.expectEqualSlices(u8, obj.get("surrogatepair").?.string, "😂");
182182}
183183
184test "Value with duplicate fields" {
185 var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
186 defer arena_allocator.deinit();
187
188 const doc =
189 \\{
190 \\ "abc": 0,
191 \\ "abc": 1
192 \\}
193 ;
194
195 try testing.expectError(error.DuplicateField, parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
196 .duplicate_field_behavior = .@"error",
197 }));
198
199 const first = try parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
200 .duplicate_field_behavior = .use_first,
201 });
202 try testing.expectEqual(@as(usize, 1), first.object.count());
203 try testing.expectEqual(@as(i64, 0), first.object.get("abc").?.integer);
204
205 const last = try parseFromSliceLeaky(std.json.Value, arena_allocator.allocator(), doc, .{
206 .duplicate_field_behavior = .use_last,
207 });
208 try testing.expectEqual(@as(usize, 1), last.object.count());
209 try testing.expectEqual(@as(i64, 1), last.object.get("abc").?.integer);
210}
211
184212test "Value.jsonStringify" {
185213 var vals = [_]Value{
186214 .{ .integer = 1 },
lib/std/json/test.zig+3-1
......@@ -28,7 +28,9 @@ fn testLowLevelScanner(s: []const u8) !void {
2828 }
2929}
3030fn testHighLevelDynamicParser(s: []const u8) !void {
31 var parsed = try parseFromSlice(Value, testing.allocator, s, .{});
31 var parsed = try parseFromSlice(Value, testing.allocator, s, .{
32 .duplicate_field_behavior = .use_first,
33 });
3234 defer parsed.deinit();
3335}
3436