aboutsummaryrefslogtreecommitdiff
path: root/lib/std/json.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-06-03 16:02:23 +0300
committerVeikka Tuominen <git@vexu.eu>2022-06-03 20:21:20 +0300
commit6d44c0a16c90a13cb3507751e2015edf51c642cf (patch)
tree6dfa9b43c776a3a34fad7aedada8b76b5eac5ac2 /lib/std/json.zig
parent1a7b4ddeaedb81255cfa8907958c3cf09dd340ee (diff)
downloadzig-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.zig221
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.