master
1const std = @import("std");
2const json = std.json;
3const testing = std.testing;
4const parseFromSlice = @import("./static.zig").parseFromSlice;
5const Scanner = @import("./Scanner.zig");
6const Value = @import("./dynamic.zig").Value;
7
8// Support for JSONTestSuite.zig
9pub fn ok(s: []const u8) !void {
10 try testLowLevelScanner(s);
11 try testHighLevelDynamicParser(s);
12}
13pub fn err(s: []const u8) !void {
14 try testing.expect(std.meta.isError(testLowLevelScanner(s)));
15 try testing.expect(std.meta.isError(testHighLevelDynamicParser(s)));
16}
17pub fn any(s: []const u8) !void {
18 testLowLevelScanner(s) catch {};
19 testHighLevelDynamicParser(s) catch {};
20}
21fn testLowLevelScanner(s: []const u8) !void {
22 var scanner = Scanner.initCompleteInput(testing.allocator, s);
23 defer scanner.deinit();
24 while (true) {
25 const token = try scanner.next();
26 if (token == .end_of_document) break;
27 }
28}
29fn testHighLevelDynamicParser(s: []const u8) !void {
30 var parsed = try parseFromSlice(Value, testing.allocator, s, .{
31 .duplicate_field_behavior = .use_first,
32 });
33 defer parsed.deinit();
34}
35
36// Additional tests not part of test JSONTestSuite.
37test "y_trailing_comma_after_empty" {
38 try roundTrip(
39 \\{"1":[],"2":{},"3":"4"}
40 );
41}
42test "n_object_closed_missing_value" {
43 try err(
44 \\{"a":}
45 );
46}
47
48fn roundTrip(s: []const u8) !void {
49 try testing.expect(try Scanner.validate(testing.allocator, s));
50
51 var parsed = try parseFromSlice(Value, testing.allocator, s, .{});
52 defer parsed.deinit();
53
54 const rendered = try json.Stringify.valueAlloc(testing.allocator, parsed.value, .{});
55 defer testing.allocator.free(rendered);
56
57 try testing.expectEqualStrings(s, rendered);
58}
59
60test "truncated UTF-8 sequence" {
61 try err("\"\xc2\"");
62 try err("\"\xdf\"");
63 try err("\"\xed\xa0\"");
64 try err("\"\xf0\x80\"");
65 try err("\"\xf0\x80\x80\"");
66}
67
68test "invalid continuation byte" {
69 try err("\"\xc2\x00\"");
70 try err("\"\xc2\x7f\"");
71 try err("\"\xc2\xc0\"");
72 try err("\"\xc3\xc1\"");
73 try err("\"\xc4\xf5\"");
74 try err("\"\xc5\xff\"");
75 try err("\"\xe4\x80\x00\"");
76 try err("\"\xe5\x80\x10\"");
77 try err("\"\xe6\x80\xc0\"");
78 try err("\"\xe7\x80\xf5\"");
79 try err("\"\xe8\x00\x80\"");
80 try err("\"\xf2\x00\x80\x80\"");
81 try err("\"\xf0\x80\x00\x80\"");
82 try err("\"\xf1\x80\xc0\x80\"");
83 try err("\"\xf2\x80\x80\x00\"");
84 try err("\"\xf3\x80\x80\xc0\"");
85 try err("\"\xf4\x80\x80\xf5\"");
86}
87
88test "disallowed overlong form" {
89 try err("\"\xc0\x80\"");
90 try err("\"\xc0\x90\"");
91 try err("\"\xc1\x80\"");
92 try err("\"\xc1\x90\"");
93 try err("\"\xe0\x80\x80\"");
94 try err("\"\xf0\x80\x80\x80\"");
95}
96
97test "out of UTF-16 range" {
98 try err("\"\xf4\x90\x80\x80\"");
99 try err("\"\xf5\x80\x80\x80\"");
100 try err("\"\xf6\x80\x80\x80\"");
101 try err("\"\xf7\x80\x80\x80\"");
102 try err("\"\xf8\x80\x80\x80\"");
103 try err("\"\xf9\x80\x80\x80\"");
104 try err("\"\xfa\x80\x80\x80\"");
105 try err("\"\xfb\x80\x80\x80\"");
106 try err("\"\xfc\x80\x80\x80\"");
107 try err("\"\xfd\x80\x80\x80\"");
108 try err("\"\xfe\x80\x80\x80\"");
109 try err("\"\xff\x80\x80\x80\"");
110}