diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-06-03 16:02:23 +0300 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-06-03 20:21:20 +0300 |
| commit | 6d44c0a16c90a13cb3507751e2015edf51c642cf (patch) | |
| tree | 6dfa9b43c776a3a34fad7aedada8b76b5eac5ac2 /lib/std/json.zig | |
| parent | 1a7b4ddeaedb81255cfa8907958c3cf09dd340ee (diff) | |
| download | zig-6d44c0a16c90a13cb3507751e2015edf51c642cf.tar.gz zig-6d44c0a16c90a13cb3507751e2015edf51c642cf.zip | |
std: update tests to stage2 semantics
Diffstat (limited to 'lib/std/json.zig')
| -rw-r--r-- | lib/std/json.zig | 221 |
1 files changed, 136 insertions, 85 deletions
diff --git a/lib/std/json.zig b/lib/std/json.zig index 2650b98822..cc82c1d0a5 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1506,42 +1506,46 @@ fn skipValue(tokens: *TokenStream) SkipValueError!void { } test "skipValue" { - try skipValue(&TokenStream.init("false")); - try skipValue(&TokenStream.init("true")); - try skipValue(&TokenStream.init("null")); - try skipValue(&TokenStream.init("42")); - try skipValue(&TokenStream.init("42.0")); - try skipValue(&TokenStream.init("\"foo\"")); - try skipValue(&TokenStream.init("[101, 111, 121]")); - try skipValue(&TokenStream.init("{}")); - try skipValue(&TokenStream.init("{\"foo\": \"bar\"}")); + var ts = TokenStream.init("false"); + try skipValue(&ts); + ts = TokenStream.init("true"); + try skipValue(&ts); + ts = TokenStream.init("null"); + try skipValue(&ts); + ts = TokenStream.init("42"); + try skipValue(&ts); + ts = TokenStream.init("42.0"); + try skipValue(&ts); + ts = TokenStream.init("\"foo\""); + try skipValue(&ts); + ts = TokenStream.init("[101, 111, 121]"); + try skipValue(&ts); + ts = TokenStream.init("{}"); + try skipValue(&ts); + ts = TokenStream.init("{\"foo\": \"bar\"}"); + try skipValue(&ts); { // An absurd number of nestings const nestings = StreamingParser.default_max_nestings + 1; - try testing.expectError( - error.TooManyNestedItems, - skipValue(&TokenStream.init("[" ** nestings ++ "]" ** nestings)), - ); + ts = TokenStream.init("[" ** nestings ++ "]" ** nestings); + try testing.expectError(error.TooManyNestedItems, skipValue(&ts)); } { // Would a number token cause problems in a deeply-nested array? const nestings = StreamingParser.default_max_nestings; const deeply_nested_array = "[" ** nestings ++ "0.118, 999, 881.99, 911.9, 725, 3" ++ "]" ** nestings; - try skipValue(&TokenStream.init(deeply_nested_array)); + ts = TokenStream.init(deeply_nested_array); + try skipValue(&ts); - try testing.expectError( - error.TooManyNestedItems, - skipValue(&TokenStream.init("[" ++ deeply_nested_array ++ "]")), - ); + ts = TokenStream.init("[" ++ deeply_nested_array ++ "]"); + try testing.expectError(error.TooManyNestedItems, skipValue(&ts)); } // Mismatched brace/square bracket - try testing.expectError( - error.UnexpectedClosingBrace, - skipValue(&TokenStream.init("[102, 111, 111}")), - ); + ts = TokenStream.init("[102, 111, 111}"); + try testing.expectError(error.UnexpectedClosingBrace, skipValue(&ts)); { // should fail if no value found (e.g. immediate close of object) var empty_object = TokenStream.init("{}"); @@ -1980,18 +1984,29 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { } test "parse" { - try testing.expectEqual(false, try parse(bool, &TokenStream.init("false"), ParseOptions{})); - try testing.expectEqual(true, try parse(bool, &TokenStream.init("true"), ParseOptions{})); - try testing.expectEqual(@as(u1, 1), try parse(u1, &TokenStream.init("1"), ParseOptions{})); - try testing.expectError(error.Overflow, parse(u1, &TokenStream.init("50"), ParseOptions{})); - try testing.expectEqual(@as(u64, 42), try parse(u64, &TokenStream.init("42"), ParseOptions{})); - try testing.expectEqual(@as(f64, 42), try parse(f64, &TokenStream.init("42.0"), ParseOptions{})); - try testing.expectEqual(@as(?bool, null), try parse(?bool, &TokenStream.init("null"), ParseOptions{})); - try testing.expectEqual(@as(?bool, true), try parse(?bool, &TokenStream.init("true"), ParseOptions{})); - - try testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &TokenStream.init("\"foo\""), ParseOptions{})); - try testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &TokenStream.init("[102, 111, 111]"), ParseOptions{})); - try testing.expectEqual(@as([0]u8, undefined), try parse([0]u8, &TokenStream.init("[]"), ParseOptions{})); + var ts = TokenStream.init("false"); + try testing.expectEqual(false, try parse(bool, &ts, ParseOptions{})); + ts = TokenStream.init("true"); + try testing.expectEqual(true, try parse(bool, &ts, ParseOptions{})); + ts = TokenStream.init("1"); + try testing.expectEqual(@as(u1, 1), try parse(u1, &ts, ParseOptions{})); + ts = TokenStream.init("50"); + try testing.expectError(error.Overflow, parse(u1, &ts, ParseOptions{})); + ts = TokenStream.init("42"); + try testing.expectEqual(@as(u64, 42), try parse(u64, &ts, ParseOptions{})); + ts = TokenStream.init("42.0"); + try testing.expectEqual(@as(f64, 42), try parse(f64, &ts, ParseOptions{})); + ts = TokenStream.init("null"); + try testing.expectEqual(@as(?bool, null), try parse(?bool, &ts, ParseOptions{})); + ts = TokenStream.init("true"); + try testing.expectEqual(@as(?bool, true), try parse(?bool, &ts, ParseOptions{})); + + ts = TokenStream.init("\"foo\""); + try testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &ts, ParseOptions{})); + ts = TokenStream.init("[102, 111, 111]"); + try testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &ts, ParseOptions{})); + ts = TokenStream.init("[]"); + try testing.expectEqual(@as([0]u8, undefined), try parse([0]u8, &ts, ParseOptions{})); } test "parse into enum" { @@ -2000,36 +2015,48 @@ test "parse into enum" { Bar, @"with\\escape", }; - try testing.expectEqual(@as(T, .Foo), try parse(T, &TokenStream.init("\"Foo\""), ParseOptions{})); - try testing.expectEqual(@as(T, .Foo), try parse(T, &TokenStream.init("42"), ParseOptions{})); - try testing.expectEqual(@as(T, .@"with\\escape"), try parse(T, &TokenStream.init("\"with\\\\escape\""), ParseOptions{})); - try testing.expectError(error.InvalidEnumTag, parse(T, &TokenStream.init("5"), ParseOptions{})); - try testing.expectError(error.InvalidEnumTag, parse(T, &TokenStream.init("\"Qux\""), ParseOptions{})); + var ts = TokenStream.init("\"Foo\""); + try testing.expectEqual(@as(T, .Foo), try parse(T, &ts, ParseOptions{})); + ts = TokenStream.init("42"); + try testing.expectEqual(@as(T, .Foo), try parse(T, &ts, ParseOptions{})); + ts = TokenStream.init("\"with\\\\escape\""); + try testing.expectEqual(@as(T, .@"with\\escape"), try parse(T, &ts, ParseOptions{})); + ts = TokenStream.init("5"); + try testing.expectError(error.InvalidEnumTag, parse(T, &ts, ParseOptions{})); + ts = TokenStream.init("\"Qux\""); + try testing.expectError(error.InvalidEnumTag, parse(T, &ts, ParseOptions{})); } test "parse with trailing data" { - try testing.expectEqual(false, try parse(bool, &TokenStream.init("falsed"), ParseOptions{ .allow_trailing_data = true })); - try testing.expectError(error.InvalidTopLevelTrailing, parse(bool, &TokenStream.init("falsed"), ParseOptions{ .allow_trailing_data = false })); + var ts = TokenStream.init("falsed"); + try testing.expectEqual(false, try parse(bool, &ts, ParseOptions{ .allow_trailing_data = true })); + ts = TokenStream.init("falsed"); + try testing.expectError(error.InvalidTopLevelTrailing, parse(bool, &ts, ParseOptions{ .allow_trailing_data = false })); // trailing whitespace is okay - try testing.expectEqual(false, try parse(bool, &TokenStream.init("false \n"), ParseOptions{ .allow_trailing_data = false })); + ts = TokenStream.init("false \n"); + try testing.expectEqual(false, try parse(bool, &ts, ParseOptions{ .allow_trailing_data = false })); } test "parse into that allocates a slice" { - try testing.expectError(error.AllocatorRequired, parse([]u8, &TokenStream.init("\"foo\""), ParseOptions{})); + var ts = TokenStream.init("\"foo\""); + try testing.expectError(error.AllocatorRequired, parse([]u8, &ts, ParseOptions{})); const options = ParseOptions{ .allocator = testing.allocator }; { - const r = try parse([]u8, &TokenStream.init("\"foo\""), options); + ts = TokenStream.init("\"foo\""); + const r = try parse([]u8, &ts, options); defer parseFree([]u8, r, options); try testing.expectEqualSlices(u8, "foo", r); } { - const r = try parse([]u8, &TokenStream.init("[102, 111, 111]"), options); + ts = TokenStream.init("[102, 111, 111]"); + const r = try parse([]u8, &ts, options); defer parseFree([]u8, r, options); try testing.expectEqualSlices(u8, "foo", r); } { - const r = try parse([]u8, &TokenStream.init("\"with\\\\escape\""), options); + ts = TokenStream.init("\"with\\\\escape\""); + const r = try parse([]u8, &ts, options); defer parseFree([]u8, r, options); try testing.expectEqualSlices(u8, "with\\escape", r); } @@ -2042,7 +2069,8 @@ test "parse into tagged union" { float: f64, string: []const u8, }; - try testing.expectEqual(T{ .float = 1.5 }, try parse(T, &TokenStream.init("1.5"), ParseOptions{})); + var ts = TokenStream.init("1.5"); + try testing.expectEqual(T{ .float = 1.5 }, try parse(T, &ts, ParseOptions{})); } { // failing allocations should be bubbled up instantly without trying next member @@ -2053,7 +2081,8 @@ test "parse into tagged union" { string: []const u8, array: [3]u8, }; - try testing.expectError(error.OutOfMemory, parse(T, &TokenStream.init("[1,2,3]"), options)); + var ts = TokenStream.init("[1,2,3]"); + try testing.expectError(error.OutOfMemory, parse(T, &ts, options)); } { @@ -2062,7 +2091,8 @@ test "parse into tagged union" { x: u8, y: u8, }; - try testing.expectEqual(T{ .x = 42 }, try parse(T, &TokenStream.init("42"), ParseOptions{})); + var ts = TokenStream.init("42"); + try testing.expectEqual(T{ .x = 42 }, try parse(T, &ts, ParseOptions{})); } { // needs to back out when first union member doesn't match @@ -2070,7 +2100,8 @@ test "parse into tagged union" { A: struct { x: u32 }, B: struct { y: u32 }, }; - try testing.expectEqual(T{ .B = .{ .y = 42 } }, try parse(T, &TokenStream.init("{\"y\":42}"), ParseOptions{})); + var ts = TokenStream.init("{\"y\":42}"); + try testing.expectEqual(T{ .B = .{ .y = 42 } }, try parse(T, &ts, ParseOptions{})); } } @@ -2080,7 +2111,8 @@ test "parse union bubbles up AllocatorRequired" { string: []const u8, int: i32, }; - try testing.expectError(error.AllocatorRequired, parse(T, &TokenStream.init("42"), ParseOptions{})); + var ts = TokenStream.init("42"); + try testing.expectError(error.AllocatorRequired, parse(T, &ts, ParseOptions{})); } { // string member not first in union (and matching) @@ -2089,7 +2121,8 @@ test "parse union bubbles up AllocatorRequired" { float: f64, string: []const u8, }; - try testing.expectError(error.AllocatorRequired, parse(T, &TokenStream.init("\"foo\""), ParseOptions{})); + var ts = TokenStream.init("\"foo\""); + try testing.expectError(error.AllocatorRequired, parse(T, &ts, ParseOptions{})); } } @@ -2102,7 +2135,8 @@ test "parseFree descends into tagged union" { string: []const u8, }; // use a string with unicode escape so we know result can't be a reference to global constant - const r = try parse(T, &TokenStream.init("\"with\\u0105unicode\""), options); + var ts = TokenStream.init("\"with\\u0105unicode\""); + const r = try parse(T, &ts, options); try testing.expectEqual(std.meta.Tag(T).string, @as(std.meta.Tag(T), r)); try testing.expectEqualSlices(u8, "withÄ…unicode", r.string); try testing.expectEqual(@as(usize, 0), fail_alloc.deallocations); @@ -2116,12 +2150,13 @@ test "parse with comptime field" { comptime a: i32 = 0, b: bool, }; - try testing.expectEqual(T{ .a = 0, .b = true }, try parse(T, &TokenStream.init( + var ts = TokenStream.init( \\{ \\ "a": 0, \\ "b": true \\} - ), ParseOptions{})); + ); + try testing.expectEqual(T{ .a = 0, .b = true }, try parse(T, &ts, ParseOptions{})); } { // string comptime values currently require an allocator @@ -2140,12 +2175,13 @@ test "parse with comptime field" { .allocator = std.testing.allocator, }; - const r = try parse(T, &TokenStream.init( + var ts = TokenStream.init( \\{ \\ "kind": "float", \\ "b": 1.0 \\} - ), options); + ); + const r = try parse(T, &ts, options); // check that parseFree doesn't try to free comptime fields parseFree(T, r, options); @@ -2154,7 +2190,8 @@ test "parse with comptime field" { test "parse into struct with no fields" { const T = struct {}; - try testing.expectEqual(T{}, try parse(T, &TokenStream.init("{}"), ParseOptions{})); + var ts = TokenStream.init("{}"); + try testing.expectEqual(T{}, try parse(T, &ts, ParseOptions{})); } test "parse into struct with misc fields" { @@ -2186,7 +2223,7 @@ test "parse into struct with misc fields" { string: []const u8, }; }; - const r = try parse(T, &TokenStream.init( + var ts = TokenStream.init( \\{ \\ "int": 420, \\ "float": 3.14, @@ -2208,7 +2245,8 @@ test "parse into struct with misc fields" { \\ ], \\ "a_union": 100000 \\} - ), options); + ); + const r = try parse(T, &ts, options); defer parseFree(T, r, options); try testing.expectEqual(@as(i64, 420), r.int); try testing.expectEqual(@as(f64, 3.14), r.float); @@ -2239,14 +2277,15 @@ test "parse into struct with strings and arrays with sentinels" { data: [:99]const i32, simple_data: []const i32, }; - const r = try parse(T, &TokenStream.init( + var ts = TokenStream.init( \\{ \\ "language": "zig", \\ "language_without_sentinel": "zig again!", \\ "data": [1, 2, 3], \\ "simple_data": [4, 5, 6] \\} - ), options); + ); + const r = try parse(T, &ts, options); defer parseFree(T, r, options); try testing.expectEqualSentinel(u8, 0, "zig", r.language); @@ -2275,19 +2314,25 @@ test "parse into struct with duplicate field" { const T1 = struct { a: *u64 }; // both .UseFirst and .UseLast should fail because second "a" value isn't a u64 - try testing.expectError(error.InvalidNumber, parse(T1, &TokenStream.init(str), options_first)); - try testing.expectError(error.InvalidNumber, parse(T1, &TokenStream.init(str), options_last)); + var ts = TokenStream.init(str); + try testing.expectError(error.InvalidNumber, parse(T1, &ts, options_first)); + ts = TokenStream.init(str); + try testing.expectError(error.InvalidNumber, parse(T1, &ts, options_last)); const T2 = struct { a: f64 }; - try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &TokenStream.init(str), options_first)); - try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options_last)); + ts = TokenStream.init(str); + try testing.expectEqual(T2{ .a = 1.0 }, try parse(T2, &ts, options_first)); + ts = TokenStream.init(str); + try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &ts, options_last)); const T3 = struct { comptime a: f64 = 1.0 }; // .UseFirst should succeed because second "a" value is unconditionally ignored (even though != 1.0) const t3 = T3{ .a = 1.0 }; - try testing.expectEqual(t3, try parse(T3, &TokenStream.init(str), options_first)); + ts = TokenStream.init(str); + try testing.expectEqual(t3, try parse(T3, &ts, options_first)); // .UseLast should fail because second "a" value is 0.25 which is not equal to default value of 1.0 - try testing.expectError(error.UnexpectedValue, parse(T3, &TokenStream.init(str), options_last)); + ts = TokenStream.init(str); + try testing.expectError(error.UnexpectedValue, parse(T3, &ts, options_last)); } test "parse into struct ignoring unknown fields" { @@ -2301,7 +2346,7 @@ test "parse into struct ignoring unknown fields" { .ignore_unknown_fields = true, }; - const r = try parse(T, &std.json.TokenStream.init( + var ts = TokenStream.init( \\{ \\ "int": 420, \\ "float": 3.14, @@ -2323,7 +2368,8 @@ test "parse into struct ignoring unknown fields" { \\ "a_union": 100000, \\ "language": "zig" \\} - ), ops); + ); + const r = try parse(T, &ts, ops); defer parseFree(T, r, ops); try testing.expectEqual(@as(i64, 420), r.int); @@ -2341,7 +2387,8 @@ test "parse into recursive union definition" { }; const ops = ParseOptions{ .allocator = testing.allocator }; - const r = try parse(T, &std.json.TokenStream.init("{\"values\":[58]}"), ops); + var ts = TokenStream.init("{\"values\":[58]}"); + const r = try parse(T, &ts, ops); defer parseFree(T, r, ops); try testing.expectEqual(@as(i64, 58), r.values.array[0].integer); @@ -2363,7 +2410,8 @@ test "parse into double recursive union definition" { }; const ops = ParseOptions{ .allocator = testing.allocator }; - const r = try parse(T, &std.json.TokenStream.init("{\"values\":[[58]]}"), ops); + var ts = TokenStream.init("{\"values\":[[58]]}"); + const r = try parse(T, &ts, ops); defer parseFree(T, r, ops); try testing.expectEqual(@as(i64, 58), r.values.array[0].array[0].integer); @@ -2806,10 +2854,13 @@ test "integer after float has proper type" { test "parse exponential into int" { const T = struct { int: i64 }; - const r = try parse(T, &TokenStream.init("{ \"int\": 4.2e2 }"), ParseOptions{}); + var ts = TokenStream.init("{ \"int\": 4.2e2 }"); + const r = try parse(T, &ts, ParseOptions{}); try testing.expectEqual(@as(i64, 420), r.int); - try testing.expectError(error.InvalidNumber, parse(T, &TokenStream.init("{ \"int\": 0.042e2 }"), ParseOptions{})); - try testing.expectError(error.Overflow, parse(T, &TokenStream.init("{ \"int\": 18446744073709551616.0 }"), ParseOptions{})); + ts = TokenStream.init("{ \"int\": 0.042e2 }"); + try testing.expectError(error.InvalidNumber, parse(T, &ts, ParseOptions{})); + ts = TokenStream.init("{ \"int\": 18446744073709551616.0 }"); + try testing.expectError(error.Overflow, parse(T, &ts, ParseOptions{})); } test "escaped characters" { @@ -2858,10 +2909,12 @@ test "string copy option" { defer arena_allocator.deinit(); const allocator = arena_allocator.allocator(); - const tree_nocopy = try Parser.init(allocator, false).parse(input); + var parser = Parser.init(allocator, false); + const tree_nocopy = try parser.parse(input); const obj_nocopy = tree_nocopy.root.Object; - const tree_copy = try Parser.init(allocator, true).parse(input); + parser = Parser.init(allocator, true); + const tree_copy = try parser.parse(input); const obj_copy = tree_copy.root.Object; for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| { @@ -3376,14 +3429,12 @@ test "stringify null optional fields" { StringifyOptions{ .emit_null_optional_fields = false }, ); - try std.testing.expect(try parsesTo( - MyStruct, - MyStruct{}, - &TokenStream.init( - \\{"required":"something","another_required":"something else"} - ), - .{ .allocator = std.testing.allocator }, - )); + var ts = TokenStream.init( + \\{"required":"something","another_required":"something else"} + ); + try std.testing.expect(try parsesTo(MyStruct, MyStruct{}, &ts, .{ + .allocator = std.testing.allocator, + })); } // Same as `stringify` but accepts an Allocator and stores result in dynamically allocated memory instead of using a Writer. |
