aboutsummaryrefslogtreecommitdiff
path: root/lib/std/json/dynamic_test.zig
diff options
context:
space:
mode:
authorLoris Cro <kappaloris@gmail.com>2023-06-18 09:06:40 +0200
committerGitHub <noreply@github.com>2023-06-18 09:06:40 +0200
commit216ef10dc471e4db60a30208be178d6c59efeaaf (patch)
tree8c239dab283ae9cb3b7fe099bae240bcc53f894e /lib/std/json/dynamic_test.zig
parent0fc1d396495c1ab482197021dedac8bea3f9401c (diff)
parent729a051e9e38674233190aea23c0ac8c134f2d67 (diff)
downloadzig-216ef10dc471e4db60a30208be178d6c59efeaaf.tar.gz
zig-216ef10dc471e4db60a30208be178d6c59efeaaf.zip
Merge branch 'master' into autodoc-searchkey
Diffstat (limited to 'lib/std/json/dynamic_test.zig')
-rw-r--r--lib/std/json/dynamic_test.zig285
1 files changed, 285 insertions, 0 deletions
diff --git a/lib/std/json/dynamic_test.zig b/lib/std/json/dynamic_test.zig
new file mode 100644
index 0000000000..f20098f2d7
--- /dev/null
+++ b/lib/std/json/dynamic_test.zig
@@ -0,0 +1,285 @@
+const std = @import("std");
+const mem = std.mem;
+const testing = std.testing;
+
+const ObjectMap = @import("dynamic.zig").ObjectMap;
+const Array = @import("dynamic.zig").Array;
+const Value = @import("dynamic.zig").Value;
+const Parser = @import("dynamic.zig").Parser;
+
+test "json.parser.dynamic" {
+ var p = Parser.init(testing.allocator, .alloc_if_needed);
+ defer p.deinit();
+
+ const s =
+ \\{
+ \\ "Image": {
+ \\ "Width": 800,
+ \\ "Height": 600,
+ \\ "Title": "View from 15th Floor",
+ \\ "Thumbnail": {
+ \\ "Url": "http://www.example.com/image/481989943",
+ \\ "Height": 125,
+ \\ "Width": 100
+ \\ },
+ \\ "Animated" : false,
+ \\ "IDs": [116, 943, 234, 38793],
+ \\ "ArrayOfObject": [{"n": "m"}],
+ \\ "double": 1.3412,
+ \\ "LargeInt": 18446744073709551615
+ \\ }
+ \\}
+ ;
+
+ var tree = try p.parse(s);
+ defer tree.deinit();
+
+ var root = tree.root;
+
+ var image = root.object.get("Image").?;
+
+ const width = image.object.get("Width").?;
+ try testing.expect(width.integer == 800);
+
+ const height = image.object.get("Height").?;
+ try testing.expect(height.integer == 600);
+
+ const title = image.object.get("Title").?;
+ try testing.expect(mem.eql(u8, title.string, "View from 15th Floor"));
+
+ const animated = image.object.get("Animated").?;
+ try testing.expect(animated.bool == false);
+
+ const array_of_object = image.object.get("ArrayOfObject").?;
+ try testing.expect(array_of_object.array.items.len == 1);
+
+ const obj0 = array_of_object.array.items[0].object.get("n").?;
+ try testing.expect(mem.eql(u8, obj0.string, "m"));
+
+ const double = image.object.get("double").?;
+ try testing.expect(double.float == 1.3412);
+
+ const large_int = image.object.get("LargeInt").?;
+ try testing.expect(mem.eql(u8, large_int.number_string, "18446744073709551615"));
+}
+
+const writeStream = @import("./write_stream.zig").writeStream;
+test "write json then parse it" {
+ var out_buffer: [1000]u8 = undefined;
+
+ var fixed_buffer_stream = std.io.fixedBufferStream(&out_buffer);
+ const out_stream = fixed_buffer_stream.writer();
+ var jw = writeStream(out_stream, 4);
+
+ try jw.beginObject();
+
+ try jw.objectField("f");
+ try jw.emitBool(false);
+
+ try jw.objectField("t");
+ try jw.emitBool(true);
+
+ try jw.objectField("int");
+ try jw.emitNumber(1234);
+
+ try jw.objectField("array");
+ try jw.beginArray();
+
+ try jw.arrayElem();
+ try jw.emitNull();
+
+ try jw.arrayElem();
+ try jw.emitNumber(12.34);
+
+ try jw.endArray();
+
+ try jw.objectField("str");
+ try jw.emitString("hello");
+
+ try jw.endObject();
+
+ var parser = Parser.init(testing.allocator, .alloc_if_needed);
+ defer parser.deinit();
+ var tree = try parser.parse(fixed_buffer_stream.getWritten());
+ defer tree.deinit();
+
+ try testing.expect(tree.root.object.get("f").?.bool == false);
+ try testing.expect(tree.root.object.get("t").?.bool == true);
+ try testing.expect(tree.root.object.get("int").?.integer == 1234);
+ try testing.expect(tree.root.object.get("array").?.array.items[0].null == {});
+ try testing.expect(tree.root.object.get("array").?.array.items[1].float == 12.34);
+ try testing.expect(mem.eql(u8, tree.root.object.get("str").?.string, "hello"));
+}
+
+fn testParse(arena_allocator: std.mem.Allocator, json_str: []const u8) !Value {
+ var p = Parser.init(arena_allocator, .alloc_if_needed);
+ return (try p.parse(json_str)).root;
+}
+
+test "parsing empty string gives appropriate error" {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ try testing.expectError(error.UnexpectedEndOfInput, testParse(arena_allocator.allocator(), ""));
+}
+
+test "parse tree should not contain dangling pointers" {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+
+ var p = Parser.init(arena_allocator.allocator(), .alloc_if_needed);
+ defer p.deinit();
+
+ var tree = try p.parse("[]");
+ defer tree.deinit();
+
+ // Allocation should succeed
+ var i: usize = 0;
+ while (i < 100) : (i += 1) {
+ try tree.root.array.append(Value{ .integer = 100 });
+ }
+ try testing.expectEqual(tree.root.array.items.len, 100);
+}
+
+test "integer after float has proper type" {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ const parsed = try testParse(arena_allocator.allocator(),
+ \\{
+ \\ "float": 3.14,
+ \\ "ints": [1, 2, 3]
+ \\}
+ );
+ try std.testing.expect(parsed.object.get("ints").?.array.items[0] == .integer);
+}
+
+test "escaped characters" {
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ const input =
+ \\{
+ \\ "backslash": "\\",
+ \\ "forwardslash": "\/",
+ \\ "newline": "\n",
+ \\ "carriagereturn": "\r",
+ \\ "tab": "\t",
+ \\ "formfeed": "\f",
+ \\ "backspace": "\b",
+ \\ "doublequote": "\"",
+ \\ "unicode": "\u0105",
+ \\ "surrogatepair": "\ud83d\ude02"
+ \\}
+ ;
+
+ const obj = (try testParse(arena_allocator.allocator(), input)).object;
+
+ try testing.expectEqualSlices(u8, obj.get("backslash").?.string, "\\");
+ try testing.expectEqualSlices(u8, obj.get("forwardslash").?.string, "/");
+ try testing.expectEqualSlices(u8, obj.get("newline").?.string, "\n");
+ try testing.expectEqualSlices(u8, obj.get("carriagereturn").?.string, "\r");
+ try testing.expectEqualSlices(u8, obj.get("tab").?.string, "\t");
+ try testing.expectEqualSlices(u8, obj.get("formfeed").?.string, "\x0C");
+ try testing.expectEqualSlices(u8, obj.get("backspace").?.string, "\x08");
+ try testing.expectEqualSlices(u8, obj.get("doublequote").?.string, "\"");
+ try testing.expectEqualSlices(u8, obj.get("unicode").?.string, "ą");
+ try testing.expectEqualSlices(u8, obj.get("surrogatepair").?.string, "😂");
+}
+
+test "string copy option" {
+ const input =
+ \\{
+ \\ "noescape": "aą😂",
+ \\ "simple": "\\\/\n\r\t\f\b\"",
+ \\ "unicode": "\u0105",
+ \\ "surrogatepair": "\ud83d\ude02"
+ \\}
+ ;
+
+ var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
+ defer arena_allocator.deinit();
+ const allocator = arena_allocator.allocator();
+
+ var parser = Parser.init(allocator, .alloc_if_needed);
+ const tree_nocopy = try parser.parse(input);
+ const obj_nocopy = tree_nocopy.root.object;
+
+ parser = Parser.init(allocator, .alloc_always);
+ const tree_copy = try parser.parse(input);
+ const obj_copy = tree_copy.root.object;
+
+ for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| {
+ try testing.expectEqualSlices(u8, obj_nocopy.get(field_name).?.string, obj_copy.get(field_name).?.string);
+ }
+
+ const nocopy_addr = &obj_nocopy.get("noescape").?.string[0];
+ const copy_addr = &obj_copy.get("noescape").?.string[0];
+
+ var found_nocopy = false;
+ for (input, 0..) |_, index| {
+ try testing.expect(copy_addr != &input[index]);
+ if (nocopy_addr == &input[index]) {
+ found_nocopy = true;
+ }
+ }
+ try testing.expect(found_nocopy);
+}
+
+test "Value.jsonStringify" {
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try @as(Value, .null).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "null");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try (Value{ .bool = true }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "true");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try (Value{ .integer = 42 }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "42");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try (Value{ .number_string = "43" }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "43");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try (Value{ .float = 42 }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "4.2e+01");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ try (Value{ .string = "weeee" }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "\"weeee\"");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ var vals = [_]Value{
+ .{ .integer = 1 },
+ .{ .integer = 2 },
+ .{ .number_string = "3" },
+ };
+ try (Value{
+ .array = Array.fromOwnedSlice(undefined, &vals),
+ }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "[1,2,3]");
+ }
+ {
+ var buffer: [10]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buffer);
+ var obj = ObjectMap.init(testing.allocator);
+ defer obj.deinit();
+ try obj.putNoClobber("a", .{ .string = "b" });
+ try (Value{ .object = obj }).jsonStringify(.{}, fbs.writer());
+ try testing.expectEqualSlices(u8, fbs.getWritten(), "{\"a\":\"b\"}");
+ }
+}