Something went wrong. Try again.
fork of gitlab.com/devnw/zig/json for zig 0.17
Something went wrong. Try again.
19 kB · 608 lines
Zig
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609//! Edge Case Tests for JSON Parsing//!//! Tests parsing of valid and invalid JSON from the edge-testdata directory.
const std = @import("std");const json = @import("json");
fn readTestFile(allocator: std.mem.Allocator, path: []const u8) ![]u8 { const io = std.Io.Threaded.global_single_threaded.io(); return try std.Io.Dir.cwd().readFileAlloc(io, path, allocator, .limited(10 * 1024 * 1024));}
// ============================================================// Invalid JSON Tests// ============================================================
test "invalid: missing-colon.json should fail to parse" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/invalid/missing-colon.json"); defer allocator.free(content);
var err = json.ParseError.init(); const result = json.parse(allocator, content, .{}, &err);
try std.testing.expectError(error.JsonParse, result);}
test "invalid: unterminated.json should fail to parse" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/invalid/unterminated.json"); defer allocator.free(content);
var err = json.ParseError.init(); const result = json.parse(allocator, content, .{}, &err);
try std.testing.expectError(error.JsonParse, result);}
test "invalid: binary-data.json should fail to parse" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/invalid/binary-data.json"); defer allocator.free(content);
var err = json.ParseError.init(); const result = json.parse(allocator, content, .{}, &err);
try std.testing.expectError(error.JsonParse, result);}
// ============================================================// Valid JSON Tests - Formatted// ============================================================
test "valid: 64KB.json formatted" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/64KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
// Verify it's an array try std.testing.expect(doc.root == .arr); try std.testing.expect(doc.root.arr.len > 0);}
test "valid: 128KB.json formatted" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/128KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 256KB.json formatted" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/256KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 512KB.json formatted" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/512KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 1MB.json formatted" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/1MB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
// ============================================================// Valid JSON Tests - Minified// ============================================================
test "valid: 64KB-min.json minified" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/64KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 128KB-min.json minified" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/128KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 256KB-min.json minified" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/256KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 512KB-min.json minified" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/512KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
test "valid: 1MB-min.json minified" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/1MB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
try std.testing.expect(doc.root == .arr);}
// ============================================================// Round-trip Tests// ============================================================
test "round-trip: parse and stringify 64KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/64KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
// Stringify const output = try json.stringify(allocator, doc.root); defer allocator.free(output);
// Parse the stringified output var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
// Verify equality try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: parse and stringify 128KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/128KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.stringify(allocator, doc.root); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: parse and stringify 256KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/256KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.stringify(allocator, doc.root); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: parse and stringify 512KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/512KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.stringify(allocator, doc.root); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: parse and stringify 1MB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/1MB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.stringify(allocator, doc.root); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
// ============================================================// Round-trip with encode() function// ============================================================
test "round-trip: parse and encode 64KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/64KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
// Use encode() instead of stringify() const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: parse and encode 128KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/formatted/128KB.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: minified 64KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/64KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: minified 128KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/128KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: minified 256KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/256KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: minified 512KB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/512KB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: minified 1MB" { const allocator = std.testing.allocator;
const content = try readTestFile(allocator, "testdata/edge-testdata/minified/1MB-min.json"); defer allocator.free(content);
var err = json.ParseError.init(); var doc = try json.parse(allocator, content, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
// ============================================================// Round-trip Edge Cases// ============================================================
test "round-trip: unicode strings" { const allocator = std.testing.allocator;
// Use JSON escape sequences for unicode characters const input = "[\"hello\",\"world\",\"\\u00A9\",\"\\uD83D\\uDE00\",\"\\u4E2D\\u6587\"]";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: nested objects and arrays" { const allocator = std.testing.allocator;
const input = \\{"a":{"b":{"c":[1,2,{"d":[3,4,5]}]}},"e":[{"f":1},{"g":2}]} ;
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: all value types" { const allocator = std.testing.allocator;
const input = \\{"null":null,"bool_true":true,"bool_false":false,"int":42,"neg_int":-123,"float":3.14159,"exp":1.5e10,"string":"hello\nworld","array":[1,2,3],"object":{"key":"value"}} ;
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: escape sequences" { const allocator = std.testing.allocator;
const input = "[\"\\\"quoted\\\"\",\"back\\\\slash\",\"new\\nline\",\"tab\\there\",\"return\\rhere\"]";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: empty containers" { const allocator = std.testing.allocator;
const input = "{\"empty_array\":[],\"empty_object\":{}}";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: number precision" { const allocator = std.testing.allocator;
const input = "[0,1,-1,123456789012345678901234567890,0.1,0.123456789,1e100,1.5e-10]";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: pretty print preserves values" { const allocator = std.testing.allocator;
const input = "{\"a\":1,\"b\":[2,3],\"c\":{\"d\":4}}";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
// Encode with pretty printing const output = try json.encode(allocator, doc.root, json.encode_mod.pretty_2); defer allocator.free(output);
// Verify output contains newlines (is pretty-printed) try std.testing.expect(std.mem.indexOf(u8, output, "\n") != null);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: deeply nested structure" { const allocator = std.testing.allocator;
// Create a deeply nested structure const input = "[[[[[[[[[[1]]]]]]]]]]";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const output = try json.encode(allocator, doc.root, .{}); defer allocator.free(output);
var doc2 = try json.parse(allocator, output, .{}, &err); defer doc2.deinit();
try std.testing.expect(doc.root.eql(doc2.root));}
test "round-trip: stringify vs encode equivalence" { const allocator = std.testing.allocator;
const input = "{\"key\":\"value\",\"num\":42,\"arr\":[1,2,3]}";
var err = json.ParseError.init(); var doc = try json.parse(allocator, input, .{}, &err); defer doc.deinit();
const stringify_output = try json.stringify(allocator, doc.root); defer allocator.free(stringify_output);
const encode_output = try json.encode(allocator, doc.root, .{}); defer allocator.free(encode_output);
// Both should produce the same minified output try std.testing.expectEqualStrings(stringify_output, encode_output);}