| author | |
| committer | |
| log | 8f7b50e2c4ad0c08015bce02a3ba8a7a9a058e11 |
| tree | f0b56e1d62c04164cefdc8a47b98e561f50248a4 |
| parent | fe66a12a23eda90b89b06dc28957f3baac01ee89 |
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 |
| 147 | 147 | |
| 148 | 148 | // stack: [..., .object] |
| 149 | 149 | 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 | } | |
| 151 | 163 | |
| 152 | 164 | // This is an invalid state to leave the stack in, |
| 153 | 165 | // 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" { |
| 181 | 181 | try testing.expectEqualSlices(u8, obj.get("surrogatepair").?.string, "😂"); |
| 182 | 182 | } |
| 183 | 183 | |
| 184 | test "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 | ||
| 184 | 212 | test "Value.jsonStringify" { |
| 185 | 213 | var vals = [_]Value{ |
| 186 | 214 | .{ .integer = 1 }, |
lib/std/json/test.zig+3-1| ... | ... | @@ -28,7 +28,9 @@ fn testLowLevelScanner(s: []const u8) !void { |
| 28 | 28 | } |
| 29 | 29 | } |
| 30 | 30 | fn 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 | }); | |
| 32 | 34 | defer parsed.deinit(); |
| 33 | 35 | } |
| 34 | 36 |