Skip to content

Commit 177b7f5

Browse files
committed
test: add extensive tests for msgpack edge cases and boundaries
- add tests for array32, bin16, bin32, str16, and str32 encoding/decoding - test int64/uint64 boundaries, NaN/infinity floats, and getUint error handling - cover fixint, fixstr, fixarray, and fixmap boundaries and edge cases - verify correct handling of array/map sizes, string/binary lengths, and error conditions
1 parent 2535db8 commit 177b7f5

File tree

1 file changed

+392
-0
lines changed

1 file changed

+392
-0
lines changed

src/test.zig

Lines changed: 392 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,3 +855,395 @@ test "large maps" {
855855
try expect(value19 != null);
856856
try expect(try value19.?.getInt() == 19);
857857
}
858+
859+
// Test array32 format
860+
test "array32 write and read" {
861+
// Create an array larger than 65535 elements would be too memory intensive
862+
// Instead test the boundary where array32 format kicks in
863+
var arr: [0xfffff]u8 = std.mem.zeroes([0xfffff]u8);
864+
var write_buffer = std.io.fixedBufferStream(&arr);
865+
var read_buffer = std.io.fixedBufferStream(&arr);
866+
var p = pack.init(&write_buffer, &read_buffer);
867+
868+
// Test with 65536 elements (0x10000), which should use array32
869+
const test_size = 0x10000;
870+
var test_payload = try Payload.arrPayload(test_size, allocator);
871+
defer test_payload.free(allocator);
872+
873+
for (0..test_size) |i| {
874+
try test_payload.setArrElement(i, Payload.uintToPayload(i % 256));
875+
}
876+
877+
try p.write(test_payload);
878+
const val = try p.read(allocator);
879+
defer val.free(allocator);
880+
881+
try expect((try val.getArrLen()) == test_size);
882+
// Check first and last elements
883+
try expect((try val.getArrElement(0)).uint == 0);
884+
try expect((try val.getArrElement(test_size - 1)).uint == (test_size - 1) % 256);
885+
}
886+
887+
// Test bin16 and bin32
888+
test "bin16 and bin32 write and read" {
889+
var arr: [0xfffff]u8 = std.mem.zeroes([0xfffff]u8);
890+
var write_buffer = std.io.fixedBufferStream(&arr);
891+
var read_buffer = std.io.fixedBufferStream(&arr);
892+
var p = pack.init(&write_buffer, &read_buffer);
893+
894+
// Test bin16 (256 bytes)
895+
const test_bin16 = try allocator.alloc(u8, 256);
896+
defer allocator.free(test_bin16);
897+
for (test_bin16, 0..) |*byte, i| {
898+
byte.* = @intCast(i % 256);
899+
}
900+
901+
try p.write(.{ .bin = msgpack.wrapBin(test_bin16) });
902+
{
903+
const val = try p.read(allocator);
904+
defer val.free(allocator);
905+
try expect(val.bin.value().len == 256);
906+
try expect(val.bin.value()[0] == 0);
907+
try expect(val.bin.value()[255] == 255);
908+
}
909+
910+
// Reset buffers for bin32 test
911+
arr = std.mem.zeroes([0xfffff]u8);
912+
write_buffer = std.io.fixedBufferStream(&arr);
913+
read_buffer = std.io.fixedBufferStream(&arr);
914+
p = pack.init(&write_buffer, &read_buffer);
915+
916+
// Test bin32 (65536 bytes)
917+
const test_bin32 = try allocator.alloc(u8, 65536);
918+
defer allocator.free(test_bin32);
919+
for (test_bin32, 0..) |*byte, i| {
920+
byte.* = @intCast(i % 256);
921+
}
922+
923+
try p.write(.{ .bin = msgpack.wrapBin(test_bin32) });
924+
{
925+
const val = try p.read(allocator);
926+
defer val.free(allocator);
927+
try expect(val.bin.value().len == 65536);
928+
try expect(val.bin.value()[0] == 0);
929+
try expect(val.bin.value()[65535] == 255);
930+
}
931+
}
932+
933+
// Test str16 and str32
934+
test "str16 and str32 write and read" {
935+
var arr: [0xfffff]u8 = std.mem.zeroes([0xfffff]u8);
936+
var write_buffer = std.io.fixedBufferStream(&arr);
937+
var read_buffer = std.io.fixedBufferStream(&arr);
938+
var p = pack.init(&write_buffer, &read_buffer);
939+
940+
// Test str16 (256 characters)
941+
const str16_data = "x" ** 256;
942+
const str16_payload = try Payload.strToPayload(str16_data, allocator);
943+
defer str16_payload.free(allocator);
944+
try p.write(str16_payload);
945+
{
946+
const val = try p.read(allocator);
947+
defer val.free(allocator);
948+
try expect(val.str.value().len == 256);
949+
try expect(u8eql(str16_data, val.str.value()));
950+
}
951+
952+
// Reset buffers for str32 test
953+
arr = std.mem.zeroes([0xfffff]u8);
954+
write_buffer = std.io.fixedBufferStream(&arr);
955+
read_buffer = std.io.fixedBufferStream(&arr);
956+
p = pack.init(&write_buffer, &read_buffer);
957+
958+
// Test str32 (65536 characters)
959+
const str32_data = try allocator.alloc(u8, 65536);
960+
defer allocator.free(str32_data);
961+
@memset(str32_data, 'A');
962+
963+
const str32_payload = try Payload.strToPayload(str32_data, allocator);
964+
defer str32_payload.free(allocator);
965+
try p.write(str32_payload);
966+
{
967+
const val = try p.read(allocator);
968+
defer val.free(allocator);
969+
try expect(val.str.value().len == 65536);
970+
try expect(u8eql(str32_data, val.str.value()));
971+
}
972+
}
973+
974+
// Test int64 and uint64 boundary values
975+
test "int64 uint64 boundary values" {
976+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
977+
var write_buffer = std.io.fixedBufferStream(&arr);
978+
var read_buffer = std.io.fixedBufferStream(&arr);
979+
var p = pack.init(&write_buffer, &read_buffer);
980+
981+
// Test max int64
982+
const max_i64: i64 = std.math.maxInt(i64);
983+
try p.write(.{ .int = max_i64 });
984+
{
985+
const val = try p.read(allocator);
986+
defer val.free(allocator);
987+
try expect(try val.getInt() == max_i64);
988+
}
989+
990+
// Reset buffers
991+
arr = std.mem.zeroes([0xffff_f]u8);
992+
write_buffer = std.io.fixedBufferStream(&arr);
993+
read_buffer = std.io.fixedBufferStream(&arr);
994+
p = pack.init(&write_buffer, &read_buffer);
995+
996+
// Test min int64
997+
const min_i64: i64 = std.math.minInt(i64);
998+
try p.write(.{ .int = min_i64 });
999+
{
1000+
const val = try p.read(allocator);
1001+
defer val.free(allocator);
1002+
try expect(val.int == min_i64);
1003+
}
1004+
1005+
// Reset buffers
1006+
arr = std.mem.zeroes([0xffff_f]u8);
1007+
write_buffer = std.io.fixedBufferStream(&arr);
1008+
read_buffer = std.io.fixedBufferStream(&arr);
1009+
p = pack.init(&write_buffer, &read_buffer);
1010+
1011+
// Test max uint64
1012+
const max_u64: u64 = std.math.maxInt(u64);
1013+
try p.write(.{ .uint = max_u64 });
1014+
{
1015+
const val = try p.read(allocator);
1016+
defer val.free(allocator);
1017+
try expect(val.uint == max_u64);
1018+
}
1019+
}
1020+
1021+
// Test getUint method
1022+
test "getUint method" {
1023+
// Test uint payload
1024+
const uint_payload = Payload.uintToPayload(42);
1025+
try expect(try uint_payload.getUint() == 42);
1026+
1027+
// Test positive int payload converted to uint
1028+
const pos_int_payload = Payload.intToPayload(24);
1029+
try expect(try pos_int_payload.getUint() == 24);
1030+
1031+
// Test negative int payload should fail
1032+
const neg_int_payload = Payload.intToPayload(-5);
1033+
const result = neg_int_payload.getUint();
1034+
try expect(result == msgpack.MsGPackError.INVALID_TYPE);
1035+
1036+
// Test non-numeric payload should fail
1037+
const nil_payload = Payload.nilToPayload();
1038+
const nil_result = nil_payload.getUint();
1039+
try expect(nil_result == msgpack.MsGPackError.INVALID_TYPE);
1040+
}
1041+
1042+
// Test NaN and Infinity float values
1043+
test "nan and infinity float values" {
1044+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
1045+
var write_buffer = std.io.fixedBufferStream(&arr);
1046+
var read_buffer = std.io.fixedBufferStream(&arr);
1047+
var p = pack.init(&write_buffer, &read_buffer);
1048+
1049+
// Test positive infinity
1050+
try p.write(.{ .float = std.math.inf(f64) });
1051+
{
1052+
const val = try p.read(allocator);
1053+
defer val.free(allocator);
1054+
try expect(std.math.isInf(val.float));
1055+
try expect(val.float > 0);
1056+
}
1057+
1058+
// Reset buffers
1059+
arr = std.mem.zeroes([0xffff_f]u8);
1060+
write_buffer = std.io.fixedBufferStream(&arr);
1061+
read_buffer = std.io.fixedBufferStream(&arr);
1062+
p = pack.init(&write_buffer, &read_buffer);
1063+
1064+
// Test negative infinity
1065+
try p.write(.{ .float = -std.math.inf(f64) });
1066+
{
1067+
const val = try p.read(allocator);
1068+
defer val.free(allocator);
1069+
try expect(std.math.isInf(val.float));
1070+
try expect(val.float < 0);
1071+
}
1072+
1073+
// Reset buffers
1074+
arr = std.mem.zeroes([0xffff_f]u8);
1075+
write_buffer = std.io.fixedBufferStream(&arr);
1076+
read_buffer = std.io.fixedBufferStream(&arr);
1077+
p = pack.init(&write_buffer, &read_buffer);
1078+
1079+
// Test NaN
1080+
try p.write(.{ .float = std.math.nan(f64) });
1081+
{
1082+
const val = try p.read(allocator);
1083+
defer val.free(allocator);
1084+
try expect(std.math.isNan(val.float));
1085+
}
1086+
}
1087+
1088+
// Test edge cases and error conditions
1089+
test "edge cases and error conditions" {
1090+
var arr: [100]u8 = std.mem.zeroes([100]u8);
1091+
var write_buffer = std.io.fixedBufferStream(&arr);
1092+
var read_buffer = std.io.fixedBufferStream(&arr);
1093+
var p = pack.init(&write_buffer, &read_buffer);
1094+
1095+
// Test array index out of bounds
1096+
var test_arr = try Payload.arrPayload(3, allocator);
1097+
defer test_arr.free(allocator);
1098+
1099+
// This should work
1100+
try test_arr.setArrElement(0, Payload.nilToPayload());
1101+
try test_arr.setArrElement(1, Payload.boolToPayload(true));
1102+
try test_arr.setArrElement(2, Payload.intToPayload(42));
1103+
1104+
try p.write(test_arr);
1105+
const val = try p.read(allocator);
1106+
defer val.free(allocator);
1107+
1108+
try expect((try val.getArrLen()) == 3);
1109+
try expect((try val.getArrElement(0)) == .nil);
1110+
try expect((try val.getArrElement(1)).bool == true);
1111+
try expect(try (try val.getArrElement(2)).getInt() == 42);
1112+
}
1113+
1114+
// Test positive fixint boundary (0-127)
1115+
test "positive fixint boundary" {
1116+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
1117+
var write_buffer = std.io.fixedBufferStream(&arr);
1118+
var read_buffer = std.io.fixedBufferStream(&arr);
1119+
var p = pack.init(&write_buffer, &read_buffer);
1120+
1121+
// Test boundary values for positive fixint (0-127)
1122+
const boundary_values = [_]u64{ 0, 1, 126, 127, 128 };
1123+
1124+
for (boundary_values) |val| {
1125+
try p.write(.{ .uint = val });
1126+
}
1127+
1128+
// Reset read buffer
1129+
read_buffer = std.io.fixedBufferStream(&arr);
1130+
p = pack.init(&write_buffer, &read_buffer);
1131+
1132+
for (boundary_values) |expected| {
1133+
const result = try p.read(allocator);
1134+
defer result.free(allocator);
1135+
try expect(result.uint == expected);
1136+
}
1137+
}
1138+
1139+
// Test fixstr boundary (0-31 bytes)
1140+
test "fixstr boundary" {
1141+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
1142+
var write_buffer = std.io.fixedBufferStream(&arr);
1143+
var read_buffer = std.io.fixedBufferStream(&arr);
1144+
var p = pack.init(&write_buffer, &read_buffer);
1145+
1146+
// Test different fixstr lengths
1147+
const test_strings = [_][]const u8{
1148+
"", // 0 bytes
1149+
"a", // 1 byte
1150+
"hello", // 5 bytes
1151+
"a" ** 31, // 31 bytes (max fixstr)
1152+
"b" ** 32, // 32 bytes (should use str8)
1153+
};
1154+
1155+
for (test_strings) |test_str| {
1156+
const str_payload = try Payload.strToPayload(test_str, allocator);
1157+
defer str_payload.free(allocator);
1158+
try p.write(str_payload);
1159+
}
1160+
1161+
// Reset read buffer
1162+
read_buffer = std.io.fixedBufferStream(&arr);
1163+
p = pack.init(&write_buffer, &read_buffer);
1164+
1165+
for (test_strings) |expected| {
1166+
const result = try p.read(allocator);
1167+
defer result.free(allocator);
1168+
try expect(u8eql(expected, result.str.value()));
1169+
}
1170+
}
1171+
1172+
// Test fixarray boundary (0-15 elements)
1173+
test "fixarray boundary" {
1174+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
1175+
var write_buffer = std.io.fixedBufferStream(&arr);
1176+
var read_buffer = std.io.fixedBufferStream(&arr);
1177+
var p = pack.init(&write_buffer, &read_buffer);
1178+
1179+
// Test different fixarray sizes
1180+
const test_sizes = [_]usize{ 0, 1, 5, 15, 16 };
1181+
1182+
for (test_sizes) |size| {
1183+
var test_payload = try Payload.arrPayload(size, allocator);
1184+
defer test_payload.free(allocator);
1185+
1186+
for (0..size) |i| {
1187+
try test_payload.setArrElement(i, Payload.uintToPayload(i));
1188+
}
1189+
1190+
try p.write(test_payload);
1191+
}
1192+
1193+
// Reset read buffer
1194+
read_buffer = std.io.fixedBufferStream(&arr);
1195+
p = pack.init(&write_buffer, &read_buffer);
1196+
1197+
for (test_sizes) |expected_size| {
1198+
const result = try p.read(allocator);
1199+
defer result.free(allocator);
1200+
try expect((try result.getArrLen()) == expected_size);
1201+
1202+
for (0..expected_size) |i| {
1203+
const element = try result.getArrElement(i);
1204+
try expect(element.uint == i);
1205+
}
1206+
}
1207+
}
1208+
1209+
// Test fixmap boundary (0-15 elements)
1210+
test "fixmap boundary" {
1211+
var arr: [0xffff_f]u8 = std.mem.zeroes([0xffff_f]u8);
1212+
var write_buffer = std.io.fixedBufferStream(&arr);
1213+
var read_buffer = std.io.fixedBufferStream(&arr);
1214+
var p = pack.init(&write_buffer, &read_buffer);
1215+
1216+
// Test different fixmap sizes
1217+
const test_sizes = [_]usize{ 0, 1, 5, 15, 16 };
1218+
1219+
for (test_sizes) |size| {
1220+
var test_map = Payload.mapPayload(allocator);
1221+
defer test_map.free(allocator);
1222+
1223+
for (0..size) |i| {
1224+
const key = try std.fmt.allocPrint(allocator, "k{d}", .{i});
1225+
defer allocator.free(key);
1226+
try test_map.mapPut(key, Payload.uintToPayload(i));
1227+
}
1228+
1229+
try p.write(test_map);
1230+
}
1231+
1232+
// Reset read buffer
1233+
read_buffer = std.io.fixedBufferStream(&arr);
1234+
p = pack.init(&write_buffer, &read_buffer);
1235+
1236+
for (test_sizes) |expected_size| {
1237+
const result = try p.read(allocator);
1238+
defer result.free(allocator);
1239+
try expect(result.map.count() == expected_size);
1240+
1241+
for (0..expected_size) |i| {
1242+
const key = try std.fmt.allocPrint(allocator, "k{d}", .{i});
1243+
defer allocator.free(key);
1244+
const value = try result.mapGet(key);
1245+
try expect(value != null);
1246+
try expect(value.?.uint == i);
1247+
}
1248+
}
1249+
}

0 commit comments

Comments
 (0)