feat: extend protocol

This commit is contained in:
dualfroz committed 2026-09-08 15:50:33 +02:00
1 parent 06e9e3fe13
commit b94896cb62
1 file changed
+157
+157
View File
@@ -3295,3 +3295,160 @@ test "coll_op payload round trips a zero-arg action" {
try std.testing.expectEqual(@as(usize, 0), decoded.args.len); try std.testing.expectEqual(@as(usize, 0), decoded.args.len);
} }
test "decodeCollOp rejects an unknown action byte" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const w = encode.ByteWriter.init(&buf);
try w.byte(250);
try putLenPrefixed(w, "x");
try w.putU32(0);
try std.testing.expectError(error.Malformed, decodeCollOp(allocator, buf.items));
}
test "coll reply round trips nil and ok" {
const allocator = std.testing.allocator;
const nilPayload = try encodeCollReply(allocator, .nil);
defer allocator.free(nilPayload);
var nilReply = try decodeCollReply(allocator, nilPayload);
defer nilReply.deinit(allocator);
try std.testing.expect(nilReply == .nil);
const okPayload = try encodeCollReply(allocator, .ok);
defer allocator.free(okPayload);
var okReply = try decodeCollReply(allocator, okPayload);
defer okReply.deinit(allocator);
try std.testing.expect(okReply == .ok);
}
test "coll reply round trips int and real" {
const allocator = std.testing.allocator;
const intPayload = try encodeCollReply(allocator, .{ .int = -42 });
defer allocator.free(intPayload);
var intReply = try decodeCollReply(allocator, intPayload);
defer intReply.deinit(allocator);
try std.testing.expectEqual(@as(i64, -42), intReply.int);
const realPayload = try encodeCollReply(allocator, .{ .real = 3.5 });
defer allocator.free(realPayload);
var realReply = try decodeCollReply(allocator, realPayload);
defer realReply.deinit(allocator);
try std.testing.expectEqual(@as(f64, 3.5), realReply.real);
}
test "coll reply round trips raw bytes independently of the source payload" {
const allocator = std.testing.allocator;
const payload = try encodeCollReply(allocator, .{ .bytes = "hello" });
defer allocator.free(payload);
var reply = try decodeCollReply(allocator, payload);
defer reply.deinit(allocator);
try std.testing.expectEqualStrings("hello", reply.bytes);
}
test "coll reply round trips a string list, including empty" {
const allocator = std.testing.allocator;
const items = [_][]const u8{ "a", "bb", "ccc" };
const payload = try encodeCollReply(allocator, .{ .stringList = &items });
defer allocator.free(payload);
var reply = try decodeCollReply(allocator, payload);
defer reply.deinit(allocator);
try std.testing.expectEqual(@as(usize, 3), reply.stringList.len);
try std.testing.expectEqualStrings("bb", reply.stringList[1]);
const emptyPayload = try encodeCollReply(allocator, .{ .stringList = &.{} });
defer allocator.free(emptyPayload);
var emptyReply = try decodeCollReply(allocator, emptyPayload);
defer emptyReply.deinit(allocator);
try std.testing.expectEqual(@as(usize, 0), emptyReply.stringList.len);
}
test "coll reply round trips a pair list (hash getall shape)" {
const allocator = std.testing.allocator;
const pairs = [_]CollPair{
.{ .field = "name", .value = "ada" },
.{ .field = "age", .value = "36" },
};
const payload = try encodeCollReply(allocator, .{ .pairList = &pairs });
defer allocator.free(payload);
var reply = try decodeCollReply(allocator, payload);
defer reply.deinit(allocator);
try std.testing.expectEqual(@as(usize, 2), reply.pairList.len);
try std.testing.expectEqualStrings("name", reply.pairList[0].field);
try std.testing.expectEqualStrings("ada", reply.pairList[0].value);
try std.testing.expectEqualStrings("age", reply.pairList[1].field);
try std.testing.expectEqualStrings("36", reply.pairList[1].value);
}
test "coll reply round trips a score pair list (zset range shape), including negative scores" {
const allocator = std.testing.allocator;
const pairs = [_]CollScorePair{
.{ .member = "bob", .score = -1.5 },
.{ .member = "ada", .score = 10.25 },
};
const payload = try encodeCollReply(allocator, .{ .scorePairList = &pairs });
defer allocator.free(payload);
var reply = try decodeCollReply(allocator, payload);
defer reply.deinit(allocator);
try std.testing.expectEqual(@as(usize, 2), reply.scorePairList.len);
try std.testing.expectEqualStrings("bob", reply.scorePairList[0].member);
try std.testing.expectEqual(@as(f64, -1.5), reply.scorePairList[0].score);
try std.testing.expectEqualStrings("ada", reply.scorePairList[1].member);
try std.testing.expectEqual(@as(f64, 10.25), reply.scorePairList[1].score);
}
test "decodeCollReply rejects an unknown tag byte" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const w = encode.ByteWriter.init(&buf);
try w.byte(250);
try std.testing.expectError(error.Malformed, decodeCollReply(allocator, buf.items));
}
test "txn_op entries round trip put and del across two tables" {
const allocator = std.testing.allocator;
const putFields = [_]rowmod.Field{
.{ .name = "balance", .value = .{ .int = 100 } },
.{ .name = "city", .value = .{ .text = "warsaw" } },
};
const entries = [_]TxnOpEntry{
.{ .verb = .put, .table = "accounts", .pk = .{ .int = 1 }, .fields = &putFields },
.{ .verb = .del, .table = "sessions", .pk = .{ .text = "abc" } },
};
const payload = try encodeTxnOp(allocator, &entries);
defer allocator.free(payload);
const decoded = try decodeTxnOp(allocator, payload);
defer allocator.free(decoded);
try std.testing.expectEqual(@as(usize, 2), decoded.len);
try std.testing.expectEqual(TxnVerb.put, decoded[0].verb);
try std.testing.expectEqualStrings("accounts", decoded[0].table);
const pk0 = try rowmod.decodeValue(allocator, decoded[0].pkBytes);
try std.testing.expectEqual(@as(i64, 1), pk0.int);
var fields0 = try rowmod.Row.decode(allocator, decoded[0].fieldsBytes);
defer fields0.deinit();
try std.testing.expectEqual(@as(i64, 100), fields0.get("balance").?.int);
try std.testing.expectEqualStrings("warsaw", fields0.get("city").?.text);
try std.testing.expectEqual(TxnVerb.del, decoded[1].verb);
try std.testing.expectEqualStrings("sessions", decoded[1].table);
var pk1 = try rowmod.decodeValue(allocator, decoded[1].pkBytes);
defer pk1.free(allocator);
try std.testing.expectEqualStrings("abc", pk1.text);
var fields1 = try rowmod.Row.decode(allocator, decoded[1].fieldsBytes);
defer fields1.deinit();
try std.testing.expectEqual(@as(usize, 0), fields1.count());
}
test "empty txn_op entry list round trips" {
const allocator = std.testing.allocator;
const payload = try encodeTxnOp(allocator, &[_]TxnOpEntry{});
defer allocator.free(payload);
const decoded = try decodeTxnOp(allocator, payload);
defer allocator.free(decoded);
try std.testing.expectEqual(@as(usize, 0), decoded.len);
}