aboutsummaryrefslogtreecommitdiff
path: root/lib/std/json/test.zig
blob: 939f2e194c187a8312e4539372f7cdf58129e9f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
const std = @import("std");
const testing = std.testing;
const parseFromSlice = @import("./static.zig").parseFromSlice;
const validate = @import("./scanner.zig").validate;
const JsonScanner = @import("./scanner.zig").Scanner;
const Value = @import("./dynamic.zig").Value;

// Support for JSONTestSuite.zig
pub fn ok(s: []const u8) !void {
    try testLowLevelScanner(s);
    try testHighLevelDynamicParser(s);
}
pub fn err(s: []const u8) !void {
    try testing.expect(std.meta.isError(testLowLevelScanner(s)));
    try testing.expect(std.meta.isError(testHighLevelDynamicParser(s)));
}
pub fn any(s: []const u8) !void {
    testLowLevelScanner(s) catch {};
    testHighLevelDynamicParser(s) catch {};
}
fn testLowLevelScanner(s: []const u8) !void {
    var scanner = JsonScanner.initCompleteInput(testing.allocator, s);
    defer scanner.deinit();
    while (true) {
        const token = try scanner.next();
        if (token == .end_of_document) break;
    }
}
fn testHighLevelDynamicParser(s: []const u8) !void {
    var parsed = try parseFromSlice(Value, testing.allocator, s, .{});
    defer parsed.deinit();
}

// Additional tests not part of test JSONTestSuite.
test "y_trailing_comma_after_empty" {
    try roundTrip(
        \\{"1":[],"2":{},"3":"4"}
    );
}
test "n_object_closed_missing_value" {
    try err(
        \\{"a":}
    );
}

fn roundTrip(s: []const u8) !void {
    try testing.expect(try validate(testing.allocator, s));

    var parsed = try parseFromSlice(Value, testing.allocator, s, .{});
    defer parsed.deinit();

    var buf: [256]u8 = undefined;
    var fbs = std.io.fixedBufferStream(&buf);
    try parsed.value.jsonStringify(.{}, fbs.writer());

    try testing.expectEqualStrings(s, fbs.getWritten());
}

test "truncated UTF-8 sequence" {
    try err("\"\xc2\"");
    try err("\"\xdf\"");
    try err("\"\xed\xa0\"");
    try err("\"\xf0\x80\"");
    try err("\"\xf0\x80\x80\"");
}

test "invalid continuation byte" {
    try err("\"\xc2\x00\"");
    try err("\"\xc2\x7f\"");
    try err("\"\xc2\xc0\"");
    try err("\"\xc3\xc1\"");
    try err("\"\xc4\xf5\"");
    try err("\"\xc5\xff\"");
    try err("\"\xe4\x80\x00\"");
    try err("\"\xe5\x80\x10\"");
    try err("\"\xe6\x80\xc0\"");
    try err("\"\xe7\x80\xf5\"");
    try err("\"\xe8\x00\x80\"");
    try err("\"\xf2\x00\x80\x80\"");
    try err("\"\xf0\x80\x00\x80\"");
    try err("\"\xf1\x80\xc0\x80\"");
    try err("\"\xf2\x80\x80\x00\"");
    try err("\"\xf3\x80\x80\xc0\"");
    try err("\"\xf4\x80\x80\xf5\"");
}

test "disallowed overlong form" {
    try err("\"\xc0\x80\"");
    try err("\"\xc0\x90\"");
    try err("\"\xc1\x80\"");
    try err("\"\xc1\x90\"");
    try err("\"\xe0\x80\x80\"");
    try err("\"\xf0\x80\x80\x80\"");
}

test "out of UTF-16 range" {
    try err("\"\xf4\x90\x80\x80\"");
    try err("\"\xf5\x80\x80\x80\"");
    try err("\"\xf6\x80\x80\x80\"");
    try err("\"\xf7\x80\x80\x80\"");
    try err("\"\xf8\x80\x80\x80\"");
    try err("\"\xf9\x80\x80\x80\"");
    try err("\"\xfa\x80\x80\x80\"");
    try err("\"\xfb\x80\x80\x80\"");
    try err("\"\xfc\x80\x80\x80\"");
    try err("\"\xfd\x80\x80\x80\"");
    try err("\"\xfe\x80\x80\x80\"");
    try err("\"\xff\x80\x80\x80\"");
}