Add tests for deserialization

This commit is contained in:
jaina heartles 2022-11-30 20:01:17 -08:00
parent aa632ace8b
commit c7dcded04a

View file

@ -207,7 +207,7 @@ fn DeserializerContext(comptime Result: type, comptime From: type, comptime Cont
}
pub fn finish(self: *@This()) !Result {
return (try self.deserialize(Result, &.{})).?;
return (try self.deserialize(Result, &.{})) orelse error.MissingField;
}
fn getSerializedField(self: *@This(), comptime field_ref: FieldRef) ?From {
@ -233,7 +233,7 @@ fn DeserializerContext(comptime Result: type, comptime From: type, comptime Cont
const maybe_value = try self.deserialize(F, new_field_ref);
if (maybe_value) |value| {
// TODO: errdefer cleanup
if (result != null) return error.DuplicateUnionField;
if (result != null) return error.DuplicateUnionMember;
result = @unionInit(T, field.name, value);
}
}
@ -258,12 +258,10 @@ fn DeserializerContext(comptime Result: type, comptime From: type, comptime Cont
}
} else {
any_missing = true;
std.debug.print("\nMissing field {s}\n", .{util.comptimeJoin(".", new_field_ref)});
//return error.MissingStructField;
}
}
if (any_missing) {
return if (any_explicit) error.MissingStructField else null;
return if (any_explicit) error.MissingField else null;
}
return result;
@ -292,85 +290,110 @@ const bool_map = std.ComptimeStringMap(bool, .{
.{ "0", false },
});
test {
const T = struct {
foo: usize,
bar: bool,
};
const TDefault = struct {
foo: usize = 0,
bar: bool = false,
};
_ = TDefault;
test "Deserializer" {
// Happy case - simple
{
const T = struct { foo: usize, bar: bool };
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo", "123");
try ds.setSerializedField("bar", "true");
try std.testing.expectEqual(T{ .foo = 123, .bar = true }, try ds.finish());
}
// Returns error if nonexistent field set
{
const T = struct { foo: usize, bar: bool };
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo", "123");
try std.testing.expectError(error.MissingStructField, ds.finish());
try std.testing.expectError(error.UnknownField, ds.setSerializedField("baz", "123"));
}
//const int = Intermediary(T, QueryStringOptions){
//.age = "123",
//.@"sub_struct.foo" = "abc",
//.@"sub_struct.bar" = "abc",
//.@"foo_union" = "abc",
//};
//std.debug.print("{any}\n", .{int});
//std.debug.print("{any}\n", .{deserialize(T, QueryStringOptions, &.{}, int)});
// Substruct dereferencing
{
const T = struct {
foo: struct { bar: bool, baz: bool },
};
//const int2 = Intermediary(T, FormDataOptions){
//.age = .{ .value = "123" },
//.@"sub_struct.foo" = .{ .value = "123" },
//.@"sub_struct.bar" = .{ .value = "123" },
////.@"foo_union" = .{
//.value = "abc",
//},
//};
//std.debug.print("{any}\n", .{int2});
//
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo.bar", "true");
try ds.setSerializedField("foo.baz", "true");
try std.testing.expectEqual(T{ .foo = .{ .bar = true, .baz = true } }, try ds.finish());
}
// const T = struct {
// age: usize,
// sub_struct: ?struct {
// x: union(enum) {
// foo: []const u8,
// bar: []const u8,
// },
// },
// sub_union: union(enum) {
// foo_union: []const u8,
// bar_union: []const u8,
// },
// time: ?@import("./DateTime.zig"),
// };
// inline for (comptime getRecursiveFieldList(T, &.{}, .{})) |list| {
// std.debug.print("{s}\n", .{util.comptimeJoin(".", list)});
// }
// // var ds = Deserializer(struct {
// age: usize,
// sub_struct: ?struct {
// x: union(enum) {
// foo: []const u8,
// bar: []const u8,
// },
// },
// sub_union: union(enum) {
// foo_union: []const u8,
// bar_union: []const u8,
// },
// time: ?@import("./DateTime.zig"),
// }, []const u8){ .context = .{} };
//try ds.setSerializedField("age", "123");
//try ds.setSerializedField("foo_union", "123");
//try ds.setSerializedField("sub_struct.foo", "123");
//try ds.setSerializedField("sub_struct.bar", "123");
// Union embedding
{
const T = struct {
foo: union(enum) { bar: bool, baz: bool },
};
//std.debug.print("{any}\n", .{try ds.finish()});
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("bar", "true");
try std.testing.expectEqual(T{ .foo = .{ .bar = true } }, try ds.finish());
}
// Returns error if multiple union fields specified
{
const T = struct {
foo: union(enum) { bar: bool, baz: bool },
};
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("bar", "true");
try ds.setSerializedField("baz", "true");
try std.testing.expectError(error.DuplicateUnionMember, ds.finish());
}
// Uses default values if fields aren't provided
{
const T = struct { foo: usize = 123, bar: bool = true };
var ds = Deserializer(T, []const u8){};
try std.testing.expectEqual(T{ .foo = 123, .bar = true }, try ds.finish());
}
// Returns an error if fields aren't provided and no default exists
{
const T = struct { foo: usize, bar: bool };
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo", "123");
try std.testing.expectError(error.MissingField, ds.finish());
}
// Handles optional containers
{
const T = struct {
foo: ?struct { bar: usize = 3, baz: usize } = null,
qux: ?union(enum) { quux: usize } = null,
};
var ds = Deserializer(T, []const u8){};
try std.testing.expectEqual(T{ .foo = null, .qux = null }, try ds.finish());
}
{
const T = struct {
foo: ?struct { bar: usize = 3, baz: usize } = null,
qux: ?union(enum) { quux: usize } = null,
};
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo.baz", "3");
try ds.setSerializedField("quux", "3");
try std.testing.expectEqual(T{ .foo = .{ .bar = 3, .baz = 3 }, .qux = .{ .quux = 3 } }, try ds.finish());
}
{
const T = struct {
foo: ?struct { bar: usize = 3, baz: usize } = null,
qux: ?union(enum) { quux: usize } = null,
};
var ds = Deserializer(T, []const u8){};
try ds.setSerializedField("foo.bar", "3");
try ds.setSerializedField("quux", "3");
try std.testing.expectError(error.MissingField, ds.finish());
}
}