diff --git a/lib/std/json.zig b/lib/std/json.zig index 0cbd4cba54b9..2a12023c76b3 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1,14 +1,70 @@ //! JSON parsing and stringification conforming to RFC 8259. https://datatracker.ietf.org/doc/html/rfc8259 //! -//! The low-level `Scanner` API reads from an input slice or successive slices of inputs, +//! The low-level `Scanner` API produces `Token`s from an input slice or successive slices of inputs, //! The `Reader` API connects a `std.io.Reader` to a `Scanner`. //! -//! The high-level `parseFromSlice` and `parseFromTokenSource` deserializes a JSON document into a Zig type. +//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type. //! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection. //! //! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.io.Writer`. //! The high-level `stringify` serializes a Zig or `Value` type into JSON. +const testing = @import("std").testing; +const ArrayList = @import("std").ArrayList; + +test Scanner { + var scanner = Scanner.initCompleteInput(testing.allocator, "{\"foo\": 123}\n"); + defer scanner.deinit(); + try testing.expectEqual(Token.object_begin, try scanner.next()); + try testing.expectEqualSlices(u8, "foo", (try scanner.next()).string); + try testing.expectEqualSlices(u8, "123", (try scanner.next()).number); + try testing.expectEqual(Token.object_end, try scanner.next()); + try testing.expectEqual(Token.end_of_document, try scanner.next()); +} + +test parseFromSlice { + var parsed_str = try parseFromSlice([]const u8, testing.allocator, "\"a\\u0020b\"", .{}); + defer parsed_str.deinit(); + try testing.expectEqualSlices(u8, "a b", parsed_str.value); + + const T = struct { a: i32 = -1, b: [2]u8 }; + var parsed_struct = try parseFromSlice(T, testing.allocator, "{\"b\":\"xy\"}", .{}); + defer parsed_struct.deinit(); + try testing.expectEqual(@as(i32, -1), parsed_struct.value.a); // default value + try testing.expectEqualSlices(u8, "xy", parsed_struct.value.b[0..]); +} + +test Value { + var parsed = try parseFromSlice(Value, testing.allocator, "{\"anything\": \"goes\"}", .{}); + defer parsed.deinit(); + try testing.expectEqualSlices(u8, "goes", parsed.value.object.get("anything").?.string); +} + +test writeStream { + var out = ArrayList(u8).init(testing.allocator); + defer out.deinit(); + var write_stream = writeStream(out.writer(), 99); + try write_stream.beginObject(); + try write_stream.objectField("foo"); + try write_stream.emitNumber(123); + try write_stream.endObject(); + const expected = + \\{ + \\ "foo": 123 + \\} + ; + try testing.expectEqualSlices(u8, expected, out.items); +} + +test stringify { + var out = ArrayList(u8).init(testing.allocator); + defer out.deinit(); + + const T = struct { a: i32, b: []const u8 }; + try stringify(T{ .a = 123, .b = "xy" }, .{}, out.writer()); + try testing.expectEqualSlices(u8, "{\"a\":123,\"b\":\"xy\"}", out.items); +} + pub const ObjectMap = @import("json/dynamic.zig").ObjectMap; pub const Array = @import("json/dynamic.zig").Array; pub const Value = @import("json/dynamic.zig").Value;